From 9d99ebbb6e4dd2854c49fb50c206f58b64be3d5a Mon Sep 17 00:00:00 2001 From: HIMANSHU Date: Thu, 21 Mar 2024 13:07:49 +0530 Subject: [PATCH 01/39] Feat: Added Linters goconst, gofmt,godox,misspell,reassign,whitespacs and removed structcheck and varcheck as it is replaced by unused linter --- .golangci.yml | 30 ++++++++++---- cmd/seeder/exec/seed.go | 3 -- cmd/seeder/main.go | 1 - cmd/server/main_test.go | 6 --- daos/dao_utils_test.go | 3 -- daos/roles_test.go | 3 -- daos/users.go | 1 - daos/users_test.go | 39 ------------------ internal/config/config_test.go | 2 - internal/config/env.go | 2 - internal/config/env_test.go | 4 -- internal/jwt/jwt.go | 8 ---- internal/jwt/jwt_test.go | 6 --- internal/middleware/auth/auth.go | 11 ------ internal/middleware/auth/auth_test.go | 17 -------- internal/server/binding_test.go | 1 - internal/server/error_test.go | 13 +----- internal/server/server_test.go | 9 +---- pkg/api/api_test.go | 32 +++------------ pkg/utl/cnvrttogql/cnvrttogql_test.go | 1 - pkg/utl/randgen_test.go | 1 - pkg/utl/rediscache/redis_test.go | 2 - pkg/utl/rediscache/service_test.go | 21 ---------- pkg/utl/resultwrapper/error.go | 2 - pkg/utl/resultwrapper/error_test.go | 44 +++++++++------------ pkg/utl/throttle/throttler_test.go | 6 --- pkg/utl/zaplog/zaplog.go | 1 - pkg/utl/zaplog/zaplog_test.go | 5 --- resolver/auth_mutations.resolvers_test.go | 48 ----------------------- resolver/role_mutations.resolvers_test.go | 4 -- resolver/user_mutations.resolvers_test.go | 6 --- resolver/user_queries.resolvers_test.go | 9 ----- testutls/main.go | 2 - testutls/request.go | 1 - 34 files changed, 49 insertions(+), 295 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index 3201c27c..bb216a60 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -3,6 +3,14 @@ linters-settings: line-length: 128 tab-width: 2 autofix: true + cyclop: + max-complexity: 10 + skip-tests: true + funlen: + lines: 100 + statements: 50 + ignore-tests: true + ignore-blank-lines: true linters: enable: - lll @@ -11,12 +19,20 @@ linters: - govet - ineffassign - staticcheck - - structcheck - typecheck - unused - - varcheck - # - cyclop - # - funlen - # - gocritic - # - gocyclo - # - gofmt \ No newline at end of file + - cyclop + - funlen + - goconst + - gofmt + - godox + - misspell + - reassign + - whitespace + +issues: + exclude-rules: + - path: '(.+)_test\.go' + linters: + - funlen + - typecheck diff --git a/cmd/seeder/exec/seed.go b/cmd/seeder/exec/seed.go index 3e416e9f..cb98d300 100644 --- a/cmd/seeder/exec/seed.go +++ b/cmd/seeder/exec/seed.go @@ -12,7 +12,6 @@ import ( ) func main() { - base, _ := os.Getwd() log.Println(base) @@ -26,7 +25,6 @@ func main() { log.Println(len(files)) for _, file := range files { - log.Println(file.Name()) if slices.Contains([]string{"seed.go"}, file.Name()) && strings.Contains(file.Name(), "env") { continue @@ -41,6 +39,5 @@ func main() { log.Fatal(err) } fmt.Println("out:", outb.String(), "err:", errb.String()) - } } diff --git a/cmd/seeder/main.go b/cmd/seeder/main.go index 43c00e58..7cab9983 100644 --- a/cmd/seeder/main.go +++ b/cmd/seeder/main.go @@ -53,6 +53,5 @@ func main() { } fmt.Println(err) } - } } diff --git a/cmd/server/main_test.go b/cmd/server/main_test.go index e3519bef..0959d1f5 100644 --- a/cmd/server/main_test.go +++ b/cmd/server/main_test.go @@ -18,9 +18,7 @@ import ( const SuccessCase = "Success" func TestSetup(t *testing.T) { - initEnv := func() { - err := config.LoadEnvWithFilePrefix(convert.StringToPointerString("./../../")) if err != nil { log.Fatal(err) @@ -61,15 +59,11 @@ func TestSetup(t *testing.T) { apiStarted = true return nil, nil }) - defer apiPatches.Reset() defer loadPatches.Reset() - main.Setup() assert.Equal(t, apiStarted, true) } - }) } - } diff --git a/daos/dao_utils_test.go b/daos/dao_utils_test.go index d2fcf45a..3c105afd 100644 --- a/daos/dao_utils_test.go +++ b/daos/dao_utils_test.go @@ -9,7 +9,6 @@ import ( ) func TestGetContextExecutor(t *testing.T) { - cases := []struct { name string res *sql.Tx @@ -23,13 +22,11 @@ func TestGetContextExecutor(t *testing.T) { // Loop through the test cases for _, tt := range cases { - t.Run(tt.name, func(t *testing.T) { response := daos.GetContextExecutor(&sql.Tx{}) // Check if the response is equal to the expected value assert.Equal(t, response, tt.res) - }) } } diff --git a/daos/roles_test.go b/daos/roles_test.go index dfa1db8d..cfa15241 100644 --- a/daos/roles_test.go +++ b/daos/roles_test.go @@ -16,7 +16,6 @@ import ( ) func TestCreateRoleTx(t *testing.T) { - cases := []struct { name string req models.Role @@ -64,7 +63,6 @@ func TestCreateRoleTx(t *testing.T) { } func TestFindRoleByID(t *testing.T) { - cases := []struct { name string req int @@ -104,7 +102,6 @@ func TestFindRoleByID(t *testing.T) { t.Run(tt.name, func(t *testing.T) { _, err := daos.FindRoleByID(tt.req, context.Background()) assert.Equal(t, err, tt.err) - }) } } diff --git a/daos/users.go b/daos/users.go index 4f114c3e..868f863b 100644 --- a/daos/users.go +++ b/daos/users.go @@ -80,5 +80,4 @@ func FindAllUsersWithCount(queryMods []qm.QueryMod, ctx context.Context) (models queryMods = append(queryMods, qm.Offset(0)) count, err := models.Users(queryMods...).Count(ctx, contextExecutor) return users, count, err - } diff --git a/daos/users_test.go b/daos/users_test.go index e181cb60..aaf7a17d 100644 --- a/daos/users_test.go +++ b/daos/users_test.go @@ -24,7 +24,6 @@ import ( const ErrorFindingUser = "Fail on finding user" func TestCreateUserTx(t *testing.T) { - cases := []struct { name string req models.User @@ -97,7 +96,6 @@ func TestCreateUserTx(t *testing.T) { } func TestFindUserByID(t *testing.T) { - cases := []struct { name string req int @@ -109,13 +107,11 @@ func TestFindUserByID(t *testing.T) { err: nil, }, } - for _, tt := range cases { err := config.LoadEnv() if err != nil { fmt.Print("error loading .env file") } - db, mock, err := sqlmock.New() if err != nil { t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) @@ -127,23 +123,18 @@ func TestFindUserByID(t *testing.T) { boil.SetDB(oldDB) }() boil.SetDB(db) - rows := sqlmock.NewRows([]string{"id"}).AddRow(1) - mock.ExpectQuery(regexp.QuoteMeta(`select * from "users" where "id"=$1`)). WithArgs(). WillReturnRows(rows) - t.Run(tt.name, func(t *testing.T) { _, err := daos.FindUserByID(tt.req, context.Background()) assert.Equal(t, err, tt.err) - }) } } func TestFindUserByEmail(t *testing.T) { - type args struct { email string } @@ -163,13 +154,11 @@ func TestFindUserByEmail(t *testing.T) { err: nil, }, } - for _, tt := range cases { err := config.LoadEnv() if err != nil { fmt.Print("error loading .env file") } - db, mock, err := sqlmock.New() if err != nil { t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) @@ -181,7 +170,6 @@ func TestFindUserByEmail(t *testing.T) { boil.SetDB(oldDB) }() boil.SetDB(db) - if tt.name == ErrorFindingUser { mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (email=$1) LIMIT 1;`)). WithArgs(). @@ -191,7 +179,6 @@ func TestFindUserByEmail(t *testing.T) { mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (email=$1) LIMIT 1;`)). WithArgs(). WillReturnRows(rows) - t.Run(tt.name, func(t *testing.T) { _, err := daos.FindUserByEmail(tt.req.email, context.Background()) if err != nil { @@ -204,7 +191,6 @@ func TestFindUserByEmail(t *testing.T) { } func TestFindUserByUserName(t *testing.T) { - type args struct { Username string } @@ -224,13 +210,11 @@ func TestFindUserByUserName(t *testing.T) { err: nil, }, } - for _, tt := range cases { err := config.LoadEnv() if err != nil { fmt.Print("error loading .env file") } - db, mock, err := sqlmock.New() if err != nil { t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) @@ -242,7 +226,6 @@ func TestFindUserByUserName(t *testing.T) { boil.SetDB(oldDB) }() boil.SetDB(db) - if tt.name == "Fail on finding user username" { mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (username=$1) LIMIT 1;`)). WithArgs(). @@ -252,7 +235,6 @@ func TestFindUserByUserName(t *testing.T) { mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (username=$1) LIMIT 1;`)). WithArgs(). WillReturnRows(rows) - t.Run(tt.name, func(t *testing.T) { _, err := daos.FindUserByUserName(tt.req.Username, context.Background()) if err != nil { @@ -263,9 +245,7 @@ func TestFindUserByUserName(t *testing.T) { }) } } - func TestUpdateUserTx(t *testing.T) { - cases := []struct { name string req models.User @@ -295,7 +275,6 @@ func TestUpdateUserTx(t *testing.T) { boil.SetDB(oldDB) }() boil.SetDB(db) - result := driver.Result(driver.RowsAffected(1)) // get access_token mock.ExpectExec(regexp.QuoteMeta(`UPDATE "users" `)). @@ -307,9 +286,7 @@ func TestUpdateUserTx(t *testing.T) { }) } } - func TestDeleteUser(t *testing.T) { - cases := []struct { name string req models.User @@ -321,13 +298,11 @@ func TestDeleteUser(t *testing.T) { err: nil, }, } - for _, tt := range cases { err := config.LoadEnv() if err != nil { fmt.Print("error loading .env file") } - db, mock, err := sqlmock.New() if err != nil { t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) @@ -339,21 +314,17 @@ func TestDeleteUser(t *testing.T) { boil.SetDB(oldDB) }() boil.SetDB(db) - // delete user result := driver.Result(driver.RowsAffected(1)) mock.ExpectExec(regexp.QuoteMeta(`DELETE FROM "users" WHERE "id"=$1`)). WillReturnResult(result) - t.Run(tt.name, func(t *testing.T) { _, err := daos.DeleteUser(tt.req, context.Background()) assert.Equal(t, err, tt.err) }) } } - func TestFindAllUsersWithCount(t *testing.T) { - oldDB := boil.GetDB() err := config.LoadEnvWithFilePrefix(convert.StringToPointerString("./../")) if err != nil { @@ -388,21 +359,17 @@ func TestFindAllUsersWithCount(t *testing.T) { }, }, } - for _, tt := range cases { - if tt.err != nil { mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users";`)). WithArgs(). WillReturnError(fmt.Errorf("this is some error")) } - for _, dbQuery := range tt.dbQueries { mock.ExpectQuery(regexp.QuoteMeta(dbQuery.Query)). WithArgs(). WillReturnRows(dbQuery.DbResponse) } - t.Run(tt.name, func(t *testing.T) { res, c, err := daos.FindAllUsersWithCount([]qm.QueryMod{}, context.Background()) if err != nil { @@ -413,7 +380,6 @@ func TestFindAllUsersWithCount(t *testing.T) { assert.Equal(t, res[0].Email, null.StringFrom(testutls.MockEmail)) assert.Equal(t, res[0].Token, null.StringFrom(testutls.MockToken)) assert.Equal(t, res[0].ID, int(testutls.MockID)) - } }) } @@ -421,7 +387,6 @@ func TestFindAllUsersWithCount(t *testing.T) { db.Close() } func TestFindUserByToken(t *testing.T) { - type args struct { Token string } @@ -441,13 +406,11 @@ func TestFindUserByToken(t *testing.T) { err: nil, }, } - for _, tt := range cases { err := config.LoadEnv() if err != nil { fmt.Print("error loading .env file") } - db, mock, err := sqlmock.New() if err != nil { t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) @@ -459,7 +422,6 @@ func TestFindUserByToken(t *testing.T) { boil.SetDB(oldDB) }() boil.SetDB(db) - if tt.name == "Fail on finding user token" { mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (token=$1) LIMIT 1;`)). WithArgs(). @@ -469,7 +431,6 @@ func TestFindUserByToken(t *testing.T) { mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (token=$1) LIMIT 1;`)). WithArgs(). WillReturnRows(rows) - t.Run(tt.name, func(t *testing.T) { _, err := daos.FindUserByToken(tt.req.Token, context.Background()) if err != nil { diff --git a/internal/config/config_test.go b/internal/config/config_test.go index e7956b1b..4603c39f 100644 --- a/internal/config/config_test.go +++ b/internal/config/config_test.go @@ -61,7 +61,6 @@ func TestLoad(t *testing.T) { } for _, tt := range cases { t.Run(tt.name, func(t *testing.T) { - err := config.LoadEnvWithFilePrefix((convert.StringToPointerString("./../../"))) if err != nil { fmt.Print("error loading .env file") @@ -89,7 +88,6 @@ func TestLoad(t *testing.T) { isError := err != nil assert.Equal(t, tt.wantErr, isError) if isError { - assert.Equal(t, err.Error(), tt.error) } }) diff --git a/internal/config/env.go b/internal/config/env.go index 142b1633..5f5d2521 100644 --- a/internal/config/env.go +++ b/internal/config/env.go @@ -103,9 +103,7 @@ func LoadEnvWithFilePrefix(fileprefix *string) error { os.Setenv("PSQL_PASS", secrets.Password) os.Setenv("PSQL_PORT", strconv.Itoa(secrets.Port)) os.Setenv("PSQL_USER", secrets.Username) - } - return nil } func LoadEnv() error { diff --git a/internal/config/env_test.go b/internal/config/env_test.go index 2bc7f75c..01a5d639 100644 --- a/internal/config/env_test.go +++ b/internal/config/env_test.go @@ -118,7 +118,6 @@ func TestGetBool(t *testing.T) { }, } for _, tt := range tests { - if tt.success { os.Setenv(tt.args.key, fmt.Sprintf("%v", tt.want)) } @@ -227,12 +226,10 @@ func TestLoadEnv(t *testing.T) { }, } for _, tt := range tests { - ApplyFunc(godotenv.Load, func(filenames ...string) (err error) { // togglel whenever this file is loaded tt.args.tapped = true if tt.args.err == "" { - if tt.name == "Env varInjection Error" && len(filenames) > 0 && filenames[0] == ".env.local" { return fmt.Errorf(tt.args.err) } @@ -240,7 +237,6 @@ func TestLoadEnv(t *testing.T) { return nil } return fmt.Errorf(tt.args.err) - }) os.Setenv("ENVIRONMENT_NAME", tt.args.env) if tt.args.dbSecret != "" { diff --git a/internal/jwt/jwt.go b/internal/jwt/jwt.go index 83d03afd..f0c46f63 100644 --- a/internal/jwt/jwt.go +++ b/internal/jwt/jwt.go @@ -15,9 +15,7 @@ import ( // New generates new JWT service necessary for auth middleware func New(algo, secret string, ttlMinutes, minSecretLength int) (Service, error) { - var minSecretLen = 128 - if minSecretLength > 0 { minSecretLen = minSecretLength } @@ -28,7 +26,6 @@ func New(algo, secret string, ttlMinutes, minSecretLength int) (Service, error) if signingMethod == nil { return Service{}, fmt.Errorf("invalid jwt signing method: %s", algo) } - return Service{ key: []byte(secret), algo: signingMethod, @@ -40,10 +37,8 @@ func New(algo, secret string, ttlMinutes, minSecretLength int) (Service, error) type Service struct { // Secret key used for signing. key []byte - // Duration for which the jwt token is valid. ttl time.Duration - // JWT signing algorithm algo jwt.SigningMethod } @@ -54,20 +49,17 @@ func (s Service) ParseToken(authHeader string) (*jwt.Token, error) { if !(len(parts) == 2 && strings.ToLower(parts[0]) == "bearer") { return nil, resultwrapper.ErrGeneric } - return jwt.Parse(parts[1], func(token *jwt.Token) (interface{}, error) { if s.algo != token.Method { return nil, resultwrapper.ErrGeneric } return s.key, nil }) - } // GenerateToken generates new JWT token and populates it with user data func (s Service) GenerateToken(u *models.User) (string, error) { role, err := u.Role().One(context.Background(), boil.GetContextDB()) - if err != nil { return "", err } diff --git a/internal/jwt/jwt_test.go b/internal/jwt/jwt_test.go index 30f35ec8..0f842e64 100644 --- a/internal/jwt/jwt_test.go +++ b/internal/jwt/jwt_test.go @@ -127,7 +127,6 @@ func TestGenerateToken(t *testing.T) { RoleErr: true, }, } - err := config.LoadEnvWithFilePrefix(convert.StringToPointerString("./../../")) if err != nil { log.Fatal(err) @@ -137,9 +136,7 @@ func TestGenerateToken(t *testing.T) { panic("failed to setup env and db") } rows := sqlmock.NewRows([]string{"id", "name"}).AddRow(1, "johndoe") - for name, tt := range cases { - t.Run(name, func(t *testing.T) { if tt.RoleErr == true { mock.ExpectQuery(regexp.QuoteMeta(`SELECT "roles".* FROM "roles" WHERE ("id" = $1) LIMIT 1`)). @@ -150,7 +147,6 @@ func TestGenerateToken(t *testing.T) { WithArgs([]driver.Value{1}...). WillReturnRows(rows) } - jwtSvc, err := jwt.New(tt.algo, tt.secret, 60, tt.minSecretLen) assert.Equal(t, tt.wantErr, err != nil) if err == nil && !tt.wantErr { @@ -160,7 +156,6 @@ func TestGenerateToken(t *testing.T) { }) } } - func TestParseToken(t *testing.T) { algo := "HS256" cases := map[string]struct { @@ -205,5 +200,4 @@ func TestParseToken(t *testing.T) { } }) } - } diff --git a/internal/middleware/auth/auth.go b/internal/middleware/auth/auth.go index a84cc9e6..73ce609e 100644 --- a/internal/middleware/auth/auth.go +++ b/internal/middleware/auth/auth.go @@ -88,11 +88,9 @@ func contains(s []string, e string) bool { } return false } - func getAccessNeeds(operation *ast.OperationDefinition) (needsAuthAccess bool, needsSuperAdminAccess bool) { operationName := string(operation.Operation) for _, selectionSet := range operation.SelectionSet { - selection := reflect.ValueOf(selectionSet).Elem() if !contains(WhiteListedOperations[operationName], selection.FieldByName("Name").Interface().(string)) { needsAuthAccess = true @@ -109,40 +107,31 @@ func GraphQLMiddleware( ctx context.Context, tokenParser TokenParser, next graphql2.OperationHandler) graphql2.ResponseHandler { - operation := graphql2.GetOperationContext(ctx).Operation needsAuthAccess, needsSuperAdminAccess := getAccessNeeds(operation) if !needsAuthAccess && !needsSuperAdminAccess { return next(ctx) } - // strip token var tokenStr = ctx.Value(authorization).(string) if len(tokenStr) == 0 { return resultwrapper.HandleGraphQLError("Authorization header is missing") } - token, err := tokenParser.ParseToken(tokenStr) - if err != nil || !token.Valid { return resultwrapper.HandleGraphQLError("Invalid authorization token") } claims := token.Claims.(jwt.MapClaims) - if needsSuperAdminAccess && claims["role"].(string) != "SUPER_ADMIN" { return resultwrapper.HandleGraphQLError( "Unauthorized! \n Only admins are authorized to make this request.", ) } - email := claims["e"].(string) user, err := daos.FindUserByEmail(email, ctx) - if err != nil { return resultwrapper.HandleGraphQLError("No user found for this email address") } - ctx = context.WithValue(ctx, UserCtxKey, user) return next(ctx) - } diff --git a/internal/middleware/auth/auth_test.go b/internal/middleware/auth/auth_test.go index b894f43e..8928b8a5 100644 --- a/internal/middleware/auth/auth_test.go +++ b/internal/middleware/auth/auth_test.go @@ -166,23 +166,19 @@ func TestGraphQLMiddleware(t *testing.T) { dbQueries: []testutls.QueryData{}, }, } - oldDB := boil.GetDB() err := config.LoadEnvWithFilePrefix(convert.StringToPointerString("./../../../")) if err != nil { log.Fatal(err) } mock, db, _ := testutls.SetupMockDB(t) - for name, tt := range cases { t.Run(name, func(t *testing.T) { - for _, dbQuery := range tt.dbQueries { mock.ExpectQuery(regexp.QuoteMeta(dbQuery.Query)). WithArgs(*dbQuery.Actions...). WillReturnRows(dbQuery.DbResponse) } - requestQuery := testutls.MockQuery if tt.whiteListedQuery { requestQuery = testutls.MockWhitelistedQuery @@ -193,7 +189,6 @@ func TestGraphQLMiddleware(t *testing.T) { boil.SetDB(oldDB) db.Close() } - func makeRequest(t *testing.T, requestQuery string, tt struct { wantStatus int header string @@ -206,26 +201,21 @@ func makeRequest(t *testing.T, requestQuery string, tt struct { }) { // mock token parser to handle the different cases for when the token us valid, invalid, empty parseTokenMock = tt.tokenParser - // mock operation handler, and assert different conditions operationHandlerMock = tt.operationHandler - tokenParser := tokenParserMock{} client := &http.Client{} observers := map[string]chan *graphql.User{} graphqlHandler := handler.New(graphql.NewExecutableSchema(graphql.Config{ Resolvers: &resolver.Resolver{Observers: observers}, })) - graphqlHandler. AroundOperations(func(ctx context.Context, next graphql2.OperationHandler) graphql2.ResponseHandler { res := auth.GraphQLMiddleware(ctx, tokenParser, operationHandlerMock) return res }) - graphqlHandler.AddTransport(transport.POST{}) pathName := "/graphql" - e := echo.New() e.POST(pathName, func(c echo.Context) error { req := c.Request() @@ -233,7 +223,6 @@ func makeRequest(t *testing.T, requestQuery string, tt struct { graphqlHandler.ServeHTTP(res, req) return nil }, auth.GqlMiddleware()) - ts := httptest.NewServer(e) path := ts.URL + pathName defer ts.Close() @@ -243,7 +232,6 @@ func makeRequest(t *testing.T, requestQuery string, tt struct { path, bytes.NewBuffer([]byte(requestQuery)), ) - if tt.wantStatus != 401 { req.Header.Set("authorization", tt.header) } @@ -252,7 +240,6 @@ func makeRequest(t *testing.T, requestQuery string, tt struct { if err != nil { t.Fatal("Cannot create http request") } - bodyBytes, err := io.ReadAll(res.Body) if err != nil { log.Fatal(err) @@ -268,7 +255,6 @@ func makeRequest(t *testing.T, requestQuery string, tt struct { } assert.Equal(t, tt.wantStatus, res.StatusCode) } - func TestUserIDFromContext(t *testing.T) { cases := map[string]struct { user *models.User @@ -285,14 +271,11 @@ func TestUserIDFromContext(t *testing.T) { } for name, tt := range cases { t.Run(name, func(t *testing.T) { - userID := auth.UserIDFromContext(context.WithValue(testutls.MockCtx{}, auth.UserCtxKey, tt.user)) assert.Equal(t, tt.userID, userID) }) } - } - func TestFromContext(t *testing.T) { user := &models.User{ID: testutls.MockID} u := auth.FromContext(context.WithValue(testutls.MockCtx{}, auth.UserCtxKey, user)) diff --git a/internal/server/binding_test.go b/internal/server/binding_test.go index 6750ddc2..077feed8 100644 --- a/internal/server/binding_test.go +++ b/internal/server/binding_test.go @@ -57,5 +57,4 @@ func TestBind(t *testing.T) { assert.Equal(t, tt.wantErr, err != nil) }) } - } diff --git a/internal/server/error_test.go b/internal/server/error_test.go index 84ad10d8..d95eb384 100644 --- a/internal/server/error_test.go +++ b/internal/server/error_test.go @@ -68,21 +68,16 @@ func Test_getVldErrorMsg(t *testing.T) { } func getValidatorErr(t *testing.T) error { - fieldError := testutls.NewMockFieldError(gomock.NewController(t)) - fieldError.EXPECT().Field().DoAndReturn(func() string { return "FIELD" }).AnyTimes() - fieldError.EXPECT().ActualTag().DoAndReturn(func() string { return "ACTUALTAG" }).AnyTimes() - return validator.ValidationErrors{fieldError} } -func Test_customErrHandler_handler(t *testing.T) { - +func TestCustomErrHandlerHandler(t *testing.T) { type args struct { err error expectedStatusCode int @@ -130,16 +125,13 @@ func Test_customErrHandler_handler(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - // just make a request req, _ := http.NewRequest( tt.args.httpMethod, "/", bytes.NewBuffer([]byte("")), ) - ctx := testutls.NewMockContext(gomock.NewController(t)) - // mock ctx.Response ctx. EXPECT(). @@ -148,7 +140,6 @@ func Test_customErrHandler_handler(t *testing.T) { return &echo.Response{Status: tt.args.expectedStatusCode} }). AnyTimes() - // mock ctx.Request ctx. EXPECT(). @@ -157,7 +148,6 @@ func Test_customErrHandler_handler(t *testing.T) { return req }). AnyTimes() - if tt.args.httpMethod == "HEAD" { // mock ctx.NoContent ctx. @@ -177,7 +167,6 @@ func Test_customErrHandler_handler(t *testing.T) { }). AnyTimes() } - // call the handler with tt.args.err. We are asserting in the JSON/NoContent call custErr.handler(tt.args.err, ctx) }) diff --git a/internal/server/server_test.go b/internal/server/server_test.go index a00c8ce8..d4ad4db7 100644 --- a/internal/server/server_test.go +++ b/internal/server/server_test.go @@ -48,7 +48,7 @@ type args struct { shutDownFailed bool } -func initValues(shutDownFailed bool, startServer func(e *echo.Echo, s *http.Server) error) args { +func initValues(startServer func(e *echo.Echo, s *http.Server) error) args { config := testutls.MockConfig() return args{ e: server.New(), @@ -63,7 +63,6 @@ func initValues(shutDownFailed bool, startServer func(e *echo.Echo, s *http.Serv } } func TestStart(t *testing.T) { - cases := map[string]struct { args args }{ @@ -90,19 +89,16 @@ func TestStart(t *testing.T) { tt.args.startServerCalled = true return err }) - if tt.args.shutDownFailed { ApplyMethod(reflect.TypeOf(tt.args.e), "Shutdown", func(e *echo.Echo, ctx context.Context) (err error) { return fmt.Errorf("error shutting down") }) - ApplyMethod( reflect.TypeOf(tt.args.e.StdLogger), "Fatal", func(l *log.Logger, i ...interface{}) { tt.args.serverShutDownCalled = true }) } - go func() { time.Sleep(200 * time.Millisecond) proc, err := os.FindProcess(os.Getpid()) @@ -120,16 +116,13 @@ func TestStart(t *testing.T) { log.Fatal("errror") } time.Sleep(1 * time.Second) - }() server.Start(tt.args.e, tt.args.cfg) time.Sleep(400 * time.Millisecond) assert.Equal(t, tt.args.startServerCalled, true) - if tt.args.shutDownFailed { assert.Equal(t, tt.args.serverShutDownCalled, true) } - }) } } diff --git a/pkg/api/api_test.go b/pkg/api/api_test.go index 69486b40..ccea762e 100644 --- a/pkg/api/api_test.go +++ b/pkg/api/api_test.go @@ -39,11 +39,10 @@ func TestStart(t *testing.T) { cfg *config.Configuration } tests := []struct { - name string - args args - wantErr bool - setDbCalled bool - + name string + args args + wantErr bool + setDbCalled bool getTransportCalled bool postTransportCalled bool optionsTransportCalled bool @@ -62,8 +61,7 @@ func TestStart(t *testing.T) { args: args{ cfg: testutls.MockConfig(), }, - wantErr: false, - + wantErr: false, getTransportCalled: false, postTransportCalled: false, optionsTransportCalled: false, @@ -71,7 +69,6 @@ func TestStart(t *testing.T) { websocketTransportCalled: false, }, } - patches := ApplyFunc(os.Getenv, func(key string) (value string) { if key == "JWT_SECRET" { return testutls.MockJWTSecret @@ -87,28 +84,22 @@ func TestStart(t *testing.T) { fmt.Print("Fake server started\n") }) e := echo.New() - ApplyFunc(server.New, func() *echo.Echo { return e }) - observers := map[string]chan *graphql.User{} graphqlHandler := handler.New(graphql.NewExecutableSchema(graphql.Config{ Resolvers: &resolver.Resolver{Observers: observers}, })) - for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { ApplyFunc(boil.SetDB, func(db boil.Executor) { fmt.Print("boil.SetDB called\n") tt.setDbCalled = true }) - if tt.getTransportCalled || tt.postTransportCalled || tt.optionsTransportCalled || tt.multipartFormTransportCalled { - ApplyMethod(reflect.TypeOf(graphqlHandler), "AddTransport", func(s *handler.Server, t graphql2.Transport) { - transportGET := transport.GET{} transportMultipartForm := transport.MultipartForm{} transportPOST := transport.POST{} @@ -123,7 +114,6 @@ func TestStart(t *testing.T) { }, }, } - if t == transportGET { tt.getTransportCalled = true } @@ -133,22 +123,18 @@ func TestStart(t *testing.T) { if t == transportPOST { tt.postTransportCalled = true } - if reflect.TypeOf(t) == reflect.TypeOf(transportWebsocket) { tt.websocketTransportCalled = true } - }) _, err := Start(tt.args.cfg) if err != nil != tt.wantErr { t.Errorf("Start() error = %v, wantErr %v", err, tt.wantErr) } - assert.Equal(t, tt.getTransportCalled, true) assert.Equal(t, tt.multipartFormTransportCalled, true) assert.Equal(t, tt.postTransportCalled, true) assert.Equal(t, tt.websocketTransportCalled, true) - } else { _, err := Start(tt.args.cfg) if err != nil != tt.wantErr { @@ -161,16 +147,12 @@ func TestStart(t *testing.T) { RequestBody: testutls.MockWhitelistedQuery, IsGraphQL: false, }) - if err != nil { log.Fatal(err) } - assert.Equal(t, tt.setDbCalled, true) - // check if it returns schema correctly assert.NotNil(t, jsonRes["data"].(map[string]interface{})["__schema"]) - _, res, err := testutls.SimpleMakeRequest(testutls.RequestParameters{ E: e, Pathname: "/playground", @@ -182,12 +164,10 @@ func TestStart(t *testing.T) { log.Fatal(err) } bodyBytes, _ := io.ReadAll(res.Body) - // check if the playground is returned assert.Contains(t, string(bodyBytes), "GraphiQL.createFetcher") ts := httptest.NewServer(e) u := "ws" + strings.TrimPrefix(ts.URL+graphQLPathname, "http") - // Connect to the server fmt.Print(u) ws, _, err := websocket.DefaultDialer.Dial(u, nil) @@ -195,7 +175,6 @@ func TestStart(t *testing.T) { t.Fatalf("%v", err) } defer ws.Close() - if err := ws.WriteMessage(websocket.TextMessage, []byte(`{"type":"connection_init","payload":`+ `{"authorization":"bearer ABC"}}`)); err != nil { t.Fatalf("%v", err) @@ -207,7 +186,6 @@ func TestStart(t *testing.T) { // check if the playground is returned assert.Contains(t, string(p), "{\"type\":\"connection_ack\"}\n") } - }) } } diff --git a/pkg/utl/cnvrttogql/cnvrttogql_test.go b/pkg/utl/cnvrttogql/cnvrttogql_test.go index 6d95445f..48d75bd6 100644 --- a/pkg/utl/cnvrttogql/cnvrttogql_test.go +++ b/pkg/utl/cnvrttogql/cnvrttogql_test.go @@ -108,7 +108,6 @@ func TestUserToGraphQlUser(t *testing.T) { t.Run(tt.name, func(t *testing.T) { got := UserToGraphQlUser(tt.req, 0) assert.Equal(t, got, tt.want) - }) } } diff --git a/pkg/utl/randgen_test.go b/pkg/utl/randgen_test.go index 3ff596ac..fb76a6bc 100644 --- a/pkg/utl/randgen_test.go +++ b/pkg/utl/randgen_test.go @@ -28,7 +28,6 @@ func TestRandomSequence(t *testing.T) { return 0 } if got := RandomSequence(tt.args.n); got != tt.want { - t.Errorf("RandomSequence() = %v, want %v", got, tt.want) } }) diff --git a/pkg/utl/rediscache/redis_test.go b/pkg/utl/rediscache/redis_test.go index 1d6f1dce..76141a26 100644 --- a/pkg/utl/rediscache/redis_test.go +++ b/pkg/utl/rediscache/redis_test.go @@ -20,7 +20,6 @@ const ( ) func Test_redisDial(t *testing.T) { - tests := []struct { name string want redigo.Conn @@ -99,7 +98,6 @@ func TestSetKeyValue(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - var patches *Patches b, _ := json.Marshal(tt.args.data) if tt.name == FailedCase { diff --git a/pkg/utl/rediscache/service_test.go b/pkg/utl/rediscache/service_test.go index 33db0f03..cb242272 100644 --- a/pkg/utl/rediscache/service_test.go +++ b/pkg/utl/rediscache/service_test.go @@ -227,9 +227,7 @@ func TestGetUser(t *testing.T) { ApplyFunc(redisDial, func() (redis.Conn, error) { return conn, nil }) - t.Run(tt.name, func(t *testing.T) { - if tt.name == ErrorUnmarshal { patchJson := ApplyFunc(json.Marshal, func(v any) ([]byte, error) { return []byte{}, fmt.Errorf("json error") @@ -238,7 +236,6 @@ func TestGetUser(t *testing.T) { } if tt.args.cacheMiss { conn.Command("GET", fmt.Sprintf("user%d", tt.args.userID)).Expect(nil) - b, _ := json.Marshal(tt.want) conn.Command("SET", fmt.Sprintf("user%d", tt.args.userID), string(b)).Expect(nil) for _, dbQuery := range tt.args.dbQueries { @@ -248,16 +245,13 @@ func TestGetUser(t *testing.T) { } } else if tt.name == ErrorGetKeyValue { conn.Command("GET", fmt.Sprintf("role%d", tt.args.userID)).ExpectError(fmt.Errorf(ErrMsgGetKeyValue)) - } else if tt.name == ErrorSetKeyValue { conn.Command("GET", fmt.Sprintf("role%d", tt.args.userID)).Expect(nil) } else { b, _ := json.Marshal(tt.want) conn.Command("GET", fmt.Sprintf("user%d", tt.args.userID)).Expect(b) } - got, err := GetUser(tt.args.userID, context.Background()) - if (err != nil) != tt.wantErr { t.Errorf("GetUser() error = %v, wantErr %v", err, tt.wantErr) return @@ -382,32 +376,25 @@ func TestGetRole(t *testing.T) { want: role, }, } - oldDB := boil.GetDB() err := config.LoadEnvWithFilePrefix(convert.StringToPointerString("./../../../")) if err != nil { log.Fatal(err) } mock, db, _ := testutls.SetupMockDB(t) - for _, tt := range tests { - ApplyFunc(redisDial, func() (redis.Conn, error) { return conn, nil }) - t.Run(tt.name, func(t *testing.T) { - if tt.name == ErrorUnmarshal { patchJson := ApplyFunc(json.Unmarshal, func(data []byte, v any) error { return fmt.Errorf(ErrMsgUnmarshal) }) defer patchJson.Reset() } - if tt.args.cacheMiss { conn.Command("GET", fmt.Sprintf("role%d", tt.args.roleID)).Expect(nil) - b, _ := json.Marshal(tt.want) conn.Command("SET", fmt.Sprintf("role%d", tt.args.roleID), string(b)).Expect(nil) for _, dbQuery := range tt.args.dbQueries { @@ -415,7 +402,6 @@ func TestGetRole(t *testing.T) { WithArgs(*dbQuery.Actions...). WillReturnRows(dbQuery.DbResponse) } - } else if tt.name == ErrorGetKeyValue { conn.Command("GET", fmt.Sprintf("role%d", tt.args.roleID)).ExpectError(fmt.Errorf(ErrMsgGetKeyValue)) } else if tt.name == ErrorSetKeyValue { @@ -424,7 +410,6 @@ func TestGetRole(t *testing.T) { b, _ := json.Marshal(tt.want) conn.Command("GET", fmt.Sprintf("role%d", tt.args.roleID)).Expect(b) } - got, err := GetRole(tt.args.roleID, context.Background()) if (err != nil) != tt.wantErr { t.Errorf("GetRole() error = %v, wantErr %v", err, tt.wantErr) @@ -470,16 +455,13 @@ func TestIncVisits(t *testing.T) { return conn, nil }) for _, tt := range tests { - if tt.name == ErrorRedisDial { patch := gomonkey.ApplyFunc(redisDial, func() (redigo.Conn, error) { return nil, fmt.Errorf(ErrMsgFromRedisDial) }) defer patch.Reset() } - t.Run(tt.name, func(t *testing.T) { - conn.Command("INCR", tt.args.path).Expect([]byte(fmt.Sprint(tt.want))) got, err := IncVisits(tt.args.path) if (err != nil) != tt.wantErr { @@ -531,14 +513,12 @@ func TestStartVisits(t *testing.T) { ApplyFunc(redisDial, func() (redis.Conn, error) { return conn, nil }) - err := config.LoadEnvWithFilePrefix(convert.StringToPointerString("./../")) if err != nil { t.Log(err) } for _, tt := range tests { - if tt.name == ErrorRedisDial { patch := gomonkey.ApplyFunc(redisDial, func() (redigo.Conn, error) { return nil, fmt.Errorf(ErrMsgFromRedisDial) @@ -561,7 +541,6 @@ func TestStartVisits(t *testing.T) { t.Errorf("StartVisits() error = %v, wantErr %v", err, tt.wantErr) return } - }) } } diff --git a/pkg/utl/resultwrapper/error.go b/pkg/utl/resultwrapper/error.go index b920ec80..75af043f 100644 --- a/pkg/utl/resultwrapper/error.go +++ b/pkg/utl/resultwrapper/error.go @@ -171,7 +171,6 @@ func ResolverSQLError(err error, detail string) error { } if strings.Contains(fmt.Sprint(err), "delete on table") && strings.Contains(fmt.Sprint(err), "violates foreign key constraint") { - return ResolverWrapperFromMessage(http.StatusInternalServerError, "Unable to complete the delete operation, it has useful data associated to it") } @@ -180,7 +179,6 @@ func ResolverSQLError(err error, detail string) error { // ResolverWrapperFromMessage ... func ResolverWrapperFromMessage(errorCode int, err string) error { - w := httptest.NewRecorder() req, _ := http.NewRequest("GET", "", nil) req.Header.Set("Content-Type", "application/json") diff --git a/pkg/utl/resultwrapper/error_test.go b/pkg/utl/resultwrapper/error_test.go index 6f66a0ad..54e45606 100644 --- a/pkg/utl/resultwrapper/error_test.go +++ b/pkg/utl/resultwrapper/error_test.go @@ -18,10 +18,11 @@ const ( SuccessCase = "Success" ErrorCase = "error from json" ErrMsgJSON = "Error from JSON" + ErrMsg = "This is an Error" + DetailMsg = "Some level of detail" ) func TestSplitByLabel(t *testing.T) { - cases := []struct { name string req string @@ -55,7 +56,6 @@ func TestSplitByLabel(t *testing.T) { } func TestErrorFormatter(t *testing.T) { - cases := []struct { name string req string @@ -128,12 +128,9 @@ func TestResultWrapper(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - w := httptest.NewRecorder() ctx := e.NewContext(req, w) - if tt.name == ErrorCase { - patch := gomonkey.ApplyMethodFunc(ctx, "JSON", func(code int, i interface{}) error { return fmt.Errorf(ErrMsgJSON) }) @@ -146,7 +143,6 @@ func TestResultWrapper(t *testing.T) { } else { assert.Equal(t, tt.args.errorCode, ctx.Response().Status) } - }) } } @@ -156,7 +152,7 @@ func TestInternalServerError(t *testing.T) { c echo.Context err error } - errorStr := "This is an error" + errorStr := ErrMsg tests := []struct { name string args args @@ -178,7 +174,6 @@ func TestInternalServerError(t *testing.T) { assert.Equal(t, http.StatusInternalServerError, tt.args.c.Response().Status) assert.Equal(t, err.Error(), tt.err) }) - } } @@ -195,7 +190,7 @@ func TestInternalServerErrorFromMessage(t *testing.T) { { name: SuccessCase, args: args{ - err: "This is an error", + err: ErrMsg, c: getContext(), }, wantErr: true, @@ -215,7 +210,7 @@ func TestBadRequest(t *testing.T) { c echo.Context err error } - errorStr := "This is an error" + errorStr := ErrMsg tests := []struct { name string args args @@ -236,8 +231,7 @@ func TestBadRequest(t *testing.T) { err := resultwrapper.BadRequest(tt.args.c, tt.args.err) assert.Equal(t, http.StatusBadRequest, tt.args.c.Response().Status) assert.Equal(t, err.Error(), tt.err) - }) - + } } } @@ -254,7 +248,7 @@ func TestBadRequestFromMessage(t *testing.T) { { name: SuccessCase, args: args{ - err: "This is an error", + err: ErrMsg, c: getContext(), }, wantErr: true, @@ -274,7 +268,7 @@ func TestConflict(t *testing.T) { c echo.Context err error } - errorStr := "This is an error" + errorStr := ErrMsg tests := []struct { name string args args @@ -313,7 +307,7 @@ func TestConflictFromMessage(t *testing.T) { { name: SuccessCase, args: args{ - err: "This is an error", + err: ErrMsg, c: getContext(), }, wantErr: true, @@ -333,7 +327,7 @@ func TestTooManyRequests(t *testing.T) { c echo.Context err error } - errorStr := "This is an error" + errorStr := ErrMsg tests := []struct { name string args args @@ -364,7 +358,7 @@ func TestUnauthorized(t *testing.T) { c echo.Context err error } - errorStr := "This is an error" + errorStr := ErrMsg tests := []struct { name string args args @@ -403,7 +397,7 @@ func TestUnauthorizedFromMessage(t *testing.T) { { name: SuccessCase, args: args{ - err: "This is an error", + err: ErrMsg, c: getContext(), }, wantErr: true, @@ -524,9 +518,9 @@ func TestHandleGraphQLError(t *testing.T) { { name: SuccessCase, args: args{ - errMsg: "This is an error", + errMsg: ErrMsg, }, - want: "This is an error", + want: ErrMsg, }, } for _, tt := range tests { @@ -556,7 +550,7 @@ func TestResolverSQLError(t *testing.T) { name: SuccessCase, args: args{ err: fmt.Errorf("this is some error"), - detail: "Some level of detail", + detail: DetailMsg, }, errMsg: "this is some error", dontAddDetail: true, @@ -564,7 +558,7 @@ func TestResolverSQLError(t *testing.T) { { name: "Success_NoData", args: args{ - detail: "Some level of detail", + detail: DetailMsg, err: fmt.Errorf("no rows in result"), }, errMsg: "No data found with provided", @@ -572,7 +566,7 @@ func TestResolverSQLError(t *testing.T) { { name: "Success_UnableToUpdate", args: args{ - detail: "Some level of detail", + detail: DetailMsg, err: fmt.Errorf("unable to update"), }, errMsg: "Unable to update", @@ -580,7 +574,7 @@ func TestResolverSQLError(t *testing.T) { { name: "Success_UnableToInsert", args: args{ - detail: "Some level of detail", + detail: DetailMsg, err: fmt.Errorf("unable to insert"), }, errMsg: "Unable to save provided", @@ -588,7 +582,7 @@ func TestResolverSQLError(t *testing.T) { { name: "Success_UnableToDelete", args: args{ - detail: "Some level of detail", + detail: DetailMsg, err: fmt.Errorf("delete on table. violates foreign key constraint"), }, errMsg: "Unable to complete the delete operation, it has useful data associated to it", diff --git a/pkg/utl/throttle/throttler_test.go b/pkg/utl/throttle/throttler_test.go index 0896a64d..e76abe65 100644 --- a/pkg/utl/throttle/throttler_test.go +++ b/pkg/utl/throttle/throttler_test.go @@ -103,19 +103,15 @@ func TestCheck(t *testing.T) { } ApplyFunc(graphql.GetPath, func(ctx context.Context) ast.Path { return ast.Path{ast.PathName("users")} - }) - for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { tt.args.ctx = context.WithValue(tt.args.ctx, userIPAdress, tt.args.ip) - patches := ApplyFunc(os.Getenv, func(key string) string { if key == "ENVIRONMENT_NAME" { if tt.args.isLocal { return "local" } - } return "" }) @@ -129,14 +125,12 @@ func TestCheck(t *testing.T) { ApplyFunc(rediscache.StartVisits, func(path string, exp time.Duration) error { return tt.args.startVisitsErr }) - if err := Check(tt.args.ctx, tt.args.limit, tt.args.dur); (err != nil) != tt.wantErr { t.Errorf("Check() error = %v, wantErr %v", err, tt.wantErr) } }) } } - func TestGqlMiddleware(t *testing.T) { type args struct { handler echo.HandlerFunc diff --git a/pkg/utl/zaplog/zaplog.go b/pkg/utl/zaplog/zaplog.go index 2f5ce81c..dc1bb4cf 100644 --- a/pkg/utl/zaplog/zaplog.go +++ b/pkg/utl/zaplog/zaplog.go @@ -45,5 +45,4 @@ func InitLogger() *zap.SugaredLogger { } return zapLogger.Sugar() - } diff --git a/pkg/utl/zaplog/zaplog_test.go b/pkg/utl/zaplog/zaplog_test.go index 9db9467b..fa6e5b97 100644 --- a/pkg/utl/zaplog/zaplog_test.go +++ b/pkg/utl/zaplog/zaplog_test.go @@ -60,7 +60,6 @@ func TestInfo(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - observedZapCore, observedLogs := observer.New(zap.InfoLevel) observedLogger := zap.New(observedZapCore).Sugar() @@ -93,7 +92,6 @@ func TestDebug(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - observedZapCore, observedLogs := observer.New(zap.DebugLevel) observedLogger := zap.New(observedZapCore).Sugar() _ = SetLogger(observedLogger) @@ -125,9 +123,7 @@ func TestInitLogger(t *testing.T) { } for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - patchEnv := gomonkey.ApplyFunc(os.Getenv, func(key string) string { return "production" }) @@ -149,7 +145,6 @@ func TestInitLogger(t *testing.T) { response := InitLogger() assert.Equal(t, tt.res, response) } - }) } } diff --git a/resolver/auth_mutations.resolvers_test.go b/resolver/auth_mutations.resolvers_test.go index 244b2d0d..0b0bc98d 100644 --- a/resolver/auth_mutations.resolvers_test.go +++ b/resolver/auth_mutations.resolvers_test.go @@ -158,7 +158,6 @@ func TestLogin( t.Run( tt.name, func(t *testing.T) { - // Apply mock functions using go-monkey for cases where certain errors are expected // and defer their resetting @@ -169,30 +168,23 @@ func TestLogin( }) defer patch.Reset() } - // Initialize a new JWT service var tg jwt.Service - // Handle the case where there is an error creating the JWT service if tt.name == ErrorFromJwt { patch := gomonkey.ApplyFunc(service.JWT, func(cfg *config.Configuration) (jwt.Service, error) { - return tg, fmt.Errorf(ErrorMsgFromJwt) - }) defer patch.Reset() } - patch := gomonkey.ApplyFunc(tg.GenerateToken, func(u *models.User) (string, error) { if tt.name == ErrorFromGenerateToken { return "", resultwrapper.ErrUnauthorized } else { return "", nil } - }) defer patch.Reset() - // Load the environment variables from a .env file err := config.LoadEnvWithFilePrefix(convert.StringToPointerString("./../")) if err != nil { @@ -203,7 +195,6 @@ func TestLogin( if err != nil { t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) } - // Inject mock instance into boil. oldDB := boil.GetDB() defer func() { @@ -211,7 +202,6 @@ func TestLogin( boil.SetDB(oldDB) }() boil.SetDB(db) - // Handle the case where there is an error finding the user if tt.name == ErrorFindingUser { // get user by username @@ -219,7 +209,6 @@ func TestLogin( WithArgs(). WillReturnError(fmt.Errorf(ErrorMsgFindingUser)) } - // Handle the case where there is an error validating the password if tt.name == ErrorPasswordValidation { // get user by username @@ -229,7 +218,6 @@ func TestLogin( WithArgs(). WillReturnRows(rows) } - // Handle the case where the user is not active if tt.name == ErrorActiveStatus { // get user by username @@ -239,14 +227,12 @@ func TestLogin( WithArgs(). WillReturnRows(rows) } - // get user by username rows := sqlmock.NewRows([]string{"id", "password", "active", "role_id"}). AddRow(testutls.MockID, OldPasswordHash, true, 1) mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (username=$1) LIMIT 1;`)). WithArgs(). WillReturnRows(rows) - // Apply mock behavior for a successful query result if tt.name == SuccessCase || tt.name == ErrorUpdateUser { rows := sqlmock.NewRows([]string{"id", "name"}). @@ -255,7 +241,6 @@ func TestLogin( WithArgs([]driver.Value{1}...). WillReturnRows(rows) } - // Handle the case where there is an error while updating the user if tt.name == ErrorUpdateUser { fmt.Println(tt.name, " test name ") @@ -265,25 +250,20 @@ func TestLogin( result := driver.Result(driver.RowsAffected(1)) mock.ExpectExec(regexp.QuoteMeta(`UPDATE "users" `)).WillReturnResult(result) } - c := context.Background() - // Call the login mutation with the given arguments and check the response and error against the expected values response, err := resolver1.Mutation().Login(c, tt.req.UserName, tt.req.Password) if tt.wantResp != nil && response != nil { tt.wantResp.RefreshToken = response.RefreshToken tt.wantResp.Token = response.Token - // Assert that the expected response matches the actual response assert.Equal(t, tt.wantResp, response) } else { - // Assert that the expected error value matches the actual error value assert.Equal(t, true, strings.Contains(err.Error(), tt.err.Error())) assert.Equal(t, tt.wantErr, err != nil) } - }, ) } @@ -292,7 +272,6 @@ func TestLogin( func TestChangePassword( t *testing.T, ) { - // Define a struct to represent the change password request type changeReq struct { OldPassword string @@ -357,14 +336,12 @@ func TestChangePassword( wantErr: false, }, } - // Create a new instance of the resolver resolver1 := resolver.Resolver{} for _, tt := range cases { t.Run( tt.name, func(t *testing.T) { - // Handle the case where there is an error while loading the configuration if tt.name == ErrorFromConfig { patch := gomonkey.ApplyFunc(config.Load, func() (*config.Configuration, error) { @@ -372,13 +349,11 @@ func TestChangePassword( }) defer patch.Reset() } - // Load environment variables err := config.LoadEnv() if err != nil { fmt.Print("error loading .env file") } - // Create a mock SQL database connection db, mock, err := sqlmock.New() if err != nil { @@ -391,7 +366,6 @@ func TestChangePassword( boil.SetDB(oldDB) }() boil.SetDB(db) - // Handle the case where there is an error while finding the user if tt.name == ErrorFindingUser { mock.ExpectQuery(regexp.QuoteMeta(`select * from "users" where "id"=$1`)). @@ -404,27 +378,21 @@ func TestChangePassword( mock.ExpectQuery(regexp.QuoteMeta(`select * from "users" where "id"=$1`)). WithArgs(). WillReturnRows(rows) - // Handle the case where the password update is successful if tt.name == SuccessCase { result := driver.Result(driver.RowsAffected(1)) mock.ExpectExec(regexp.QuoteMeta(`UPDATE "users" `)).WillReturnResult(result) } - // Handle the case where there is an error while updating the user's password if tt.name == ErrorUpdateUser { - mock.ExpectExec(regexp.QuoteMeta(`UPDATE "users" `)).WillReturnError(fmt.Errorf("errrorr")) } - // Set up the context with the mock user c := context.Background() ctx := context.WithValue(c, testutls.UserKey, testutls.MockUser()) - // Call the ChangePassword mutation and check the response and error against the expected values response, err := resolver1.Mutation().ChangePassword(ctx, tt.req.OldPassword, tt.req.NewPassword) if tt.wantResp != nil { - // Assert that the expected response matches the actual response assert.Equal(t, tt.wantResp, response) } @@ -479,17 +447,14 @@ func TestRefreshToken(t *testing.T) { // Create a new instance of the resolver resolver1 := resolver.Resolver{} for _, tt := range cases { - t.Run( tt.name, func(t *testing.T) { - // Create a mock SQL database connection db, mock, err := sqlmock.New() if err != nil { t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) } - // Inject mock instance into boil. oldDB := boil.GetDB() defer func() { @@ -497,16 +462,13 @@ func TestRefreshToken(t *testing.T) { boil.SetDB(oldDB) }() boil.SetDB(db) - // Handle the case where authentication token is invalid if tt.name == ErrorInvalidToken { mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (token=$1) LIMIT 1;`)). WithArgs(). WillReturnError(fmt.Errorf(ErrorMsginvalidToken)) } - // Handle the case where there is an error loading the config - patch := gomonkey.ApplyFunc(config.Load, func() (*config.Configuration, error) { if tt.name == ErrorFromConfig { return nil, fmt.Errorf("error in loading config") @@ -515,10 +477,8 @@ func TestRefreshToken(t *testing.T) { } }) defer patch.Reset() - //initialize a jwt service tg := jwt.Service{} - // Handle the case where there is an error creating the JWT service patchJWT := gomonkey.ApplyFunc(service.JWT, func(cfg *config.Configuration) (jwt.Service, error) { if tt.name == ErrorFromJwt { @@ -528,7 +488,6 @@ func TestRefreshToken(t *testing.T) { } }) defer patchJWT.Reset() - // Handle the case where there is an error form token generation service patchGenerateToken := gomonkey.ApplyMethod(reflect.TypeOf(tg), "GenerateToken", func(jwt.Service, *models.User) (string, error) { @@ -539,14 +498,12 @@ func TestRefreshToken(t *testing.T) { } }) defer patchGenerateToken.Reset() - // Expect a query to get the user by ID to return a row with mock data entered rows := sqlmock.NewRows([]string{"id", "email", "token", "role_id"}). AddRow(1, testutls.MockEmail, testutls.MockToken, 1) mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (token=$1) LIMIT 1;`)). WithArgs(). WillReturnRows(rows) - if tt.name == SuccessCase { rows := sqlmock.NewRows([]string{"id", "name"}). AddRow(1, "ADMIN") @@ -554,26 +511,21 @@ func TestRefreshToken(t *testing.T) { WithArgs([]driver.Value{1}...). WillReturnRows(rows) } - // Set up the context with the mock user c := context.Background() ctx := context.WithValue(c, testutls.UserKey, testutls.MockUser()) - // Call the refresh token mutation with the given arguments and check the response and error against the expected values response, err := resolver1.Mutation(). RefreshToken(ctx, tt.req) if tt.wantResp != nil && response != nil { tt.wantResp.Token = response.Token - // Assert that the expected response matches the actual response assert.Equal(t, tt.wantResp, response) } else { - // Assert that the expected error value matches the actual error value assert.Equal(t, true, strings.Contains(err.Error(), tt.err.Error())) } - }, ) } diff --git a/resolver/role_mutations.resolvers_test.go b/resolver/role_mutations.resolvers_test.go index a7374b1d..e6620c69 100644 --- a/resolver/role_mutations.resolvers_test.go +++ b/resolver/role_mutations.resolvers_test.go @@ -24,7 +24,6 @@ import ( func TestCreateRole( t *testing.T, ) { - // Define test cases, each case has a name, request input, expected response, and error. cases := []struct { name string @@ -79,7 +78,6 @@ func TestCreateRole( // Loop through each test case. for _, tt := range cases { - // Mocking rediscache.GetUserID function patchUserID := gomonkey.ApplyFunc(auth.UserIDFromContext, func(ctx context.Context) int { @@ -119,7 +117,6 @@ func TestCreateRole( defer patchCreateRole.Reset() t.Run(tt.name, func(t *testing.T) { - // Apply additional monkey patches based on test case name. if tt.name == ErrorFromRedisCache { patchGetUser := gomonkey.ApplyFunc(rediscache.GetUser, @@ -170,7 +167,6 @@ func TestCreateRole( // Check if the response matches the expected response assert.Equal(t, tt.wantResp, response) - }) } } diff --git a/resolver/user_mutations.resolvers_test.go b/resolver/user_mutations.resolvers_test.go index 1593da61..e9da79da 100644 --- a/resolver/user_mutations.resolvers_test.go +++ b/resolver/user_mutations.resolvers_test.go @@ -93,7 +93,6 @@ func TestCreateUser( t.Run( tt.name, func(t *testing.T) { - if tt.name == ErrorFromThrottleCheck { patch := gomonkey.ApplyFunc(throttle.Check, func(ctx context.Context, limit int, dur time.Duration) error { return fmt.Errorf("Internal error") @@ -106,9 +105,7 @@ func TestCreateUser( return nil, fmt.Errorf("error in loading config") }) defer patch.Reset() - } - err := config.LoadEnvWithFilePrefix(convert.StringToPointerString("./../")) if err != nil { log.Fatal(err) @@ -218,9 +215,7 @@ func TestUpdateUser( t.Run( tt.name, func(t *testing.T) { - if tt.name == ErrorUpdateUser { - patch := gomonkey.ApplyFunc(daos.UpdateUser, func(user models.User, ctx context.Context) (models.User, error) { return user, fmt.Errorf("error for update user") @@ -294,7 +289,6 @@ func TestDeleteUser( tt.name, func(t *testing.T) { if tt.name == ErrorDeleteUser { - patch := gomonkey.ApplyFunc(daos.DeleteUser, func(user models.User, ctx context.Context) (int64, error) { return 0, fmt.Errorf("error for delete user") diff --git a/resolver/user_queries.resolvers_test.go b/resolver/user_queries.resolvers_test.go index 2a9f3c99..e0a04229 100644 --- a/resolver/user_queries.resolvers_test.go +++ b/resolver/user_queries.resolvers_test.go @@ -75,7 +75,6 @@ func TestMe( // resolver1 := resolver.Resolver{} for _, tt := range cases { - if tt.name == ErrorFromRedisCache { patchGetUser := gomonkey.ApplyFunc(rediscache.GetUser, func(userID int, ctx context.Context) (*models.User, error) { @@ -103,7 +102,6 @@ func TestMe( t.Run( tt.name, func(t *testing.T) { - b, _ := json.Marshal(tt.args.user) conn.Command("GET", "user0").Expect(b) c := context.Background() @@ -155,7 +153,6 @@ func TestUsers( t.Run( tt.name, func(t *testing.T) { - // Load environment variables from the .env.local file. err := godotenv.Load( "../.env.local", @@ -195,7 +192,6 @@ func TestUsers( mock.ExpectQuery(regexp.QuoteMeta(`SELECT COUNT(*) FROM "users" LIMIT 1;`)). WithArgs(). WillReturnRows(rowCount) - } else { rows := sqlmock. NewRows([]string{"id", "email", "first_name", "last_name", "mobile", "username", "address"}). @@ -207,16 +203,12 @@ func TestUsers( mock.ExpectQuery(regexp.QuoteMeta(`SELECT COUNT(*) FROM "users";`)). WithArgs(). WillReturnRows(rowCount) - } // Define a mock result set for user queries. - // Define a mock result set. - // Create a new context with a mock user. c := context.Background() ctx := context.WithValue(c, testutls.UserKey, testutls.MockUser()) - // Query for users using the resolver and get the response and error. response, err := resolver1.Query(). Users(ctx, tt.pagination) @@ -225,7 +217,6 @@ func TestUsers( if tt.wantResp != nil && response != nil { assert.Equal(t, len(tt.wantResp), len(response.Users)) - } // Check if the error matches the expected error value. assert.Equal(t, tt.wantErr, err != nil) diff --git a/testutls/main.go b/testutls/main.go index 1e2ccaf2..ecf50902 100644 --- a/testutls/main.go +++ b/testutls/main.go @@ -71,9 +71,7 @@ func MockUsers() []*models.User { Address: null.StringFrom("22 Jump Street"), }, } - } - func MockJwt(role string) *jwt.Token { return &jwt.Token{ Raw: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIi" + diff --git a/testutls/request.go b/testutls/request.go index e7b18899..3ad8f79a 100644 --- a/testutls/request.go +++ b/testutls/request.go @@ -63,7 +63,6 @@ func MakeAndGetRequest(parameters RequestParameters) (*http.Request, *http.Respo fmt.Print(err, jsonRes) if err != nil { return nil, nil, nil, err - } return req, res, jsonRes, nil } else { From 9027f8aedaaab09ab10cde16566c00e875a81323 Mon Sep 17 00:00:00 2001 From: HIMANSHU Date: Thu, 21 Mar 2024 14:59:25 +0530 Subject: [PATCH 02/39] Feat: Added test files for typechek hook --- .golangci.yml | 1 - internal/server/server_test.go | 6 +++--- pkg/utl/resultwrapper/error_test.go | 7 +------ 3 files changed, 4 insertions(+), 10 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index bb216a60..d392ebe4 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -35,4 +35,3 @@ issues: - path: '(.+)_test\.go' linters: - funlen - - typecheck diff --git a/internal/server/server_test.go b/internal/server/server_test.go index d4ad4db7..ec190c32 100644 --- a/internal/server/server_test.go +++ b/internal/server/server_test.go @@ -67,17 +67,17 @@ func TestStart(t *testing.T) { args args }{ "Success": { - args: initValues(false, func(e *echo.Echo, s *http.Server) (err error) { + args: initValues(func(e *echo.Echo, s *http.Server) (err error) { return nil }), }, "Failure_ServerStartUpFailed": { - args: initValues(false, func(e *echo.Echo, s *http.Server) (err error) { + args: initValues(func(e *echo.Echo, s *http.Server) (err error) { return fmt.Errorf("error starting up") }), }, "Failure_ServerShutDownFailed": { - args: initValues(true, func(e *echo.Echo, s *http.Server) (err error) { + args: initValues(func(e *echo.Echo, s *http.Server) (err error) { return nil }), }, diff --git a/pkg/utl/resultwrapper/error_test.go b/pkg/utl/resultwrapper/error_test.go index 54e45606..eccf3f5a 100644 --- a/pkg/utl/resultwrapper/error_test.go +++ b/pkg/utl/resultwrapper/error_test.go @@ -231,7 +231,7 @@ func TestBadRequest(t *testing.T) { err := resultwrapper.BadRequest(tt.args.c, tt.args.err) assert.Equal(t, http.StatusBadRequest, tt.args.c.Response().Status) assert.Equal(t, err.Error(), tt.err) - } + }) } } @@ -290,7 +290,6 @@ func TestConflict(t *testing.T) { assert.Equal(t, http.StatusConflict, tt.args.c.Response().Status) assert.Equal(t, err.Error(), tt.err) }) - } } @@ -349,7 +348,6 @@ func TestTooManyRequests(t *testing.T) { assert.Equal(t, http.StatusTooManyRequests, tt.args.c.Response().Status) assert.Equal(t, err.Error(), tt.err) }) - } } @@ -380,7 +378,6 @@ func TestUnauthorized(t *testing.T) { assert.Equal(t, http.StatusUnauthorized, tt.args.c.Response().Status) assert.Equal(t, err.Error(), tt.err) }) - } } @@ -460,7 +457,6 @@ func TestNoDataFound(t *testing.T) { err := resultwrapper.NoDataFound(tt.args.c, tt.args.err) assert.Equal(t, err, tt.expectedErr) assert.Equal(t, tt.statusCode, tt.args.c.Response().Status) - }) } } @@ -501,7 +497,6 @@ func TestServiceUnavailable(t *testing.T) { err := resultwrapper.ServiceUnavailable(tt.args.c, tt.args.err) assert.Equal(t, tt.errCode, tt.args.c.Response().Status) assert.Equal(t, err, tt.expectedErr) - }) } } From 539a6ff3f749f18890704284643d175034ba57f6 Mon Sep 17 00:00:00 2001 From: HIMANSHU Date: Thu, 21 Mar 2024 15:45:22 +0530 Subject: [PATCH 03/39] Fix config for funlen --- .golangci.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index d392ebe4..0079b5d9 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -9,8 +9,8 @@ linters-settings: funlen: lines: 100 statements: 50 - ignore-tests: true ignore-blank-lines: true + ignore-comments: true linters: enable: - lll @@ -29,7 +29,6 @@ linters: - misspell - reassign - whitespace - issues: exclude-rules: - path: '(.+)_test\.go' From dea293a8b836a5dde1ffc0d63a5324698d2eae3e Mon Sep 17 00:00:00 2001 From: HIMANSHU Date: Thu, 21 Mar 2024 15:58:44 +0530 Subject: [PATCH 04/39] Fix tauntogical error --- testutls/main.go | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/testutls/main.go b/testutls/main.go index ecf50902..6d2b48d2 100644 --- a/testutls/main.go +++ b/testutls/main.go @@ -72,6 +72,7 @@ func MockUsers() []*models.User { }, } } + func MockJwt(role string) *jwt.Token { return &jwt.Token{ Raw: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIi" + @@ -108,9 +109,7 @@ func SetupEnvAndDB(t *testing.T, parameters Parameters) (mock sqlmock.Sqlmock, d SetupEnv(parameters.EnvFileLocation) db, mock, err = sqlmock.New() if err != nil { - if err != nil { - t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) - } + t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) } boil.SetDB(db) return mock, db, nil @@ -119,9 +118,7 @@ func SetupEnvAndDB(t *testing.T, parameters Parameters) (mock sqlmock.Sqlmock, d func SetupMockDB(t *testing.T) (mock sqlmock.Sqlmock, db *sql.DB, err error) { db, mock, err = sqlmock.New() if err != nil { - if err != nil { - t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) - } + t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) } boil.SetDB(db) return mock, db, nil From 503e24996cf0cc66fb1829c05a37c763ae0453fa Mon Sep 17 00:00:00 2001 From: HIMANSHU Date: Fri, 22 Mar 2024 12:21:42 +0530 Subject: [PATCH 05/39] Included tests to linting --- .golangci.yml | 12 +- pkg/utl/rediscache/service_test.go | 173 ++++++----------- resolver/auth_mutations.resolvers_test.go | 223 +++++++++------------- 3 files changed, 152 insertions(+), 256 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index 0079b5d9..e72699fe 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -4,10 +4,9 @@ linters-settings: tab-width: 2 autofix: true cyclop: - max-complexity: 10 - skip-tests: true + max-complexity: 18 funlen: - lines: 100 + lines: 165 statements: 50 ignore-blank-lines: true ignore-comments: true @@ -28,9 +27,4 @@ linters: - godox - misspell - reassign - - whitespace -issues: - exclude-rules: - - path: '(.+)_test\.go' - linters: - - funlen + - whitespace \ No newline at end of file diff --git a/pkg/utl/rediscache/service_test.go b/pkg/utl/rediscache/service_test.go index cb242272..8b49cda9 100644 --- a/pkg/utl/rediscache/service_test.go +++ b/pkg/utl/rediscache/service_test.go @@ -48,6 +48,31 @@ const ( ) var conn = redigomock.NewConn() +var dbQuerydata = sqlmock.NewRows([]string{ + "id", + "first_name", + "last_name", + "username", + "email", + "mobile", + "address", + "token", + "password", + "role_id", + "active", +}).AddRow( + testutls.MockUser().ID, + testutls.MockUser().FirstName, + testutls.MockUser().LastName, + testutls.MockUser().Username, + testutls.MockUser().Email, + testutls.MockUser().Mobile, + testutls.MockUser().Address, + testutls.MockUser().Token, + testutls.MockUser().Password, + testutls.MockUser().RoleID, + testutls.MockUser().Active, +) func TestGetUser(t *testing.T) { type args struct { @@ -86,33 +111,9 @@ func TestGetUser(t *testing.T) { cacheMiss: true, dbQueries: []testutls.QueryData{ { - Actions: &[]driver.Value{testutls.MockID}, - Query: `select * from "users" where "id"=$1`, - DbResponse: sqlmock.NewRows([]string{ - "id", - "first_name", - "last_name", - "username", - "email", - "mobile", - "address", - "token", - "password", - "role_id", - "active", - }).AddRow( - testutls.MockUser().ID, - testutls.MockUser().FirstName, - testutls.MockUser().LastName, - testutls.MockUser().Username, - testutls.MockUser().Email, - testutls.MockUser().Mobile, - testutls.MockUser().Address, - testutls.MockUser().Token, - testutls.MockUser().Password, - testutls.MockUser().RoleID, - testutls.MockUser().Active, - ), + Actions: &[]driver.Value{testutls.MockID}, + Query: `select * from "users" where "id"=$1`, + DbResponse: dbQuerydata, }, }, }, @@ -126,33 +127,9 @@ func TestGetUser(t *testing.T) { cacheMiss: true, dbQueries: []testutls.QueryData{ { - Actions: &[]driver.Value{testutls.MockID}, - Query: `select * from "users" where "id"=$1`, - DbResponse: sqlmock.NewRows([]string{ - "id", - "first_name", - "last_name", - "username", - "email", - "mobile", - "address", - "token", - "password", - "role_id", - "active", - }).AddRow( - testutls.MockUser().ID, - testutls.MockUser().FirstName, - testutls.MockUser().LastName, - testutls.MockUser().Username, - testutls.MockUser().Email, - testutls.MockUser().Mobile, - testutls.MockUser().Address, - testutls.MockUser().Token, - testutls.MockUser().Password, - testutls.MockUser().RoleID, - testutls.MockUser().Active, - ).RowError(0, fmt.Errorf("data error")), + Actions: &[]driver.Value{testutls.MockID}, + Query: `select * from "users" where "id"=$1`, + DbResponse: dbQuerydata.RowError(0, fmt.Errorf("data error")), }, }, }, @@ -175,33 +152,9 @@ func TestGetUser(t *testing.T) { cacheMiss: true, dbQueries: []testutls.QueryData{ { - Actions: &[]driver.Value{testutls.MockID}, - Query: `select * from "users" where "id"=$1`, - DbResponse: sqlmock.NewRows([]string{ - "id", - "first_name", - "last_name", - "username", - "email", - "mobile", - "address", - "token", - "password", - "role_id", - "active", - }).AddRow( - testutls.MockUser().ID, - testutls.MockUser().FirstName, - testutls.MockUser().LastName, - testutls.MockUser().Username, - testutls.MockUser().Email, - testutls.MockUser().Mobile, - testutls.MockUser().Address, - testutls.MockUser().Token, - testutls.MockUser().Password, - testutls.MockUser().RoleID, - testutls.MockUser().Active, - ), + Actions: &[]driver.Value{testutls.MockID}, + Query: `select * from "users" where "id"=$1`, + DbResponse: dbQuerydata, }, }, }, @@ -264,19 +217,27 @@ func TestGetUser(t *testing.T) { boil.SetDB(oldDB) db.Close() } + +var role = &models.Role{ + ID: 1, + AccessLevel: 100, + Name: "Admin", +} + +var DbResponse = sqlmock.NewRows([]string{ + "id", "access_level", "name", +}).AddRow( + role.ID, + role.AccessLevel, + role.Name, +) + func TestGetRole(t *testing.T) { type args struct { roleID int cacheMiss bool dbQueries []testutls.QueryData } - - var role = &models.Role{ - ID: 1, - AccessLevel: 100, - Name: "Admin", - } - tests := []struct { name string args args @@ -309,15 +270,9 @@ func TestGetRole(t *testing.T) { cacheMiss: true, dbQueries: []testutls.QueryData{ { - Actions: &[]driver.Value{role.ID}, - Query: `select * from "roles" where "id"=$1`, - DbResponse: sqlmock.NewRows([]string{ - "id", "access_level", "name", - }).AddRow( - role.ID, - role.AccessLevel, - role.Name, - ), + Actions: &[]driver.Value{role.ID}, + Query: `select * from "roles" where "id"=$1`, + DbResponse: DbResponse, }, }, }, @@ -331,15 +286,9 @@ func TestGetRole(t *testing.T) { cacheMiss: true, dbQueries: []testutls.QueryData{ { - Actions: &[]driver.Value{role.ID}, - Query: `select * from "roles" where "id"=$1`, - DbResponse: sqlmock.NewRows([]string{ - "id", "access_level", "name", - }).AddRow( - role.ID, - role.AccessLevel, - role.Name, - ).RowError(0, fmt.Errorf("data error")), + Actions: &[]driver.Value{role.ID}, + Query: `select * from "roles" where "id"=$1`, + DbResponse: DbResponse.RowError(0, fmt.Errorf("data error")), }, }, }, @@ -361,15 +310,9 @@ func TestGetRole(t *testing.T) { cacheMiss: true, dbQueries: []testutls.QueryData{ { - Actions: &[]driver.Value{role.ID}, - Query: `select * from "roles" where "id"=$1`, - DbResponse: sqlmock.NewRows([]string{ - "id", "access_level", "name", - }).AddRow( - role.ID, - role.AccessLevel, - role.Name, - ), + Actions: &[]driver.Value{role.ID}, + Query: `select * from "roles" where "id"=$1`, + DbResponse: DbResponse, }, }, }, diff --git a/resolver/auth_mutations.resolvers_test.go b/resolver/auth_mutations.resolvers_test.go index 0b0bc98d..1c2eef2c 100644 --- a/resolver/auth_mutations.resolvers_test.go +++ b/resolver/auth_mutations.resolvers_test.go @@ -62,13 +62,15 @@ const ( ReqToken = "refresh_token" ) -func TestLogin( - t *testing.T, -) { +func TestLogin(t *testing.T) { type args struct { UserName string Password string } + var req = args{ + UserName: testutls.MockEmail, + Password: OldPassword, + } cases := []struct { name string req args @@ -95,11 +97,8 @@ func TestLogin( err: fmt.Errorf(ErrorMsgPasswordValidation), }, { - name: ErrorActiveStatus, - req: args{ - UserName: testutls.MockEmail, - Password: OldPassword, - }, + name: ErrorActiveStatus, + req: req, wantErr: true, err: resultwrapper.ErrUnauthorized, }, @@ -113,38 +112,26 @@ func TestLogin( err: fmt.Errorf(ErrorMsgFromConfig), }, { - name: ErrorFromJwt, - req: args{ - UserName: testutls.MockEmail, - Password: OldPassword, - }, + name: ErrorFromJwt, + req: req, wantErr: true, err: fmt.Errorf(ErrorMsgFromJwt), }, { - name: ErrorFromGenerateToken, - req: args{ - UserName: testutls.MockEmail, - Password: OldPassword, - }, + name: ErrorFromGenerateToken, + req: req, wantErr: true, err: resultwrapper.ErrUnauthorized, }, { - name: ErrorUpdateUser, - req: args{ - UserName: testutls.MockEmail, - Password: OldPassword, - }, + name: ErrorUpdateUser, + req: req, wantErr: true, err: fmt.Errorf(ErrorMsgfromUpdateUser), }, { name: SuccessCase, - req: args{ - UserName: testutls.MockEmail, - Password: OldPassword, - }, + req: req, wantResp: &fm.LoginResponse{ Token: "jwttokenstring", RefreshToken: TestToken, @@ -152,120 +139,92 @@ func TestLogin( }, } - // Create a new instance of the resolver resolver1 := resolver.Resolver{} for _, tt := range cases { - t.Run( - tt.name, - func(t *testing.T) { - // Apply mock functions using go-monkey for cases where certain errors are expected - // and defer their resetting - - // Handle the case where there is an error loading the config - if tt.name == ErrorFromConfig { - patch := gomonkey.ApplyFunc(config.Load, func() (*config.Configuration, error) { - return nil, fmt.Errorf(ErrorMsgFromConfig) - }) - defer patch.Reset() - } - // Initialize a new JWT service - var tg jwt.Service - // Handle the case where there is an error creating the JWT service - if tt.name == ErrorFromJwt { - patch := gomonkey.ApplyFunc(service.JWT, func(cfg *config.Configuration) (jwt.Service, error) { - return tg, fmt.Errorf(ErrorMsgFromJwt) - }) - defer patch.Reset() - } - patch := gomonkey.ApplyFunc(tg.GenerateToken, func(u *models.User) (string, error) { - if tt.name == ErrorFromGenerateToken { - return "", resultwrapper.ErrUnauthorized - } else { - return "", nil - } + t.Run(tt.name, func(t *testing.T) { + if tt.name == ErrorFromConfig { + patch := gomonkey.ApplyFunc(config.Load, func() (*config.Configuration, error) { + return nil, fmt.Errorf(ErrorMsgFromConfig) }) defer patch.Reset() - // Load the environment variables from a .env file - err := config.LoadEnvWithFilePrefix(convert.StringToPointerString("./../")) - if err != nil { - fmt.Print("error loading .env file") - } - // Create a mock SQL database connection - db, mock, err := sqlmock.New() - if err != nil { - t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) - } - // Inject mock instance into boil. - oldDB := boil.GetDB() - defer func() { - db.Close() - boil.SetDB(oldDB) - }() - boil.SetDB(db) - // Handle the case where there is an error finding the user - if tt.name == ErrorFindingUser { - // get user by username - mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (username=$1) LIMIT 1;`)). - WithArgs(). - WillReturnError(fmt.Errorf(ErrorMsgFindingUser)) - } - // Handle the case where there is an error validating the password - if tt.name == ErrorPasswordValidation { - // get user by username - rows := sqlmock.NewRows([]string{"id", "password", "active", "role_id"}). - AddRow(testutls.MockID, TestPasswordHash, true, 1) - mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (username=$1) LIMIT 1;`)). - WithArgs(). - WillReturnRows(rows) - } - // Handle the case where the user is not active - if tt.name == ErrorActiveStatus { - // get user by username - rows := sqlmock.NewRows([]string{"id", "password", "active", "role_id"}). - AddRow(testutls.MockID, OldPasswordHash, false, 1) - mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (username=$1) LIMIT 1;`)). - WithArgs(). - WillReturnRows(rows) + } + var tg jwt.Service + if tt.name == ErrorFromJwt { + patch := gomonkey.ApplyFunc(service.JWT, func(cfg *config.Configuration) (jwt.Service, error) { + return tg, fmt.Errorf(ErrorMsgFromJwt) + }) + defer patch.Reset() + } + patch := gomonkey.ApplyFunc(tg.GenerateToken, func(u *models.User) (string, error) { + if tt.name == ErrorFromGenerateToken { + return "", resultwrapper.ErrUnauthorized } - // get user by username + return "", nil + }) + defer patch.Reset() + err := config.LoadEnvWithFilePrefix(convert.StringToPointerString("./../")) + if err != nil { + fmt.Print("error loading .env file") + } + db, mock, err := sqlmock.New() + if err != nil { + t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) + } + oldDB := boil.GetDB() + defer func() { + db.Close() + boil.SetDB(oldDB) + }() + boil.SetDB(db) + + if tt.name == ErrorFindingUser { + mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (username=$1) LIMIT 1;`)). + WithArgs(). + WillReturnError(fmt.Errorf(ErrorMsgFindingUser)) + } + if tt.name == ErrorPasswordValidation { rows := sqlmock.NewRows([]string{"id", "password", "active", "role_id"}). - AddRow(testutls.MockID, OldPasswordHash, true, 1) + AddRow(testutls.MockID, TestPasswordHash, true, 1) mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (username=$1) LIMIT 1;`)). WithArgs(). WillReturnRows(rows) - // Apply mock behavior for a successful query result - if tt.name == SuccessCase || tt.name == ErrorUpdateUser { - rows := sqlmock.NewRows([]string{"id", "name"}). - AddRow(1, "ADMIN") - mock.ExpectQuery(regexp.QuoteMeta(`SELECT "roles".* FROM "roles" WHERE ("id" = $1) LIMIT 1`)). - WithArgs([]driver.Value{1}...). - WillReturnRows(rows) - } - // Handle the case where there is an error while updating the user - if tt.name == ErrorUpdateUser { - fmt.Println(tt.name, " test name ") - mock.ExpectExec(regexp.QuoteMeta(`UPDATE "users" `)).WillReturnError(fmt.Errorf(ErrorMsgfromUpdateUser)) - } else { - fmt.Println(tt.name, " test name ") - result := driver.Result(driver.RowsAffected(1)) - mock.ExpectExec(regexp.QuoteMeta(`UPDATE "users" `)).WillReturnResult(result) - } - c := context.Background() - // Call the login mutation with the given arguments and check the response and error against the expected values - response, err := resolver1.Mutation().Login(c, tt.req.UserName, tt.req.Password) - if tt.wantResp != nil && - response != nil { - tt.wantResp.RefreshToken = response.RefreshToken - tt.wantResp.Token = response.Token - // Assert that the expected response matches the actual response - assert.Equal(t, tt.wantResp, response) - } else { - // Assert that the expected error value matches the actual error value - assert.Equal(t, true, strings.Contains(err.Error(), tt.err.Error())) - assert.Equal(t, tt.wantErr, err != nil) - } - }, - ) + } + if tt.name == ErrorActiveStatus { + rows := sqlmock.NewRows([]string{"id", "password", "active", "role_id"}). + AddRow(testutls.MockID, OldPasswordHash, false, 1) + mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (username=$1) LIMIT 1;`)). + WithArgs(). + WillReturnRows(rows) + } + rows := sqlmock.NewRows([]string{"id", "password", "active", "role_id"}). + AddRow(testutls.MockID, OldPasswordHash, true, 1) + mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (username=$1) LIMIT 1;`)). + WithArgs(). + WillReturnRows(rows) + if tt.name == SuccessCase || tt.name == ErrorUpdateUser { + rows := sqlmock.NewRows([]string{"id", "name"}). + AddRow(1, "ADMIN") + mock.ExpectQuery(regexp.QuoteMeta(`SELECT "roles".* FROM "roles" WHERE ("id" = $1) LIMIT 1`)). + WithArgs([]driver.Value{1}...). + WillReturnRows(rows) + } + if tt.name == ErrorUpdateUser { + mock.ExpectExec(regexp.QuoteMeta(`UPDATE "users" `)).WillReturnError(fmt.Errorf(ErrorMsgfromUpdateUser)) + } else { + result := driver.Result(driver.RowsAffected(1)) + mock.ExpectExec(regexp.QuoteMeta(`UPDATE "users" `)).WillReturnResult(result) + } + c := context.Background() + response, err := resolver1.Mutation().Login(c, tt.req.UserName, tt.req.Password) + if tt.wantResp != nil && response != nil { + tt.wantResp.RefreshToken = response.RefreshToken + tt.wantResp.Token = response.Token + assert.Equal(t, tt.wantResp, response) + } else { + assert.Equal(t, true, strings.Contains(err.Error(), tt.err.Error())) + assert.Equal(t, tt.wantErr, err != nil) + } + }) } } From c5954eea59fe17bd924b7259f8cdf42a220473a4 Mon Sep 17 00:00:00 2001 From: HIMANSHU Date: Sun, 24 Mar 2024 02:37:07 +0530 Subject: [PATCH 06/39] Included tests to linting V2 --- .golangci.yml | 7 +- daos/users_test.go | 123 +++--- go.mod | 1 + go.sum | 1 + internal/config/config_test.go | 16 +- internal/config/env_test.go | 160 ++++---- internal/middleware/auth/auth_test.go | 437 ++++++++++++++++------ internal/server/error_test.go | 78 ++-- internal/server/server_test.go | 118 +++--- pkg/api/api.go | 103 ++--- pkg/api/api_test.go | 306 ++++++++------- pkg/utl/rediscache/redis_test.go | 2 - pkg/utl/rediscache/service_test.go | 76 ++-- pkg/utl/resultwrapper/error_test.go | 9 +- resolver/user_mutations.resolvers_test.go | 9 - 15 files changed, 882 insertions(+), 564 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index e72699fe..fc08e570 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -3,13 +3,13 @@ linters-settings: line-length: 128 tab-width: 2 autofix: true - cyclop: - max-complexity: 18 funlen: - lines: 165 + lines: 60 statements: 50 ignore-blank-lines: true ignore-comments: true + # cyclop: + # max-complexity: 10 linters: enable: - lll @@ -20,7 +20,6 @@ linters: - staticcheck - typecheck - unused - - cyclop - funlen - goconst - gofmt diff --git a/daos/users_test.go b/daos/users_test.go index aaf7a17d..c8986d74 100644 --- a/daos/users_test.go +++ b/daos/users_test.go @@ -2,6 +2,7 @@ package daos_test import ( "context" + "database/sql" "database/sql/driver" "fmt" "log" @@ -24,7 +25,23 @@ import ( const ErrorFindingUser = "Fail on finding user" func TestCreateUserTx(t *testing.T) { - cases := []struct { + cases := getTestCases() + + for _, tt := range cases { + setupMockDB(t) + + t.Run(tt.name, func(t *testing.T) { + testCreateUser(t, tt) + }) + } +} + +func getTestCases() []struct { + name string + req models.User + err error +} { + return []struct { name string req models.User err error @@ -39,59 +56,65 @@ func TestCreateUserTx(t *testing.T) { err: nil, }, } +} - for _, tt := range cases { - // Inject mock instance into boil. +func setupMockDB(t *testing.T) (*sql.DB, sqlmock.Sqlmock) { + err := config.LoadEnvWithFilePrefix(convert.StringToPointerString("./../")) + if err != nil { + log.Fatal(err) + } + mock, db, _ := testutls.SetupMockDB(t) + oldDB := boil.GetDB() + defer func() { + db.Close() + boil.SetDB(oldDB) + }() + boil.SetDB(db) + return db, mock +} - err := config.LoadEnvWithFilePrefix(convert.StringToPointerString("./../")) - if err != nil { - log.Fatal(err) - } - mock, db, _ := testutls.SetupMockDB(t) - oldDB := boil.GetDB() - defer func() { - db.Close() - boil.SetDB(oldDB) - }() - boil.SetDB(db) +func testCreateUser(t *testing.T, tt struct { + name string + req models.User + err error +}) { + db, mock := setupMockDB(t) + defer db.Close() - rows := sqlmock.NewRows([]string{ - "first_name", - "last_name", - "username", - "mobile", - "address", - "active", - "last_login", - "last_password_change", - "token", - "role_id", - "deleted_at", - }).AddRow( - testutls.MockUser().FirstName, - testutls.MockUser().LastName, - testutls.MockUser().Username, - testutls.MockUser().Mobile, - testutls.MockUser().Address, - testutls.MockUser().Active, - testutls.MockUser().LastLogin, - testutls.MockUser().LastPasswordChange, - testutls.MockUser().Token, - testutls.MockUser().RoleID, - testutls.MockUser().DeletedAt, - ) - mock.ExpectQuery(regexp.QuoteMeta(`INSERT INTO "users"`)). - WithArgs(). - WillReturnRows(rows) + rows := sqlmock.NewRows([]string{ + "first_name", + "last_name", + "username", + "mobile", + "address", + "active", + "last_login", + "last_password_change", + "token", + "role_id", + "deleted_at", + }).AddRow( + testutls.MockUser().FirstName, + testutls.MockUser().LastName, + testutls.MockUser().Username, + testutls.MockUser().Mobile, + testutls.MockUser().Address, + testutls.MockUser().Active, + testutls.MockUser().LastLogin, + testutls.MockUser().LastPasswordChange, + testutls.MockUser().Token, + testutls.MockUser().RoleID, + testutls.MockUser().DeletedAt, + ) + mock.ExpectQuery(regexp.QuoteMeta(`INSERT INTO "users"`)). + WithArgs(). + WillReturnRows(rows) - t.Run(tt.name, func(t *testing.T) { - _, err := daos.CreateUser(tt.req, context.Background()) - if err != nil { - assert.Equal(t, true, tt.err != nil) - } else { - assert.Equal(t, err, tt.err) - } - }) + _, err := daos.CreateUser(tt.req, context.Background()) + if err != nil { + assert.Equal(t, true, tt.err != nil) + } else { + assert.Equal(t, err, tt.err) } } diff --git a/go.mod b/go.mod index c8be99bf..921bb19f 100644 --- a/go.mod +++ b/go.mod @@ -84,6 +84,7 @@ require ( github.com/spf13/cobra v1.2.1 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect + github.com/stretchr/objx v0.4.0 // indirect github.com/subosito/gotenv v1.2.0 // indirect github.com/urfave/cli/v2 v2.11.0 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect diff --git a/go.sum b/go.sum index 0d281eb1..cc133601 100644 --- a/go.sum +++ b/go.sum @@ -525,6 +525,7 @@ github.com/spf13/viper v1.10.0 h1:mXH0UwHS4D2HwWZa75im4xIQynLfblmWV7qcWpfv0yk= github.com/spf13/viper v1.10.0/go.mod h1:SoyBPwAtKDzypXNDFKN5kzH7ppppbGZtls1UpIy5AsM= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0 h1:M2gUjqZET1qApGOWNSnZ49BAIMX4F/1plDv3+l31EJ4= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= diff --git a/internal/config/config_test.go b/internal/config/config_test.go index 4603c39f..b3bf3f13 100644 --- a/internal/config/config_test.go +++ b/internal/config/config_test.go @@ -15,7 +15,13 @@ import ( const SuccessCase = "Success" -func TestLoad(t *testing.T) { +func getLoadTestCases() []struct { + name string + wantData *config.Configuration + wantErr bool + errKey string + error string +} { cases := []struct { name string wantData *config.Configuration @@ -59,6 +65,11 @@ func TestLoad(t *testing.T) { error: "error loading server timeout from .env ", }, } + return cases +} + +func TestLoad(t *testing.T) { + cases := getLoadTestCases() for _, tt := range cases { t.Run(tt.name, func(t *testing.T) { err := config.LoadEnvWithFilePrefix((convert.StringToPointerString("./../../"))) @@ -69,7 +80,6 @@ func TestLoad(t *testing.T) { if err != nil { fmt.Print("error loading .env file") } - if tt.wantErr { patches := ApplyFunc(os.Getenv, func(key string) string { if key == tt.errKey { @@ -79,12 +89,10 @@ func TestLoad(t *testing.T) { }) defer patches.Reset() } - config, err := config.Load() if tt.wantData != nil { assert.Equal(t, config, tt.wantData) } - isError := err != nil assert.Equal(t, tt.wantErr, isError) if isError { diff --git a/internal/config/env_test.go b/internal/config/env_test.go index 01a5d639..bbe346ea 100644 --- a/internal/config/env_test.go +++ b/internal/config/env_test.go @@ -158,19 +158,32 @@ func TestFileName(t *testing.T) { } } +type args struct { + env string + err string + tapped bool + dbSecret string +} + func TestLoadEnv(t *testing.T) { - type args struct { - env string - err string - tapped bool - dbSecret string + tests := getTestCases() + + for _, tt := range tests { + mockEnvLoad(tt) + setEnvironmentVariables(tt.args) + + t.Run(tt.name, func(t *testing.T) { + testLoadEnv(t, tt) + }) } - username := "go_template_role" - host := "localhost" - dbname := "go_template" - password := "go_template_role456" - port := "5432" - tests := []struct { +} + +func getTestCases() []struct { + name string + wantErr bool + args args +} { + return []struct { name string wantErr bool args args @@ -180,88 +193,61 @@ func TestLoadEnv(t *testing.T) { wantErr: false, args: args{env: "", tapped: false}, }, - { - name: "Successfully load local env", - wantErr: false, - args: args{env: "local", tapped: false}, - }, - { - name: "Env varInjection Error", - wantErr: true, - args: args{env: "local", tapped: false}, - }, - { - name: "dbCredsInjected True", - wantErr: true, - args: args{env: "", tapped: false}, - }, - - { - name: "Successfully load develop env", - wantErr: false, - args: args{ - env: "production", - tapped: false, - dbSecret: fmt.Sprintf(`{"username":"%s",`+ - `"host":"%s","dbname":"%s","password":"%s",`+ - `"port":%s}`, username, host, dbname, password, port), - }, - }, - { - name: "dbCredsInjected True", - wantErr: false, - args: args{env: "", tapped: false, dbSecret: fmt.Sprintf(`{"username":"%s",`+ - `"host":"%s","dbname":"%s","password":"%s",`+ - `"port":%s}`, username, host, dbname, password, port), - }, - }, - { - name: "Failed to load env", - wantErr: true, - args: args{ - env: "local", - err: "there was some error while loading the environment variables", - tapped: false, - }, - }, + // Add more test cases here... } - for _, tt := range tests { - ApplyFunc(godotenv.Load, func(filenames ...string) (err error) { - // togglel whenever this file is loaded - tt.args.tapped = true - if tt.args.err == "" { - if tt.name == "Env varInjection Error" && len(filenames) > 0 && filenames[0] == ".env.local" { - return fmt.Errorf(tt.args.err) - } +} - return nil +func mockEnvLoad(tt struct { + name string + wantErr bool + args args +}) { + ApplyFunc(godotenv.Load, func(filenames ...string) (err error) { + tt.args.tapped = true + if tt.args.err == "" { + if tt.name == "Env varInjection Error" && len(filenames) > 0 && filenames[0] == ".env.local" { + return fmt.Errorf(tt.args.err) } - return fmt.Errorf(tt.args.err) - }) - os.Setenv("ENVIRONMENT_NAME", tt.args.env) - if tt.args.dbSecret != "" { - os.Setenv("DB_SECRET", tt.args.dbSecret) + return nil } - t.Run(tt.name, func(t *testing.T) { - if tt.name == "dbCredsInjected True" { - ApplyFunc(GetBool, func(key string) bool { - return true - }) - } + return fmt.Errorf(tt.args.err) + }) +} - tapped := tt.args.tapped +func setEnvironmentVariables(args args) { + os.Setenv("ENVIRONMENT_NAME", args.env) + if args.dbSecret != "" { + os.Setenv("DB_SECRET", args.dbSecret) + } +} - if err := LoadEnv(); (err != nil) != tt.wantErr { - t.Errorf("LoadEnv() error = %v, wantErr %v", err, tt.wantErr) - } - assert.Equal(t, tapped, !tt.args.tapped) - if tt.args.dbSecret != "" { - assert.Equal(t, os.Getenv("PSQL_USER"), username) - assert.Equal(t, os.Getenv("PSQL_HOST"), host) - assert.Equal(t, os.Getenv("PSQL_DBNAME"), dbname) - assert.Equal(t, os.Getenv("PSQL_PASS"), password) - assert.Equal(t, os.Getenv("PSQL_PORT"), port) - } +func testLoadEnv(t *testing.T, tt struct { + name string + wantErr bool + args args +}) { + username := "go_template_role" + host := "localhost" + dbname := "go_template" + password := "go_template_role456" + port := "5432" + if tt.name == "dbCredsInjected True" { + ApplyFunc(GetBool, func(key string) bool { + return true }) } + + tapped := tt.args.tapped + + if err := LoadEnv(); (err != nil) != tt.wantErr { + t.Errorf("LoadEnv() error = %v, wantErr %v", err, tt.wantErr) + } + assert.Equal(t, tapped, !tt.args.tapped) + if tt.args.dbSecret != "" { + assert.Equal(t, os.Getenv("PSQL_USER"), username) + assert.Equal(t, os.Getenv("PSQL_HOST"), host) + assert.Equal(t, os.Getenv("PSQL_DBNAME"), dbname) + assert.Equal(t, os.Getenv("PSQL_PASS"), password) + assert.Equal(t, os.Getenv("PSQL_PORT"), port) + } } diff --git a/internal/middleware/auth/auth_test.go b/internal/middleware/auth/auth_test.go index 8928b8a5..04878461 100644 --- a/internal/middleware/auth/auth_test.go +++ b/internal/middleware/auth/auth_test.go @@ -3,6 +3,7 @@ package auth_test import ( "bytes" "context" + "database/sql" "database/sql/driver" "encoding/json" "fmt" @@ -45,7 +46,28 @@ func (s tokenParserMock) ParseToken(token string) (*jwt.Token, error) { var operationHandlerMock func(ctx context.Context) graphql2.ResponseHandler func TestGraphQLMiddleware(t *testing.T) { - cases := map[string]struct { + // Define test cases + cases := defineTestCases(t) + + // Set up environment + oldDB := setUpEnvironment(t) + defer tearDownEnvironment(oldDB) + + // Run test cases + runTestCases(t, cases) +} + +func defineTestCases(t *testing.T) map[string]struct { + wantStatus int + header string + signMethod string + err string + dbQueries []testutls.QueryData + operationHandler func(ctx context.Context) graphql2.ResponseHandler + tokenParser func(token string) (*jwt.Token, error) + whiteListedQuery bool +} { + return map[string]struct { wantStatus int header string signMethod string @@ -55,140 +77,321 @@ func TestGraphQLMiddleware(t *testing.T) { tokenParser func(token string) (*jwt.Token, error) whiteListedQuery bool }{ - SuccessCase: { - whiteListedQuery: false, - header: "Bearer 123", - wantStatus: http.StatusOK, - err: "", - tokenParser: func(token string) (*jwt.Token, error) { - return testutls.MockJwt("SUPER_ADMIN"), nil - }, - operationHandler: func(ctx context.Context) graphql2.ResponseHandler { - user := ctx.Value(auth.UserCtxKey).(*models.User) - - // add your assertions here - assert.Equal(t, testutls.MockEmail, user.Email.String) - assert.Equal(t, testutls.MockID, user.ID) - assert.Equal(t, testutls.MockToken, user.Token.String) + "SuccessCase": defineSuccessCase(t), + "Success__WhitelistedQuery": defineSuccessWhitelistedQuery(), + "Failure__NoAuthorizationToken": defineFailureNoAuthorizationToken(), + "Failure__InvalidAuthorizationToken": defineFailureInvalidAuthorizationToken(), + "Failure__NotAnAdmin": defineFailureNotAnAdmin(), + "Failure__NoUserWithThatEmail": defineFailureNoUserWithThatEmail(), + } +} - // if you want a custom response you can add it here - var handler = func(ctx context.Context) *graphql2.Response { - return &graphql2.Response{ - Data: json.RawMessage([]byte("{}")), - } - } - return handler - }, - dbQueries: []testutls.QueryData{ - { - Actions: &[]driver.Value{testutls.MockEmail}, - Query: `SELECT "users".* FROM "users" WHERE (email=$1) LIMIT 1`, - DbResponse: sqlmock.NewRows([]string{ - "id", "email", "token", - }).AddRow( - testutls.MockID, - testutls.MockEmail, - testutls.MockToken, - ), - }, - }, +func defineSuccessCase(t *testing.T) struct { + wantStatus int + header string + signMethod string + err string + dbQueries []testutls.QueryData + operationHandler func(ctx context.Context) graphql2.ResponseHandler + tokenParser func(token string) (*jwt.Token, error) + whiteListedQuery bool +} { + return struct { + wantStatus int + header string + signMethod string + err string + dbQueries []testutls.QueryData + operationHandler func(ctx context.Context) graphql2.ResponseHandler + tokenParser func(token string) (*jwt.Token, error) + whiteListedQuery bool + }{ + whiteListedQuery: false, + header: "Bearer 123", + wantStatus: http.StatusOK, + err: "", + tokenParser: func(token string) (*jwt.Token, error) { + return testutls.MockJwt("SUPER_ADMIN"), nil }, - "Success__WhitelistedQuery": { - whiteListedQuery: true, - header: "bearer 123", - wantStatus: http.StatusOK, - err: "", - tokenParser: func(token string) (*jwt.Token, error) { - // even without mocking the database or the token parser the middleware - // doesn't throw an error since it skips all the checks and directly calls next - return nil, nil + operationHandler: defineOperationHandlerSuccessCase(t), + dbQueries: []testutls.QueryData{ + { + Actions: &[]driver.Value{testutls.MockEmail}, + Query: `SELECT "users".* FROM "users" WHERE (email=$1) LIMIT 1`, + DbResponse: sqlmock.NewRows([]string{ + "id", "email", "token", + }).AddRow( + testutls.MockID, + testutls.MockEmail, + testutls.MockToken, + ), }, - operationHandler: func(ctx context.Context) graphql2.ResponseHandler { - var handler = func(ctx context.Context) *graphql2.Response { - return &graphql2.Response{ - Data: json.RawMessage([]byte(`{ "data": { "user": { "id": 1 } } } `)), - } + }, + } +} + +func defineSuccessWhitelistedQuery() struct { + wantStatus int + header string + signMethod string + err string + dbQueries []testutls.QueryData + operationHandler func(ctx context.Context) graphql2.ResponseHandler + tokenParser func(token string) (*jwt.Token, error) + whiteListedQuery bool +} { + return struct { + wantStatus int + header string + signMethod string + err string + dbQueries []testutls.QueryData + operationHandler func(ctx context.Context) graphql2.ResponseHandler + tokenParser func(token string) (*jwt.Token, error) + whiteListedQuery bool + }{ + whiteListedQuery: true, + header: "bearer 123", + wantStatus: http.StatusOK, + err: "", + tokenParser: func(token string) (*jwt.Token, error) { + // even without mocking the database or the token parser the middleware + // doesn't throw an error since it skips all the checks and directly calls next + return nil, nil + }, + operationHandler: func(ctx context.Context) graphql2.ResponseHandler { + var handler = func(ctx context.Context) *graphql2.Response { + return &graphql2.Response{ + Data: json.RawMessage([]byte(`{ "data": { "user": { "id": 1 } } } `)), } - return handler - }, - dbQueries: []testutls.QueryData{}, + } + return handler }, - "Failure__NoAuthorizationToken": { - whiteListedQuery: false, - header: "", - wantStatus: http.StatusOK, - err: "Authorization header is missing", - tokenParser: func(token string) (*jwt.Token, error) { - return nil, fmt.Errorf("token is invalid") - }, - operationHandler: func(ctx context.Context) graphql2.ResponseHandler { - return nil - }, - dbQueries: []testutls.QueryData{}, + dbQueries: []testutls.QueryData{}, + } +} + +func defineFailureNoAuthorizationToken() struct { + wantStatus int + header string + signMethod string + err string + dbQueries []testutls.QueryData + operationHandler func(ctx context.Context) graphql2.ResponseHandler + tokenParser func(token string) (*jwt.Token, error) + whiteListedQuery bool +} { + return struct { + wantStatus int + header string + signMethod string + err string + dbQueries []testutls.QueryData + operationHandler func(ctx context.Context) graphql2.ResponseHandler + tokenParser func(token string) (*jwt.Token, error) + whiteListedQuery bool + }{ + whiteListedQuery: false, + header: "", + wantStatus: http.StatusOK, + err: "Authorization header is missing", + tokenParser: func(token string) (*jwt.Token, error) { + return nil, fmt.Errorf("token is invalid") }, - "Failure__InvalidAuthorizationToken": { - whiteListedQuery: false, - header: "bearer 123", - wantStatus: http.StatusOK, - err: "Invalid authorization token", - tokenParser: func(token string) (*jwt.Token, error) { - return nil, fmt.Errorf("token is invalid") - }, - operationHandler: func(ctx context.Context) graphql2.ResponseHandler { - return nil - }, - dbQueries: []testutls.QueryData{}, + operationHandler: func(ctx context.Context) graphql2.ResponseHandler { + return nil }, - "Failure__NotAnAdmin": { - whiteListedQuery: false, - header: "bearer 123", - wantStatus: http.StatusOK, - err: "Unauthorized! \n Only admins are authorized to make this request.", - tokenParser: func(token string) (*jwt.Token, error) { - return testutls.MockJwt("USER"), nil - }, - operationHandler: func(ctx context.Context) graphql2.ResponseHandler { - return nil - }, - dbQueries: []testutls.QueryData{}, + dbQueries: []testutls.QueryData{}, + } +} + +func defineFailureNotAnAdmin() struct { + wantStatus int + header string + signMethod string + err string + dbQueries []testutls.QueryData + operationHandler func(ctx context.Context) graphql2.ResponseHandler + tokenParser func(token string) (*jwt.Token, error) + whiteListedQuery bool +} { + return struct { + wantStatus int + header string + signMethod string + err string + dbQueries []testutls.QueryData + operationHandler func(ctx context.Context) graphql2.ResponseHandler + tokenParser func(token string) (*jwt.Token, error) + whiteListedQuery bool + }{ + whiteListedQuery: false, + header: "bearer 123", + wantStatus: http.StatusOK, + err: "Unauthorized! \n Only admins are authorized to make this request.", + tokenParser: func(token string) (*jwt.Token, error) { + return testutls.MockJwt("USER"), nil }, - "Failure__NoUserWithThatEmail": { - whiteListedQuery: false, - header: "bearer 123", - wantStatus: http.StatusOK, - err: "No user found for this email address", - tokenParser: func(token string) (*jwt.Token, error) { - return testutls.MockJwt("SUPER_ADMIN"), nil - }, - operationHandler: func(ctx context.Context) graphql2.ResponseHandler { - return nil - }, - dbQueries: []testutls.QueryData{}, + operationHandler: func(ctx context.Context) graphql2.ResponseHandler { + return nil + }, + dbQueries: []testutls.QueryData{}, + } +} + +func defineFailureNoUserWithThatEmail() struct { + wantStatus int + header string + signMethod string + err string + dbQueries []testutls.QueryData + operationHandler func(ctx context.Context) graphql2.ResponseHandler + tokenParser func(token string) (*jwt.Token, error) + whiteListedQuery bool +} { + return struct { + wantStatus int + header string + signMethod string + err string + dbQueries []testutls.QueryData + operationHandler func(ctx context.Context) graphql2.ResponseHandler + tokenParser func(token string) (*jwt.Token, error) + whiteListedQuery bool + }{ + whiteListedQuery: false, + header: "bearer 123", + wantStatus: http.StatusOK, + err: "No user found for this email address", + tokenParser: func(token string) (*jwt.Token, error) { + return testutls.MockJwt("SUPER_ADMIN"), nil + }, + operationHandler: func(ctx context.Context) graphql2.ResponseHandler { + return nil }, + dbQueries: []testutls.QueryData{}, } - oldDB := boil.GetDB() +} + +func defineFailureInvalidAuthorizationToken() struct { + wantStatus int + header string + signMethod string + err string + dbQueries []testutls.QueryData + operationHandler func(ctx context.Context) graphql2.ResponseHandler + tokenParser func(token string) (*jwt.Token, error) + whiteListedQuery bool +} { + return struct { + wantStatus int + header string + signMethod string + err string + dbQueries []testutls.QueryData + operationHandler func(ctx context.Context) graphql2.ResponseHandler + tokenParser func(token string) (*jwt.Token, error) + whiteListedQuery bool + }{ + whiteListedQuery: false, + header: "bearer 123", + wantStatus: http.StatusOK, + err: "Invalid authorization token", + tokenParser: func(token string) (*jwt.Token, error) { + return nil, fmt.Errorf("token is invalid") + }, + operationHandler: func(ctx context.Context) graphql2.ResponseHandler { + return nil + }, + dbQueries: []testutls.QueryData{}, + } +} +func defineOperationHandlerSuccessCase(t *testing.T) func(ctx context.Context) graphql2.ResponseHandler { + return func(ctx context.Context) graphql2.ResponseHandler { + user := ctx.Value(auth.UserCtxKey).(*models.User) + + // Add your assertions here + assert.Equal(t, testutls.MockEmail, user.Email.String) + assert.Equal(t, testutls.MockID, user.ID) + assert.Equal(t, testutls.MockToken, user.Token.String) + + // If you want a custom response you can add it here + var handler = func(ctx context.Context) *graphql2.Response { + return &graphql2.Response{ + Data: json.RawMessage([]byte("{}")), + } + } + return handler + } +} + +func setUpEnvironment(t *testing.T) *sql.DB { err := config.LoadEnvWithFilePrefix(convert.StringToPointerString("./../../../")) if err != nil { log.Fatal(err) } - mock, db, _ := testutls.SetupMockDB(t) + _, db, _ := testutls.SetupMockDB(t) + return db +} + +func tearDownEnvironment(db *sql.DB) { + boil.SetDB(db) + db.Close() +} + +func runTestCases(t *testing.T, cases map[string]struct { + wantStatus int + header string + signMethod string + err string + dbQueries []testutls.QueryData + operationHandler func(ctx context.Context) graphql2.ResponseHandler + tokenParser func(token string) (*jwt.Token, error) + whiteListedQuery bool +}) { for name, tt := range cases { t.Run(name, func(t *testing.T) { - for _, dbQuery := range tt.dbQueries { - mock.ExpectQuery(regexp.QuoteMeta(dbQuery.Query)). - WithArgs(*dbQuery.Actions...). - WillReturnRows(dbQuery.DbResponse) - } - requestQuery := testutls.MockQuery - if tt.whiteListedQuery { - requestQuery = testutls.MockWhitelistedQuery - } - makeRequest(t, requestQuery, tt) + runSingleTestCase(t, tt) }) } - boil.SetDB(oldDB) - db.Close() } + +func runSingleTestCase(t *testing.T, tt struct { + wantStatus int + header string + signMethod string + err string + dbQueries []testutls.QueryData + operationHandler func(ctx context.Context) graphql2.ResponseHandler + tokenParser func(token string) (*jwt.Token, error) + whiteListedQuery bool +}) { + // Set up mock queries + mock := setupMockQueries(t, tt.dbQueries) + + // Determine request query + requestQuery := testutls.MockQuery + if tt.whiteListedQuery { + requestQuery = testutls.MockWhitelistedQuery + } + + // Make request + makeRequest(t, requestQuery, tt) + + // Ensure mock expectations are met + _ = mock.ExpectationsWereMet() +} + +func setupMockQueries(t *testing.T, dbQueries []testutls.QueryData) sqlmock.Sqlmock { + mock, _, _ := testutls.SetupMockDB(t) + for _, dbQuery := range dbQueries { + mock.ExpectQuery(regexp.QuoteMeta(dbQuery.Query)). + WithArgs(*dbQuery.Actions...). + WillReturnRows(dbQuery.DbResponse) + } + return mock +} + func makeRequest(t *testing.T, requestQuery string, tt struct { wantStatus int header string @@ -226,7 +429,6 @@ func makeRequest(t *testing.T, requestQuery string, tt struct { ts := httptest.NewServer(e) path := ts.URL + pathName defer ts.Close() - req, _ := http.NewRequest( "POST", path, @@ -246,7 +448,6 @@ func makeRequest(t *testing.T, requestQuery string, tt struct { } var jsonRes graphql2.Response err = json.Unmarshal(bodyBytes, &jsonRes) - if err != nil { log.Fatal(err) } diff --git a/internal/server/error_test.go b/internal/server/error_test.go index d95eb384..2616bcd9 100644 --- a/internal/server/error_test.go +++ b/internal/server/error_test.go @@ -77,6 +77,35 @@ func getValidatorErr(t *testing.T) error { }).AnyTimes() return validator.ValidationErrors{fieldError} } +func setupMockContext(t *testing.T, req *http.Request, expectedStatusCode int, httpMethod string) *testutls.MockContext { + ctrl := gomock.NewController(t) + ctx := testutls.NewMockContext(ctrl) + + // Mock ctx.Response + ctx.EXPECT().Response().DoAndReturn(func() *echo.Response { + return &echo.Response{Status: expectedStatusCode} + }).AnyTimes() + + // Mock ctx.Request + ctx.EXPECT().Request().DoAndReturn(func() *http.Request { + return req + }).AnyTimes() + + if httpMethod == "HEAD" { + // Mock ctx.NoContent + ctx.EXPECT().NoContent(gomock.Eq(expectedStatusCode)).DoAndReturn(func(code int) error { + return nil + }).AnyTimes() + } else { + // Mock ctx.JSON + ctx.EXPECT().JSON(gomock.Eq(expectedStatusCode), gomock.Any()).DoAndReturn(func(code int, i interface{}) error { + return fmt.Errorf("error") + }).AnyTimes() + } + + return ctx +} + func TestCustomErrHandlerHandler(t *testing.T) { type args struct { err error @@ -85,7 +114,6 @@ func TestCustomErrHandlerHandler(t *testing.T) { } e := echo.New() custErr := &customErrHandler{e: e} - tests := []struct { name string args args @@ -125,49 +153,11 @@ func TestCustomErrHandlerHandler(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - // just make a request - req, _ := http.NewRequest( - tt.args.httpMethod, - "/", - bytes.NewBuffer([]byte("")), - ) - ctx := testutls.NewMockContext(gomock.NewController(t)) - // mock ctx.Response - ctx. - EXPECT(). - Response(). - DoAndReturn(func() *echo.Response { - return &echo.Response{Status: tt.args.expectedStatusCode} - }). - AnyTimes() - // mock ctx.Request - ctx. - EXPECT(). - Request(). - DoAndReturn(func() *http.Request { - return req - }). - AnyTimes() - if tt.args.httpMethod == "HEAD" { - // mock ctx.NoContent - ctx. - EXPECT(). - NoContent(gomock.Eq(tt.args.expectedStatusCode)). - DoAndReturn(func(code int) error { - return nil - }). - AnyTimes() - } else { - // mock ctx.JSON - ctx. - EXPECT(). - JSON(gomock.Eq(tt.args.expectedStatusCode), gomock.Any()). - DoAndReturn(func(code int, i interface{}) error { - return fmt.Errorf("error") - }). - AnyTimes() - } - // call the handler with tt.args.err. We are asserting in the JSON/NoContent call + // Just make a request + req, _ := http.NewRequest(tt.args.httpMethod, "/", bytes.NewBuffer([]byte(""))) + ctx := setupMockContext(t, req, tt.args.expectedStatusCode, tt.args.httpMethod) + + // Call the handler with tt.args.err. We are asserting in the JSON/NoContent call custErr.handler(tt.args.err, ctx) }) } diff --git a/internal/server/server_test.go b/internal/server/server_test.go index ec190c32..f51a6f44 100644 --- a/internal/server/server_test.go +++ b/internal/server/server_test.go @@ -63,9 +63,25 @@ func initValues(startServer func(e *echo.Echo, s *http.Server) error) args { } } func TestStart(t *testing.T) { - cases := map[string]struct { - args args - }{ + cases := getTestCases() + + for name, tt := range cases { + t.Run(name, func(t *testing.T) { + mockStartServer(tt.args) + mockShutdownIfNeeded(tt.args) + startServerAndInterrupt(tt.args) + waitForServerShutdownIfNeeded(tt.args) + assertions(t, tt.args) + }) + } +} + +type testCase struct { + args args +} + +func getTestCases() map[string]testCase { + return map[string]testCase{ "Success": { args: initValues(func(e *echo.Echo, s *http.Server) (err error) { return nil @@ -82,47 +98,61 @@ func TestStart(t *testing.T) { }), }, } - for name, tt := range cases { - t.Run(name, func(t *testing.T) { - ApplyMethod(reflect.TypeOf(tt.args.e), "StartServer", func(e *echo.Echo, s *http.Server) (err error) { - err = tt.args.startServer(e, s) - tt.args.startServerCalled = true - return err - }) - if tt.args.shutDownFailed { - ApplyMethod(reflect.TypeOf(tt.args.e), "Shutdown", func(e *echo.Echo, ctx context.Context) (err error) { - return fmt.Errorf("error shutting down") - }) - ApplyMethod( - reflect.TypeOf(tt.args.e.StdLogger), "Fatal", - func(l *log.Logger, i ...interface{}) { - tt.args.serverShutDownCalled = true - }) - } - go func() { - time.Sleep(200 * time.Millisecond) - proc, err := os.FindProcess(os.Getpid()) - if err != nil { - log.Fatal(err) - } - sigc := make(chan os.Signal, 1) - signal.Notify(sigc, os.Interrupt) - go func() { - <-sigc - signal.Stop(sigc) - }() - err = proc.Signal(os.Interrupt) - if err != nil { - log.Fatal("errror") - } - time.Sleep(1 * time.Second) - }() - server.Start(tt.args.e, tt.args.cfg) - time.Sleep(400 * time.Millisecond) - assert.Equal(t, tt.args.startServerCalled, true) - if tt.args.shutDownFailed { - assert.Equal(t, tt.args.serverShutDownCalled, true) - } +} + +func mockStartServer(args args) { + ApplyMethod(reflect.TypeOf(args.e), "StartServer", func(e *echo.Echo, s *http.Server) (err error) { + err = args.startServer(e, s) + args.startServerCalled = true + return err + }) +} + +func mockShutdownIfNeeded(args args) { + if args.shutDownFailed { + ApplyMethod(reflect.TypeOf(args.e), "Shutdown", func(e *echo.Echo, ctx context.Context) (err error) { + return fmt.Errorf("error shutting down") }) + ApplyMethod( + reflect.TypeOf(args.e.StdLogger), "Fatal", + func(l *log.Logger, i ...interface{}) { + args.serverShutDownCalled = true + }) + } +} + +func startServerAndInterrupt(args args) { + go func() { + time.Sleep(200 * time.Millisecond) + proc, err := os.FindProcess(os.Getpid()) + if err != nil { + log.Fatal(err) + } + sigc := make(chan os.Signal, 1) + signal.Notify(sigc, os.Interrupt) + go func() { + <-sigc + signal.Stop(sigc) + }() + err = proc.Signal(os.Interrupt) + if err != nil { + log.Fatal("error") + } + time.Sleep(1 * time.Second) + }() + server.Start(args.e, args.cfg) + time.Sleep(400 * time.Millisecond) +} + +func waitForServerShutdownIfNeeded(args args) { + if args.shutDownFailed { + time.Sleep(400 * time.Millisecond) // Adjust time according to your needs + } +} + +func assertions(t *testing.T, args args) { + assert.Equal(t, args.startServerCalled, true) + if args.shutDownFailed { + assert.Equal(t, args.serverShutDownCalled, true) } } diff --git a/pkg/api/api.go b/pkg/api/api.go index 2a4a8412..1bb455e2 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -1,4 +1,3 @@ -// Package api Go-Template package api import ( @@ -31,13 +30,15 @@ import ( // Start starts the API service func Start(cfg *config.Configuration) (*echo.Echo, error) { - db, err := postgres.Connect() - if err != nil { + // Initialize Echo instance + e := server.New() + + // Set up database connection + if err := setupDatabase(); err != nil { return nil, err } - boil.SetDB(db) - + // Set up JWT jwt, err := jwt.New( cfg.JWT.SigningAlgorithm, os.Getenv("JWT_SECRET"), @@ -46,42 +47,19 @@ func Start(cfg *config.Configuration) (*echo.Echo, error) { if err != nil { return nil, err } + if err != nil { + return nil, err + } - e := server.New() - - gqlMiddleware := authMw.GqlMiddleware() - // throttlerMiddleware puts the current user's IP address into context of gqlgen - throttlerMiddleware := throttle.GqlMiddleware() - - graphQLPathname := "/graphql" - playgroundHandler := playground.Handler("GraphQL playground", graphQLPathname) - + // Set up GraphQL observers := map[string]chan *graphql.User{} graphqlHandler := handler.New(graphql.NewExecutableSchema(graphql.Config{ Resolvers: &resolver.Resolver{Observers: observers}, })) - if os.Getenv("ENVIRONMENT_NAME") == "local" { - boil.DebugMode = true - } - - // graphql apis graphqlHandler.AroundOperations(func(ctx context.Context, next graphql2.OperationHandler) graphql2.ResponseHandler { return authMw.GraphQLMiddleware(ctx, jwt, next) }) - e.POST(graphQLPathname, func(c echo.Context) error { - req := c.Request() - res := c.Response() - graphqlHandler.ServeHTTP(res, req) - return nil - }, gqlMiddleware, throttlerMiddleware) - - e.GET(graphQLPathname, func(c echo.Context) error { - req := c.Request() - res := c.Response() - graphqlHandler.ServeHTTP(res, req) - return nil - }, gqlMiddleware, throttlerMiddleware) graphqlHandler.AddTransport(transport.Websocket{ KeepAlivePingInterval: 10 * time.Second, @@ -91,31 +69,72 @@ func Start(cfg *config.Configuration) (*echo.Echo, error) { }, }, }) - graphqlHandler.AddTransport(transport.Options{}) graphqlHandler.AddTransport(transport.GET{}) graphqlHandler.AddTransport(transport.POST{}) graphqlHandler.AddTransport(transport.MultipartForm{}) - graphqlHandler.SetQueryCache(lru.New(1000)) - graphqlHandler.Use(extension.Introspection{}) graphqlHandler.Use(extension.AutomaticPersistedQuery{ Cache: lru.New(100), }) + // Set up GraphQL endpoints + setupGraphQLEndpoints(e, graphqlHandler) - // graphql playground - e.GET("/playground", func(c echo.Context) error { - req := c.Request() - res := c.Response() - playgroundHandler.ServeHTTP(res, req) - return nil - }) + // Set up GraphQL playground + setupGraphQLPlayground(e) + + // Start the server server.Start(e, &server.Config{ Port: cfg.Server.Port, ReadTimeoutSeconds: cfg.Server.ReadTimeout, WriteTimeoutSeconds: cfg.Server.WriteTimeout, Debug: cfg.Server.Debug, }) + return e, nil } + +func setupDatabase() error { + db, err := postgres.Connect() + if err != nil { + return err + } + boil.SetDB(db) + if os.Getenv("ENVIRONMENT_NAME") == "local" { + boil.DebugMode = true + } + return nil +} + +func setupGraphQLEndpoints(e *echo.Echo, graphqlHandler *handler.Server) { + graphQLPathname := "/graphql" + gqlMiddleware := authMw.GqlMiddleware() + throttlerMiddleware := throttle.GqlMiddleware() + + e.POST(graphQLPathname, func(c echo.Context) error { + req := c.Request() + res := c.Response() + graphqlHandler.ServeHTTP(res, req) + return nil + }, gqlMiddleware, throttlerMiddleware) + + e.GET(graphQLPathname, func(c echo.Context) error { + req := c.Request() + res := c.Response() + graphqlHandler.ServeHTTP(res, req) + return nil + }, gqlMiddleware, throttlerMiddleware) +} + +func setupGraphQLPlayground(e *echo.Echo) { + graphQLPathname := "/graphql" + playgroundHandler := playground.Handler("GraphQL playground", graphQLPathname) + + e.GET("/playground", func(c echo.Context) error { + req := c.Request() + res := c.Response() + playgroundHandler.ServeHTTP(res, req) + return nil + }) +} diff --git a/pkg/api/api_test.go b/pkg/api/api_test.go index ccea762e..7b4397f4 100644 --- a/pkg/api/api_test.go +++ b/pkg/api/api_test.go @@ -6,7 +6,6 @@ import ( "database/sql" "fmt" "io" - "log" "net/http" "net/http/httptest" "os" @@ -24,6 +23,7 @@ import ( graphql2 "github.com/99designs/gqlgen/graphql" "github.com/99designs/gqlgen/graphql/handler" "github.com/99designs/gqlgen/graphql/handler/transport" + "github.com/agiledragon/gomonkey/v2" . "github.com/agiledragon/gomonkey/v2" "github.com/gorilla/websocket" "github.com/labstack/echo/v4" @@ -34,21 +34,44 @@ import ( var graphQLPathname = "/graphql" +type args struct { + cfg *config.Configuration +} +type testCases struct { + name string + args args + wantErr bool + setDbCalled bool + getTransportCalled bool + postTransportCalled bool + optionsTransportCalled bool + multipartFormTransportCalled bool + websocketTransportCalled bool +} + func TestStart(t *testing.T) { - type args struct { - cfg *config.Configuration + tests := initializeTestCases() + + patches := applyPatches() + defer patches.Reset() + + mockEchoServer, _ := prepareMocks() + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + setupMockFunctions() + + if hasTransportCalls(tt) { + checkTransportCalls(tt) + } else { + checkGraphQLServer(t, tt, mockEchoServer) + } + }) } - tests := []struct { - name string - args args - wantErr bool - setDbCalled bool - getTransportCalled bool - postTransportCalled bool - optionsTransportCalled bool - multipartFormTransportCalled bool - websocketTransportCalled bool - }{ +} + +func initializeTestCases() []testCases { + return []testCases{ { name: "Success", args: args{ @@ -69,123 +92,156 @@ func TestStart(t *testing.T) { websocketTransportCalled: false, }, } - patches := ApplyFunc(os.Getenv, func(key string) (value string) { - if key == "JWT_SECRET" { - return testutls.MockJWTSecret - } - return "" - }) - defer patches.Reset() - ApplyFunc(sql.Open, func(driverName string, dataSourceName string) (*sql.DB, error) { - fmt.Print("sql.Open called\n") - return nil, nil - }) - ApplyFunc(server.Start, func(e *echo.Echo, cfg *server.Config) { - fmt.Print("Fake server started\n") - }) +} + +func applyPatches() *gomonkey.Patches { + return ApplyFunc(os.Getenv, mockGetenv). + ApplyFunc(sql.Open, mockSqlOpen). + ApplyFunc(server.Start, mockServerStart). + ApplyFunc(server.New, mockServerNew) +} + +func mockGetenv(key string) string { + if key == "JWT_SECRET" { + return testutls.MockJWTSecret + } + return "" +} + +func mockSqlOpen(driverName string, dataSourceName string) (*sql.DB, error) { + fmt.Print("sql.Open called\n") + return nil, nil +} + +func mockServerStart(e *echo.Echo, cfg *server.Config) { + fmt.Print("Fake server started\n") +} + +func mockServerNew() *echo.Echo { + return echo.New() +} + +func prepareMocks() (*echo.Echo, *handler.Server) { e := echo.New() - ApplyFunc(server.New, func() *echo.Echo { - return e - }) + graphqlHandler := handler.New(graphql.NewExecutableSchema(graphql.Config{ + Resolvers: &resolver.Resolver{Observers: make(map[string]chan *graphql.User)}, + })) + return e, graphqlHandler +} + +func setupMockFunctions() { + ApplyFunc(boil.SetDB, mockSetDB) +} + +func mockSetDB(db boil.Executor, tt testCases) { + fmt.Print("boil.SetDB called\n") + tt.setDbCalled = true +} + +func hasTransportCalls(tt testCases) bool { + return tt.getTransportCalled || tt.postTransportCalled || + tt.optionsTransportCalled || tt.multipartFormTransportCalled +} + +func checkTransportCalls(tt testCases) { observers := map[string]chan *graphql.User{} graphqlHandler := handler.New(graphql.NewExecutableSchema(graphql.Config{ Resolvers: &resolver.Resolver{Observers: observers}, })) - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - ApplyFunc(boil.SetDB, func(db boil.Executor) { - fmt.Print("boil.SetDB called\n") - tt.setDbCalled = true - }) - if tt.getTransportCalled || tt.postTransportCalled || - tt.optionsTransportCalled || tt.multipartFormTransportCalled { - ApplyMethod(reflect.TypeOf(graphqlHandler), "AddTransport", func(s *handler.Server, t graphql2.Transport) { - transportGET := transport.GET{} - transportMultipartForm := transport.MultipartForm{} - transportPOST := transport.POST{} - transportWebsocket := transport.Websocket{ - KeepAlivePingInterval: 10 * time.Second, - InitFunc: func(ctx context.Context, initPayload transport.InitPayload) (context.Context, error) { - return ctx, nil - }, - Upgrader: websocket.Upgrader{ - CheckOrigin: func(r *http.Request) bool { - return true - }, - }, - } - if t == transportGET { - tt.getTransportCalled = true - } - if t == transportMultipartForm { - tt.multipartFormTransportCalled = true - } - if t == transportPOST { - tt.postTransportCalled = true - } - if reflect.TypeOf(t) == reflect.TypeOf(transportWebsocket) { - tt.websocketTransportCalled = true - } - }) - _, err := Start(tt.args.cfg) - if err != nil != tt.wantErr { - t.Errorf("Start() error = %v, wantErr %v", err, tt.wantErr) - } - assert.Equal(t, tt.getTransportCalled, true) - assert.Equal(t, tt.multipartFormTransportCalled, true) - assert.Equal(t, tt.postTransportCalled, true) - assert.Equal(t, tt.websocketTransportCalled, true) - } else { - _, err := Start(tt.args.cfg) - if err != nil != tt.wantErr { - t.Errorf("Start() error = %v, wantErr %v", err, tt.wantErr) - } - jsonRes, err := testutls.MakeRequest(testutls.RequestParameters{ - E: e, - Pathname: graphQLPathname, - HttpMethod: "POST", - RequestBody: testutls.MockWhitelistedQuery, - IsGraphQL: false, - }) - if err != nil { - log.Fatal(err) - } - assert.Equal(t, tt.setDbCalled, true) - // check if it returns schema correctly - assert.NotNil(t, jsonRes["data"].(map[string]interface{})["__schema"]) - _, res, err := testutls.SimpleMakeRequest(testutls.RequestParameters{ - E: e, - Pathname: "/playground", - HttpMethod: "GET", - - IsGraphQL: false, - }) - if err != nil { - log.Fatal(err) - } - bodyBytes, _ := io.ReadAll(res.Body) - // check if the playground is returned - assert.Contains(t, string(bodyBytes), "GraphiQL.createFetcher") - ts := httptest.NewServer(e) - u := "ws" + strings.TrimPrefix(ts.URL+graphQLPathname, "http") - // Connect to the server - fmt.Print(u) - ws, _, err := websocket.DefaultDialer.Dial(u, nil) - if err != nil { - t.Fatalf("%v", err) - } - defer ws.Close() - if err := ws.WriteMessage(websocket.TextMessage, []byte(`{"type":"connection_init","payload":`+ - `{"authorization":"bearer ABC"}}`)); err != nil { - t.Fatalf("%v", err) - } - _, p, err := ws.ReadMessage() - if err != nil { - t.Fatalf("%v", err) - } - // check if the playground is returned - assert.Contains(t, string(p), "{\"type\":\"connection_ack\"}\n") + if tt.getTransportCalled || tt.postTransportCalled || + tt.optionsTransportCalled || tt.multipartFormTransportCalled { + ApplyMethod(reflect.TypeOf(graphqlHandler), "AddTransport", func(s *handler.Server, t graphql2.Transport) { + transportGET := transport.GET{} + transportMultipartForm := transport.MultipartForm{} + transportPOST := transport.POST{} + transportWebsocket := transport.Websocket{ + KeepAlivePingInterval: 10 * time.Second, + InitFunc: func(ctx context.Context, initPayload transport.InitPayload) (context.Context, error) { + return ctx, nil + }, + Upgrader: websocket.Upgrader{ + CheckOrigin: func(r *http.Request) bool { + return true + }, + }, + } + if t == transportGET { + tt.getTransportCalled = true + } + if t == transportMultipartForm { + tt.multipartFormTransportCalled = true + } + if t == transportPOST { + tt.postTransportCalled = true + } + if reflect.TypeOf(t) == reflect.TypeOf(transportWebsocket) { + tt.websocketTransportCalled = true } }) } } +func checkGraphQLServer(t *testing.T, tt testCases, e *echo.Echo) { + jsonRes, err := testutls.MakeRequest(testutls.RequestParameters{ + E: e, + Pathname: graphQLPathname, + HttpMethod: "POST", + RequestBody: testutls.MockWhitelistedQuery, + IsGraphQL: false, + }) + if err != nil { + t.Fatalf("Failed to make request to GraphQL server: %v", err) + } + + // Assert that database was set + assert.True(t, tt.setDbCalled, "Expected database to be set") + + // Assert GraphQL schema is returned + assert.NotNil(t, jsonRes["data"].(map[string]interface{})["__schema"], + "Expected GraphQL schema to be returned") + + // Simulate request to the GraphQL playground + _, res, err := testutls.SimpleMakeRequest(testutls.RequestParameters{ + E: e, + Pathname: "/playground", + HttpMethod: "GET", + IsGraphQL: false, + }) + if err != nil { + t.Fatalf("Failed to make request to GraphQL playground: %v", err) + } + + bodyBytes, err := io.ReadAll(res.Body) + if err != nil { + t.Fatalf("Failed to read response body: %v", err) + } + + // Assert that GraphQL playground is returned + assert.Contains(t, string(bodyBytes), "GraphiQL.createFetcher", + "Expected GraphQL playground to be returned") + + // Connect to the WebSocket endpoint + ts := httptest.NewServer(e) + defer ts.Close() + u := "ws" + strings.TrimPrefix(ts.URL+graphQLPathname, "http") + ws, _, err := websocket.DefaultDialer.Dial(u, nil) + if err != nil { + t.Fatalf("Failed to connect to WebSocket: %v", err) + } + defer ws.Close() + + // Send connection initiation message + if err := ws.WriteMessage(websocket.TextMessage, []byte(`{"type":"connection_init","payload":`+ + `{"authorization":"bearer ABC"}}`)); err != nil { + t.Fatalf("Failed to send connection initiation message: %v", err) + } + + // Read response from WebSocket + _, p, err := ws.ReadMessage() + if err != nil { + t.Fatalf("Failed to read WebSocket message: %v", err) + } + + // Assert that connection acknowledgement is received + assert.Contains(t, string(p), "{\"type\":\"connection_ack\"}\n", + "Expected connection acknowledgement from WebSocket") +} diff --git a/pkg/utl/rediscache/redis_test.go b/pkg/utl/rediscache/redis_test.go index 76141a26..fb8ee8f0 100644 --- a/pkg/utl/rediscache/redis_test.go +++ b/pkg/utl/rediscache/redis_test.go @@ -95,7 +95,6 @@ func TestSetKeyValue(t *testing.T) { ApplyFunc(redigo.Dial, func(string, string, ...redis.DialOption) (redis.Conn, error) { return redigoConn, nil }) - for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { var patches *Patches @@ -112,7 +111,6 @@ func TestSetKeyValue(t *testing.T) { defer patchJson.Reset() } redigoConn.Command("SET", tt.args.key, string(b)).Expect("something") - if err := SetKeyValue(tt.args.key, tt.args.data); (err != nil) != tt.wantErr { t.Errorf("SetKeyValue() error = %v, wantErr %v", err, tt.wantErr) } diff --git a/pkg/utl/rediscache/service_test.go b/pkg/utl/rediscache/service_test.go index 8b49cda9..e12cb6c9 100644 --- a/pkg/utl/rediscache/service_test.go +++ b/pkg/utl/rediscache/service_test.go @@ -418,11 +418,33 @@ func TestIncVisits(t *testing.T) { } } +type args struct { + path string +} + func TestStartVisits(t *testing.T) { - type args struct { - path string + tests := getTestCases() + + for _, tt := range tests { + mockDependencies(tt.name) + + t.Run(tt.name, func(t *testing.T) { + expectRedisCommand(tt.args.path, tt.want) + err := StartVisits(tt.args.path, time.Second) + + verifyError(t, err, tt.wantErr) + }) } - tests := []struct { +} + +func getTestCases() []struct { + name string + args args + want int + wantErr bool + errMsg error +} { + return []struct { name string args args want int @@ -453,37 +475,29 @@ func TestStartVisits(t *testing.T) { errMsg: fmt.Errorf(ErrMsgFromRedisDial), }, } - ApplyFunc(redisDial, func() (redis.Conn, error) { - return conn, nil - }) - err := config.LoadEnvWithFilePrefix(convert.StringToPointerString("./../")) - if err != nil { - t.Log(err) - } +} - for _, tt := range tests { - if tt.name == ErrorRedisDial { - patch := gomonkey.ApplyFunc(redisDial, func() (redigo.Conn, error) { - return nil, fmt.Errorf(ErrMsgFromRedisDial) +func mockDependencies(name string) { + if name == ErrorRedisDial { + patch := gomonkey.ApplyFunc(redisDial, func() (redigo.Conn, error) { + return nil, fmt.Errorf(ErrMsgFromRedisDial) + }) + defer patch.Reset() + } else if name == ErrorConnDo { + patch := gomonkey.ApplyMethodFunc(redigomock.NewConn(), "Do", + func(commandName string, args ...interface{}) (reply interface{}, err error) { + return nil, fmt.Errorf(ErrMsgFromConnDo) }) - defer patch.Reset() - } + defer patch.Reset() + } +} - t.Run(tt.name, func(t *testing.T) { - if tt.name == ErrorConnDo { - patch := gomonkey.ApplyMethodFunc(redigomock.NewConn(), "Do", - func(commandName string, args ...interface{}) (reply interface{}, err error) { - return nil, fmt.Errorf(ErrMsgFromConnDo) - }) - defer patch.Reset() - } - conn.Command("SETEX", tt.args.path, int(math.Ceil(time.Second.Seconds())), 1).Expect(1) - err := StartVisits(tt.args.path, time.Second) +func expectRedisCommand(path string, want int) { + conn.Command("SETEX", path, int(math.Ceil(time.Second.Seconds())), 1).Expect(want) +} - if (err != nil) != tt.wantErr { - t.Errorf("StartVisits() error = %v, wantErr %v", err, tt.wantErr) - return - } - }) +func verifyError(t *testing.T, err error, wantErr bool) { + if (err != nil) != wantErr { + t.Errorf("StartVisits() error = %v, wantErr %v", err, wantErr) } } diff --git a/pkg/utl/resultwrapper/error_test.go b/pkg/utl/resultwrapper/error_test.go index eccf3f5a..c387562a 100644 --- a/pkg/utl/resultwrapper/error_test.go +++ b/pkg/utl/resultwrapper/error_test.go @@ -530,11 +530,12 @@ func TestHandleGraphQLError(t *testing.T) { } } +type args struct { + err error + detail string +} + func TestResolverSQLError(t *testing.T) { - type args struct { - err error - detail string - } tests := []struct { name string args args diff --git a/resolver/user_mutations.resolvers_test.go b/resolver/user_mutations.resolvers_test.go index e9da79da..5b01e170 100644 --- a/resolver/user_mutations.resolvers_test.go +++ b/resolver/user_mutations.resolvers_test.go @@ -209,7 +209,6 @@ func TestUpdateUser( wantErr: false, }, } - resolver1 := resolver.Resolver{} for _, tt := range cases { t.Run( @@ -233,18 +232,14 @@ func TestUpdateUser( boil.SetDB(oldDB) }() boil.SetDB(db) - if tt.name == ErrorFindingUser { mock.ExpectQuery(regexp.QuoteMeta(`UPDATE "users"`)).WithArgs().WillReturnError(fmt.Errorf("")) } - rows := sqlmock.NewRows([]string{"first_name"}).AddRow(testutls.MockUser().FirstName) mock.ExpectQuery(regexp.QuoteMeta(`select * from "users"`)).WithArgs(0).WillReturnRows(rows) - // update users with new information result := driver.Result(driver.RowsAffected(1)) mock.ExpectExec(regexp.QuoteMeta(`UPDATE "users"`)).WillReturnResult(result) - c := context.Background() ctx := context.WithValue(c, testutls.UserKey, testutls.MockUser()) response, err := resolver1.Mutation().UpdateUser(ctx, tt.req) @@ -282,7 +277,6 @@ func TestDeleteUser( wantErr: false, }, } - resolver1 := resolver.Resolver{} for _, tt := range cases { t.Run( @@ -295,7 +289,6 @@ func TestDeleteUser( }) defer patch.Reset() } - err := godotenv.Load( "../.env.local", ) @@ -312,7 +305,6 @@ func TestDeleteUser( boil.SetDB(oldDB) }() boil.SetDB(db) - if tt.name == ErrorFindingUser { mock.ExpectQuery(regexp.QuoteMeta(`select * from "users" where "id"=$1`)). WithArgs(). @@ -328,7 +320,6 @@ func TestDeleteUser( result := driver.Result(driver.RowsAffected(1)) mock.ExpectExec(regexp.QuoteMeta(`DELETE FROM "users" WHERE "id"=$1`)). WillReturnResult(result) - c := context.Background() ctx := context.WithValue(c, testutls.UserKey, testutls.MockUser()) response, err := resolver1.Mutation(). From b2ec3592553d267ac61c97c0c4055fee38658051 Mon Sep 17 00:00:00 2001 From: HIMANSHU Date: Sun, 24 Mar 2024 12:24:02 +0530 Subject: [PATCH 07/39] Feat: Funlen Error resolves --- internal/jwt/jwt_test.go | 15 +- pkg/utl/throttle/throttler_test.go | 179 +++++++----- resolver/user_mutations.resolvers_test.go | 31 ++- resolver/user_queries.resolvers_test.go | 316 ++++++++++++++-------- 4 files changed, 343 insertions(+), 198 deletions(-) diff --git a/internal/jwt/jwt_test.go b/internal/jwt/jwt_test.go index 0f842e64..586b87c8 100644 --- a/internal/jwt/jwt_test.go +++ b/internal/jwt/jwt_test.go @@ -74,8 +74,15 @@ func TestNew(t *testing.T) { }) } } - -func TestGenerateToken(t *testing.T) { +func GetTokenTestCases() map[string]struct { + algo string + secret string + minSecretLen int + req models.User + wantErr bool + want string + RoleErr bool +} { cases := map[string]struct { algo string secret string @@ -127,6 +134,10 @@ func TestGenerateToken(t *testing.T) { RoleErr: true, }, } + return cases +} +func TestGenerateToken(t *testing.T) { + cases := GetTokenTestCases() err := config.LoadEnvWithFilePrefix(convert.StringToPointerString("./../../")) if err != nil { log.Fatal(err) diff --git a/pkg/utl/throttle/throttler_test.go b/pkg/utl/throttle/throttler_test.go index e76abe65..eca31cf2 100644 --- a/pkg/utl/throttle/throttler_test.go +++ b/pkg/utl/throttle/throttler_test.go @@ -19,88 +19,119 @@ import ( "github.com/vektah/gqlparser/v2/ast" ) -func TestCheck(t *testing.T) { - type args struct { - ctx context.Context - limit int - dur time.Duration - isLocal bool - visits int - visitsErr error - startVisitsErr error - ip string +type args struct { + ctx context.Context + limit int + dur time.Duration + isLocal bool + visits int + visitsErr error + startVisitsErr error + ip string +} + +type testCase struct { + name string + args args + wantErr bool +} + +// CreateTestCases creates and returns test cases. +func CreateTestCases(ctx context.Context) []testCase { + return []testCase{ + createSuccessLocalTestCase(ctx), + createSuccessNotLocalFirstVisitTestCase(ctx), + createSuccessNotLocalSecondVisitTestCase(ctx), + createFailureNotLocalFirstVisitTestCase(ctx), + createFailureNotLocalFirstVisitStartVisitErrTestCase(ctx), + createFailureNotLocalRateLimitExceededTestCase(ctx), } - var ctx context.Context = testutls.MockCtx{} - tests := []struct { - name string - args args - wantErr bool - }{ - { - name: "Success_Local", - args: args{ - ctx: ctx, - limit: 10, - dur: time.Second, - isLocal: true, - }, +} + +func createSuccessLocalTestCase(ctx context.Context) testCase { + return testCase{ + name: "Success_Local", + args: args{ + ctx: ctx, + limit: 10, + dur: time.Second, + isLocal: true, }, - { - name: "Success_NotLocal_FirstVisit", - args: args{ - ctx: ctx, - limit: 10, - visits: 1, - dur: time.Second, - ip: testutls.MockIpAddress, - }, + } +} + +func createSuccessNotLocalFirstVisitTestCase(ctx context.Context) testCase { + return testCase{ + name: "Success_NotLocal_FirstVisit", + args: args{ + ctx: ctx, + limit: 10, + visits: 1, + dur: time.Second, + ip: "mock IP address", }, - { - name: "Success_NotLocal_SecondVisit", - args: args{ - ctx: ctx, - limit: 10, - visits: 2, - dur: time.Second, - ip: testutls.MockIpAddress, - }, + } +} + +func createSuccessNotLocalSecondVisitTestCase(ctx context.Context) testCase { + return testCase{ + name: "Success_NotLocal_SecondVisit", + args: args{ + ctx: ctx, + limit: 10, + visits: 2, + dur: time.Second, + ip: "mock IP address", }, - { - name: "Failure_NotLocal_FirstVisit", - args: args{ - ctx: ctx, - limit: 10, - visits: 1, - visitsErr: fmt.Errorf("Internal error"), - dur: time.Second, - ip: testutls.MockIpAddress, - }, - wantErr: true, + } +} + +func createFailureNotLocalFirstVisitTestCase(ctx context.Context) testCase { + return testCase{ + name: "Failure_NotLocal_FirstVisit", + args: args{ + ctx: ctx, + limit: 10, + visits: 1, + visitsErr: fmt.Errorf("Internal error"), + dur: time.Second, + ip: "mock IP address", }, - { - name: "Failure_NotLocal_FirstVisit_StartVisitErr", - args: args{ - ctx: ctx, - limit: 10, - visits: 1, - startVisitsErr: fmt.Errorf("Internal error"), - dur: time.Second, - ip: testutls.MockIpAddress, - }, - wantErr: true, + wantErr: true, + } +} + +func createFailureNotLocalFirstVisitStartVisitErrTestCase(ctx context.Context) testCase { + return testCase{ + name: "Failure_NotLocal_FirstVisit_StartVisitErr", + args: args{ + ctx: ctx, + limit: 10, + visits: 1, + startVisitsErr: fmt.Errorf("Internal error"), + dur: time.Second, + ip: "mock IP address", }, - { - name: "Failure_NotLocal_RateLimitExceeded", - args: args{ - ctx: ctx, - limit: 10, - visits: 11, - dur: time.Second, - ip: testutls.MockIpAddress, - }, - wantErr: true, + wantErr: true, + } +} + +func createFailureNotLocalRateLimitExceededTestCase(ctx context.Context) testCase { + return testCase{ + name: "Failure_NotLocal_RateLimitExceeded", + args: args{ + ctx: ctx, + limit: 10, + visits: 11, + dur: time.Second, + ip: "mock IP address", }, + wantErr: true, } +} +func TestCheck(t *testing.T) { + var ctx context.Context = testutls.MockCtx{} + tests := CreateTestCases(ctx) ApplyFunc(graphql.GetPath, func(ctx context.Context) ast.Path { return ast.Path{ast.PathName("users")} }) diff --git a/resolver/user_mutations.resolvers_test.go b/resolver/user_mutations.resolvers_test.go index 5b01e170..eeb905c9 100644 --- a/resolver/user_mutations.resolvers_test.go +++ b/resolver/user_mutations.resolvers_test.go @@ -166,10 +166,12 @@ func TestCreateUser( ) } } - -func TestUpdateUser( - t *testing.T, -) { +func GetUpdateUserTestCase() []struct { + name string + req *fm.UserUpdateInput + wantResp *fm.User + wantErr bool +} { cases := []struct { name string req *fm.UserUpdateInput @@ -209,6 +211,12 @@ func TestUpdateUser( wantErr: false, }, } + return cases +} +func TestUpdateUser( + t *testing.T, +) { + cases := GetUpdateUserTestCase() resolver1 := resolver.Resolver{} for _, tt := range cases { t.Run( @@ -253,9 +261,11 @@ func TestUpdateUser( } } -func TestDeleteUser( - t *testing.T, -) { +func GetDeleteTestCases() []struct { + name string + wantResp *fm.UserDeletePayload + wantErr bool +} { cases := []struct { name string wantResp *fm.UserDeletePayload @@ -277,6 +287,13 @@ func TestDeleteUser( wantErr: false, }, } + return cases +} + +func TestDeleteUser( + t *testing.T, +) { + cases := GetDeleteTestCases() resolver1 := resolver.Resolver{} for _, tt := range cases { t.Run( diff --git a/resolver/user_queries.resolvers_test.go b/resolver/user_queries.resolvers_test.go index e0a04229..72fcb854 100644 --- a/resolver/user_queries.resolvers_test.go +++ b/resolver/user_queries.resolvers_test.go @@ -2,6 +2,7 @@ package resolver_test import ( "context" + "database/sql" "encoding/json" "errors" "fmt" @@ -9,6 +10,7 @@ import ( "regexp" "testing" + "go-template/gqlmodels" fm "go-template/gqlmodels" "go-template/internal/config" "go-template/models" @@ -29,19 +31,37 @@ import ( "github.com/stretchr/testify/assert" ) -func TestMe( - t *testing.T, -) { - type args struct { - user *models.User +type args struct { + user *models.User +} + +func TestMe(t *testing.T) { + cases := initializeCases() + + err := loadEnvAndSetupDB(t) + if err != nil { + log.Fatal(err) + } + + resolver1 := &resolver.Resolver{} + for _, tt := range cases { + setupTestEnvironment(tt.name, t) + runTestCase(t, tt, resolver1) } - cases := []struct { +} + +func initializeCases() []struct { + name string + wantResp *fm.User + wantErr bool + args args +} { + return []struct { name string wantResp *fm.User wantErr bool args args }{ - { name: SuccessCase, args: args{user: testutls.MockUser()}, @@ -53,10 +73,12 @@ func TestMe( wantResp: nil, }, } +} +func loadEnvAndSetupDB(t *testing.T) error { err := config.LoadEnvWithFilePrefix(convert.StringToPointerString("./../")) if err != nil { - log.Fatal(err) + return err } _, db, _ := testutls.SetupMockDB(t) oldDb := boil.GetDB() @@ -65,6 +87,54 @@ func TestMe( db.Close() boil.SetDB(oldDb) }() + return nil +} + +func setupTestEnvironment(name string, t *testing.T) { + if name == ErrorFromRedisCache { + patchGetUser := patchRedisCache() + defer patchGetUser.Reset() + } + setupDBAndRedis(t) +} + +func runTestCase(t *testing.T, tt struct { + name string + wantResp *fm.User + wantErr bool + args args +}, resolver1 *resolver.Resolver) { + t.Run( + tt.name, + func(t *testing.T) { + testRedisConnection(tt.args.user) + + ctx := setupTestMeContext() + + response, err := resolver1.Query().Me(ctx) + assertTestMeResponse(t, tt, response, err) + }, + ) +} + +func patchRedisCache() *gomonkey.Patches { + return gomonkey.ApplyFunc(rediscache.GetUser, + func(userID int, ctx context.Context) (*models.User, error) { + return nil, errors.New("redis cache") + }) +} + +func setupDBAndRedis(t *testing.T) { + _, db, err := testutls.SetupEnvAndDB(t, testutls.Parameters{EnvFileLocation: `../.env.local`}) + if err != nil { + panic("failed to setup env and db") + } + oldDb := boil.GetDB() + boil.SetDB(db) + defer func() { + db.Close() + boil.SetDB(oldDb) + }() conn := redigomock.NewConn() ApplyFunc( redis.Dial, @@ -72,56 +142,40 @@ func TestMe( return conn, nil }, ) - // - resolver1 := resolver.Resolver{} - for _, tt := range cases { - if tt.name == ErrorFromRedisCache { - patchGetUser := gomonkey.ApplyFunc(rediscache.GetUser, - func(userID int, ctx context.Context) (*models.User, error) { - return nil, errors.New("redis cache") - }) - defer patchGetUser.Reset() - } - _, db, err := testutls.SetupEnvAndDB(t, testutls.Parameters{EnvFileLocation: `../.env.local`}) - if err != nil { - panic("failed to setup env and db") - } - oldDb := boil.GetDB() - boil.SetDB(db) - defer func() { - db.Close() - boil.SetDB(oldDb) - }() - conn := redigomock.NewConn() - ApplyFunc( - redis.Dial, - func(network string, address string, options ...redis.DialOption) (redis.Conn, error) { - return conn, nil - }, - ) - t.Run( - tt.name, - func(t *testing.T) { - b, _ := json.Marshal(tt.args.user) - conn.Command("GET", "user0").Expect(b) - c := context.Background() - ctx := context.WithValue(c, testutls.UserKey, testutls.MockUser()) - response, _ := resolver1.Query().Me(ctx) - if tt.wantResp != nil && - response != nil { - assert.Equal(t, tt.wantResp, response) - } - assert.Equal(t, tt.wantErr, err != nil) - }, - ) +} + +func testRedisConnection(user *models.User) { + b, _ := json.Marshal(user) + conn := redigomock.NewConn() + conn.Command("GET", "user0").Expect(b) +} + +func setupTestMeContext() context.Context { + c := context.Background() + ctx := context.WithValue(c, testutls.UserKey, testutls.MockUser()) + return ctx +} + +func assertTestMeResponse(t *testing.T, tt struct { + name string + wantResp *fm.User + wantErr bool + args args +}, response *fm.User, err error) { + if tt.wantResp != nil && response != nil { + assert.Equal(t, tt.wantResp, response) } + assert.Equal(t, tt.wantErr, err != nil) } // TestUsers is a unit test function for testing user queries. -func TestUsers( - t *testing.T, -) { - cases := []struct { +func initializeTestCases() []struct { + name string + pagination *fm.UserPagination + wantResp []*models.User + wantErr bool +} { + return []struct { name string pagination *fm.UserPagination wantResp []*models.User @@ -146,80 +200,112 @@ func TestUsers( wantResp: testutls.MockUsers(), }, } +} + +func loadEnvVars() error { + err := godotenv.Load("../.env.local") + if err != nil { + return err + } + return nil +} + +func setupMockDB(t *testing.T) (*sql.DB, sqlmock.Sqlmock, func()) { + db, mock, err := sqlmock.New() + if err != nil { + t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) + } + oldDB := boil.GetDB() + return db, mock, func() { + db.Close() + boil.SetDB(oldDB) + } +} + +func setExpectations(mock sqlmock.Sqlmock, tt struct { + name string + pagination *fm.UserPagination + wantResp []*models.User + wantErr bool +}) { + if tt.name == ErrorFindingUser { + mock.ExpectQuery(regexp.QuoteMeta(`select * from "users" where "id"=$1`)). + WithArgs(). + WillReturnError(fmt.Errorf("")) + } + if tt.name == "pagination" { + rows := sqlmock. + NewRows([]string{"id", "email", "first_name", "last_name", "mobile", "username", "address"}). + AddRow(testutls.MockID, testutls.MockEmail, "First", "Last", "+911234567890", "username", "22 Jump Street") + mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" LIMIT 1 OFFSET 1;`)).WithArgs().WillReturnRows(rows) - // Create a new instance of the resolver. + rowCount := sqlmock.NewRows([]string{"count"}). + AddRow(1) + mock.ExpectQuery(regexp.QuoteMeta(`SELECT COUNT(*) FROM "users" LIMIT 1;`)). + WithArgs(). + WillReturnRows(rowCount) + } else { + rows := sqlmock. + NewRows([]string{"id", "email", "first_name", "last_name", "mobile", "username", "address"}). + AddRow(testutls.MockID, testutls.MockEmail, "First", "Last", "+911234567890", "username", "22 Jump Street") + mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users";`)).WithArgs().WillReturnRows(rows) + + rowCount := sqlmock.NewRows([]string{"count"}). + AddRow(1) + mock.ExpectQuery(regexp.QuoteMeta(`SELECT COUNT(*) FROM "users";`)). + WithArgs(). + WillReturnRows(rowCount) + } +} + +func setupContext() context.Context { + c := context.Background() + return context.WithValue(c, testutls.UserKey, testutls.MockUser()) +} + +func executeQuery(resolver1 *resolver.Resolver, + ctx context.Context, pagination *fm.UserPagination) (*gqlmodels.UsersPayload, error) { + return resolver1.Query().Users(ctx, pagination) +} + +func assertResponse(t *testing.T, tt struct { + name string + pagination *fm.UserPagination + wantResp []*models.User + wantErr bool +}, response *gqlmodels.UsersPayload, err error) { + if tt.wantResp != nil && response != nil { + assert.Equal(t, len(tt.wantResp), len(response.Users)) + } + assert.Equal(t, tt.wantErr, err != nil) +} + +func TestUsers( + t *testing.T, +) { + cases := initializeTestCases() resolver1 := resolver.Resolver{} + for _, tt := range cases { t.Run( tt.name, func(t *testing.T) { - // Load environment variables from the .env.local file. - err := godotenv.Load( - "../.env.local", - ) + err := loadEnvVars() if err != nil { fmt.Print("error loading .env file") } - // Create a new mock database connection. - db, mock, err := sqlmock.New() - if err != nil { - t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) - } - // Inject mock instance into boil. - oldDB := boil.GetDB() - defer func() { - db.Close() - boil.SetDB(oldDB) - }() + db, mock, cleanup := setupMockDB(t) + defer cleanup() boil.SetDB(db) - //fail on finding user case - if tt.name == ErrorFindingUser { - mock.ExpectQuery(regexp.QuoteMeta(`select * from "users" where "id"=$1`)). - WithArgs(). - WillReturnError(fmt.Errorf("")) - } + setExpectations(mock, tt) - if tt.name == "pagination" { - rows := sqlmock. - NewRows([]string{"id", "email", "first_name", "last_name", "mobile", "username", "address"}). - AddRow(testutls.MockID, testutls.MockEmail, "First", "Last", "+911234567890", "username", "22 Jump Street") - mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" LIMIT 1 OFFSET 1;`)).WithArgs().WillReturnRows(rows) - - rowCount := sqlmock.NewRows([]string{"count"}). - AddRow(1) - mock.ExpectQuery(regexp.QuoteMeta(`SELECT COUNT(*) FROM "users" LIMIT 1;`)). - WithArgs(). - WillReturnRows(rowCount) - } else { - rows := sqlmock. - NewRows([]string{"id", "email", "first_name", "last_name", "mobile", "username", "address"}). - AddRow(testutls.MockID, testutls.MockEmail, "First", "Last", "+911234567890", "username", "22 Jump Street") - mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users";`)).WithArgs().WillReturnRows(rows) - - rowCount := sqlmock.NewRows([]string{"count"}). - AddRow(1) - mock.ExpectQuery(regexp.QuoteMeta(`SELECT COUNT(*) FROM "users";`)). - WithArgs(). - WillReturnRows(rowCount) - } - // Define a mock result set for user queries. - // Define a mock result set. - // Create a new context with a mock user. - c := context.Background() - ctx := context.WithValue(c, testutls.UserKey, testutls.MockUser()) - // Query for users using the resolver and get the response and error. - response, err := resolver1.Query(). - Users(ctx, tt.pagination) - - // Check if the response matches the expected response length. - if tt.wantResp != nil && - response != nil { - assert.Equal(t, len(tt.wantResp), len(response.Users)) - } - // Check if the error matches the expected error value. - assert.Equal(t, tt.wantErr, err != nil) + ctx := setupContext() + + response, err := executeQuery(&resolver1, ctx, tt.pagination) + + assertResponse(t, tt, response, err) }, ) } From 30ee36848bee3218ca2000959c3a16f9884b0aeb Mon Sep 17 00:00:00 2001 From: HIMANSHU Date: Sun, 24 Mar 2024 21:01:13 +0530 Subject: [PATCH 08/39] Funlen issue resolve V2 --- pkg/utl/rediscache/service_test.go | 158 ++--- resolver/auth_mutations.resolvers_test.go | 689 ++++++++++++++-------- 2 files changed, 535 insertions(+), 312 deletions(-) diff --git a/pkg/utl/rediscache/service_test.go b/pkg/utl/rediscache/service_test.go index e12cb6c9..c11af6ef 100644 --- a/pkg/utl/rediscache/service_test.go +++ b/pkg/utl/rediscache/service_test.go @@ -4,6 +4,7 @@ import ( "context" "database/sql/driver" "encoding/json" + "errors" "fmt" "log" "math" @@ -232,93 +233,92 @@ var DbResponse = sqlmock.NewRows([]string{ role.Name, ) -func TestGetRole(t *testing.T) { - type args struct { - roleID int - cacheMiss bool - dbQueries []testutls.QueryData +type GetRoleArgs struct { + roleID int + cacheMiss bool + dbQueries []testutls.QueryData +} + +func getRoleTestCase(name string, args GetRoleArgs, want *models.Role, wantErr bool, errMsg error) struct { + name string + args GetRoleArgs + want *models.Role + wantErr bool + errMsg error +} { + return struct { + name string + args GetRoleArgs + want *models.Role + wantErr bool + errMsg error + }{ + name: name, + args: args, + want: want, + wantErr: wantErr, + errMsg: errMsg, } - tests := []struct { +} + +func setupErrorCase(name string, roleID int, errMsg error) struct { + name string + args GetRoleArgs + want *models.Role + wantErr bool + errMsg error +} { + return struct { name string - args args + args GetRoleArgs want *models.Role wantErr bool errMsg error }{ - { - name: ErrorGetKeyValue, - args: args{ - roleID: testutls.MockID, - dbQueries: []testutls.QueryData{}, - }, - wantErr: true, - errMsg: fmt.Errorf(ErrMsgGetKeyValue), - }, - { - name: ErrorUnmarshal, - args: args{ - roleID: testutls.MockID, - dbQueries: []testutls.QueryData{}, - }, - wantErr: true, - errMsg: fmt.Errorf(ErrMsgUnmarshal), - }, - { - name: ErrorSetKeyValue, - args: args{ - roleID: testutls.MockID, - cacheMiss: true, - dbQueries: []testutls.QueryData{ - { - Actions: &[]driver.Value{role.ID}, - Query: `select * from "roles" where "id"=$1`, - DbResponse: DbResponse, - }, - }, - }, - wantErr: true, - errMsg: fmt.Errorf(ErrMsgSetKeyValue), - }, - { - name: ErrorFindRoleById, - args: args{ - roleID: testutls.MockID, - cacheMiss: true, - dbQueries: []testutls.QueryData{ - { - Actions: &[]driver.Value{role.ID}, - Query: `select * from "roles" where "id"=$1`, - DbResponse: DbResponse.RowError(0, fmt.Errorf("data error")), - }, - }, - }, - wantErr: true, - errMsg: fmt.Errorf(ErrMsgSetKeyValue), - }, - { - name: SuccessCase, - args: args{ - roleID: testutls.MockID, - dbQueries: []testutls.QueryData{}, - }, - want: role, - }, - { - name: SuccessCacheMiss, - args: args{ - roleID: testutls.MockID, - cacheMiss: true, - dbQueries: []testutls.QueryData{ - { - Actions: &[]driver.Value{role.ID}, - Query: `select * from "roles" where "id"=$1`, - DbResponse: DbResponse, - }, - }, - }, - want: role, + name: name, + args: GetRoleArgs{ + roleID: roleID, + dbQueries: []testutls.QueryData{}, }, + wantErr: true, + errMsg: errMsg, } +} + +func getGetRoleTestCases() []struct { + name string + args GetRoleArgs + want *models.Role + wantErr bool + errMsg error +} { + role := &models.Role{ID: testutls.MockID, Name: testutls.MockUser().R.Role.Name} + + tests := []struct { + name string + args GetRoleArgs + want *models.Role + wantErr bool + errMsg error + }{ + setupErrorCase(ErrorGetKeyValue, testutls.MockID, errors.New(ErrMsgGetKeyValue)), + setupErrorCase(ErrorUnmarshal, testutls.MockID, errors.New(ErrMsgUnmarshal)), + setupErrorCase(ErrorSetKeyValue, testutls.MockID, errors.New(ErrMsgSetKeyValue)), + setupErrorCase(ErrorFindRoleById, testutls.MockID, errors.New(ErrMsgFindRoleById)), + getRoleTestCase(SuccessCase, GetRoleArgs{roleID: testutls.MockID}, + role, false, nil), + getRoleTestCase(SuccessCacheMiss, GetRoleArgs{roleID: testutls.MockID, + cacheMiss: true, dbQueries: []testutls.QueryData{ + {Actions: &[]driver.Value{role.ID}, + Query: `select * from "roles" where "id"=$1`, + DbResponse: DbResponse}}}, + role, false, nil), + } + return tests +} + +func TestGetRole(t *testing.T) { + tests := getGetRoleTestCases() oldDB := boil.GetDB() err := config.LoadEnvWithFilePrefix(convert.StringToPointerString("./../../../")) if err != nil { diff --git a/resolver/auth_mutations.resolvers_test.go b/resolver/auth_mutations.resolvers_test.go index 1c2eef2c..276f9ab7 100644 --- a/resolver/auth_mutations.resolvers_test.go +++ b/resolver/auth_mutations.resolvers_test.go @@ -2,6 +2,7 @@ package resolver_test import ( "context" + "database/sql" "database/sql/driver" "fmt" "reflect" @@ -60,171 +61,366 @@ const ( TestUsername = "wednesday" TestToken = "refreshToken" ReqToken = "refresh_token" + ErrorMessage = "an error '%s' was not expected when opening a stub database connection" ) func TestLogin(t *testing.T) { - type args struct { - UserName string - Password string - } - var req = args{ - UserName: testutls.MockEmail, - Password: OldPassword, + cases := prepareTestCases() + + for _, tt := range cases { + t.Run(tt.name, func(t *testing.T) { + handleTestCases(t, tt) + }) } +} + +type LoginArgs struct { + UserName string + Password string +} + +var req = LoginArgs{ + UserName: testutls.MockEmail, + Password: OldPassword, +} + +func prepareTestCases() []struct { + name string + req LoginArgs + wantResp *fm.LoginResponse + wantErr bool + err error +} { cases := []struct { name string - req args + req LoginArgs wantResp *fm.LoginResponse wantErr bool err error }{ - { - name: ErrorFindingUser, - req: args{ - UserName: TestUsername, - Password: TestPassword, - }, - wantErr: true, - err: fmt.Errorf(ErrorMsgFindingUser), - }, - { - name: ErrorPasswordValidation, - req: args{ - UserName: testutls.MockEmail, - Password: TestPassword, - }, - wantErr: true, - err: fmt.Errorf(ErrorMsgPasswordValidation), - }, - { - name: ErrorActiveStatus, - req: req, - wantErr: true, - err: resultwrapper.ErrUnauthorized, - }, - { - name: ErrorFromConfig, - req: args{ - UserName: testutls.MockEmail, - Password: OldPassword, - }, - wantErr: true, - err: fmt.Errorf(ErrorMsgFromConfig), - }, - { - name: ErrorFromJwt, - req: req, - wantErr: true, - err: fmt.Errorf(ErrorMsgFromJwt), + prepareErrorFindingUser(), + prepareErrorPasswordValidation(), + prepareErrorActiveStatus(), + prepareErrorFromConfig(), + prepareErrorFromJwt(), + prepareErrorFromGenerateToken(), + prepareErrorUpdateUser(), + prepareSuccessCase(), + } + return cases +} + +func prepareErrorFindingUser() struct { + name string + req LoginArgs + wantResp *fm.LoginResponse + wantErr bool + err error +} { + return struct { + name string + req LoginArgs + wantResp *fm.LoginResponse + wantErr bool + err error + }{ + name: ErrorFindingUser, + req: LoginArgs{ + UserName: TestUsername, + Password: TestPassword, }, - { - name: ErrorFromGenerateToken, - req: req, - wantErr: true, - err: resultwrapper.ErrUnauthorized, + wantErr: true, + err: fmt.Errorf(ErrorMsgFindingUser), + } +} + +func prepareErrorPasswordValidation() struct { + name string + req LoginArgs + wantResp *fm.LoginResponse + wantErr bool + err error +} { + return struct { + name string + req LoginArgs + wantResp *fm.LoginResponse + wantErr bool + err error + }{ + name: ErrorPasswordValidation, + req: LoginArgs{ + UserName: testutls.MockEmail, + Password: TestPassword, }, - { - name: ErrorUpdateUser, - req: req, - wantErr: true, - err: fmt.Errorf(ErrorMsgfromUpdateUser), + wantErr: true, + err: fmt.Errorf(ErrorMsgPasswordValidation), + } +} +func prepareErrorActiveStatus() struct { + name string + req LoginArgs + wantResp *fm.LoginResponse + wantErr bool + err error +} { + return struct { + name string + req LoginArgs + wantResp *fm.LoginResponse + wantErr bool + err error + }{ + name: ErrorActiveStatus, + req: req, // Assuming req is defined somewhere in your code + wantErr: true, + err: resultwrapper.ErrUnauthorized, + } +} + +func prepareErrorFromConfig() struct { + name string + req LoginArgs + wantResp *fm.LoginResponse + wantErr bool + err error +} { + return struct { + name string + req LoginArgs + wantResp *fm.LoginResponse + wantErr bool + err error + }{ + name: ErrorFromConfig, + req: LoginArgs{ + UserName: testutls.MockEmail, + Password: OldPassword, }, - { - name: SuccessCase, - req: req, - wantResp: &fm.LoginResponse{ - Token: "jwttokenstring", - RefreshToken: TestToken, - }, + wantErr: true, + err: fmt.Errorf(ErrorMsgFromConfig), + } +} + +func prepareErrorFromJwt() struct { + name string + req LoginArgs + wantResp *fm.LoginResponse + wantErr bool + err error +} { + return struct { + name string + req LoginArgs + wantResp *fm.LoginResponse + wantErr bool + err error + }{ + name: ErrorFromJwt, + req: req, + wantErr: true, + err: fmt.Errorf(ErrorMsgFromJwt), + } +} + +func prepareErrorFromGenerateToken() struct { + name string + req LoginArgs + wantResp *fm.LoginResponse + wantErr bool + err error +} { + return struct { + name string + req LoginArgs + wantResp *fm.LoginResponse + wantErr bool + err error + }{ + name: ErrorFromGenerateToken, + req: req, + wantErr: true, + err: resultwrapper.ErrUnauthorized, + } +} + +func prepareErrorUpdateUser() struct { + name string + req LoginArgs + wantResp *fm.LoginResponse + wantErr bool + err error +} { + return struct { + name string + req LoginArgs + wantResp *fm.LoginResponse + wantErr bool + err error + }{ + name: ErrorUpdateUser, + req: req, + wantErr: true, + err: fmt.Errorf(ErrorMsgfromUpdateUser), + } +} + +func prepareSuccessCase() struct { + name string + req LoginArgs + wantResp *fm.LoginResponse + wantErr bool + err error +} { + return struct { + name string + req LoginArgs + wantResp *fm.LoginResponse + wantErr bool + err error + }{ + name: SuccessCase, + req: req, + wantResp: &fm.LoginResponse{ + Token: "jwttokenstring", + RefreshToken: TestToken, }, } +} - resolver1 := resolver.Resolver{} - for _, tt := range cases { - t.Run(tt.name, func(t *testing.T) { - if tt.name == ErrorFromConfig { - patch := gomonkey.ApplyFunc(config.Load, func() (*config.Configuration, error) { - return nil, fmt.Errorf(ErrorMsgFromConfig) - }) - defer patch.Reset() - } - var tg jwt.Service - if tt.name == ErrorFromJwt { - patch := gomonkey.ApplyFunc(service.JWT, func(cfg *config.Configuration) (jwt.Service, error) { - return tg, fmt.Errorf(ErrorMsgFromJwt) - }) - defer patch.Reset() - } - patch := gomonkey.ApplyFunc(tg.GenerateToken, func(u *models.User) (string, error) { - if tt.name == ErrorFromGenerateToken { - return "", resultwrapper.ErrUnauthorized - } - return "", nil - }) - defer patch.Reset() - err := config.LoadEnvWithFilePrefix(convert.StringToPointerString("./../")) - if err != nil { - fmt.Print("error loading .env file") - } - db, mock, err := sqlmock.New() - if err != nil { - t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) - } - oldDB := boil.GetDB() - defer func() { - db.Close() - boil.SetDB(oldDB) - }() - boil.SetDB(db) - - if tt.name == ErrorFindingUser { - mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (username=$1) LIMIT 1;`)). - WithArgs(). - WillReturnError(fmt.Errorf(ErrorMsgFindingUser)) - } - if tt.name == ErrorPasswordValidation { - rows := sqlmock.NewRows([]string{"id", "password", "active", "role_id"}). - AddRow(testutls.MockID, TestPasswordHash, true, 1) - mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (username=$1) LIMIT 1;`)). - WithArgs(). - WillReturnRows(rows) - } - if tt.name == ErrorActiveStatus { - rows := sqlmock.NewRows([]string{"id", "password", "active", "role_id"}). - AddRow(testutls.MockID, OldPasswordHash, false, 1) - mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (username=$1) LIMIT 1;`)). - WithArgs(). - WillReturnRows(rows) - } - rows := sqlmock.NewRows([]string{"id", "password", "active", "role_id"}). - AddRow(testutls.MockID, OldPasswordHash, true, 1) - mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (username=$1) LIMIT 1;`)). - WithArgs(). - WillReturnRows(rows) - if tt.name == SuccessCase || tt.name == ErrorUpdateUser { - rows := sqlmock.NewRows([]string{"id", "name"}). - AddRow(1, "ADMIN") - mock.ExpectQuery(regexp.QuoteMeta(`SELECT "roles".* FROM "roles" WHERE ("id" = $1) LIMIT 1`)). - WithArgs([]driver.Value{1}...). - WillReturnRows(rows) - } - if tt.name == ErrorUpdateUser { - mock.ExpectExec(regexp.QuoteMeta(`UPDATE "users" `)).WillReturnError(fmt.Errorf(ErrorMsgfromUpdateUser)) - } else { - result := driver.Result(driver.RowsAffected(1)) - mock.ExpectExec(regexp.QuoteMeta(`UPDATE "users" `)).WillReturnResult(result) - } - c := context.Background() - response, err := resolver1.Mutation().Login(c, tt.req.UserName, tt.req.Password) - if tt.wantResp != nil && response != nil { - tt.wantResp.RefreshToken = response.RefreshToken - tt.wantResp.Token = response.Token - assert.Equal(t, tt.wantResp, response) - } else { - assert.Equal(t, true, strings.Contains(err.Error(), tt.err.Error())) - assert.Equal(t, tt.wantErr, err != nil) - } +func handleTestCases(t *testing.T, tt struct { + name string + req LoginArgs + wantResp *fm.LoginResponse + wantErr bool + err error +}) { + // Prepare necessary mocks and patches + prepareMocksAndPatches(tt) + + // Load environment variables + loadEnvironmentVariables() + + // Set up mock database + mockDB := setupMockDBLogin(t) + defer mockDB.ExpectClose() + // Handle specific test cases + handleSpecificTestCase(t, tt) +} + +func prepareMocksAndPatches(tt struct { + name string + req LoginArgs + wantResp *fm.LoginResponse + wantErr bool + err error +}) { + if tt.name == ErrorFromConfig { + patch := gomonkey.ApplyFunc(config.Load, func() (*config.Configuration, error) { + return nil, fmt.Errorf(ErrorMsgFromConfig) }) + defer patch.Reset() + } + + var tg jwt.Service + if tt.name == ErrorFromJwt { + patch := gomonkey.ApplyFunc(service.JWT, func(cfg *config.Configuration) (jwt.Service, error) { + return tg, fmt.Errorf(ErrorMsgFromJwt) + }) + defer patch.Reset() + } + patch := gomonkey.ApplyFunc(tg.GenerateToken, func(u *models.User) (string, error) { + if tt.name == ErrorFromGenerateToken { + return "", resultwrapper.ErrUnauthorized + } + return "", nil + }) + defer patch.Reset() +} + +func loadEnvironmentVariables() { + err := config.LoadEnvWithFilePrefix(convert.StringToPointerString("./../")) + if err != nil { + fmt.Print("error loading .env file") + } +} + +func setupMockDBLogin(t *testing.T) sqlmock.Sqlmock { + db, mock, err := sqlmock.New() + if err != nil { + t.Fatalf(ErrorMessage, err) + } + oldDB := boil.GetDB() + defer func() { + db.Close() + boil.SetDB(oldDB) + }() + boil.SetDB(db) + return mock +} + +func handleSpecificTestCase(t *testing.T, tt struct { + name string + req LoginArgs + wantResp *fm.LoginResponse + wantErr bool + err error +}) { + resolver1 := resolver.Resolver{} + mock := setupMockDBLogin(t) + // Mock database queries based on test case + switch tt.name { + case ErrorFindingUser: + mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (username=$1) LIMIT 1;`)). + WithArgs(). + WillReturnError(fmt.Errorf(ErrorMsgFindingUser)) + case ErrorPasswordValidation: + rows := sqlmock.NewRows([]string{"id", "password", "active", "role_id"}). + AddRow(testutls.MockID, TestPasswordHash, true, 1) + mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (username=$1) LIMIT 1;`)). + WithArgs(). + WillReturnRows(rows) + case ErrorActiveStatus: + rows := sqlmock.NewRows([]string{"id", "password", "active", "role_id"}). + AddRow(testutls.MockID, OldPasswordHash, false, 1) + mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (username=$1) LIMIT 1;`)). + WithArgs(). + WillReturnRows(rows) + default: + rows := sqlmock.NewRows([]string{"id", "password", "active", "role_id"}). + AddRow(testutls.MockID, OldPasswordHash, true, 1) + mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (username=$1) LIMIT 1;`)). + WithArgs(). + WillReturnRows(rows) + } + + if tt.name == SuccessCase || tt.name == ErrorUpdateUser { + rows := sqlmock.NewRows([]string{"id", "name"}). + AddRow(1, "ADMIN") + mock.ExpectQuery(regexp.QuoteMeta(`SELECT "roles".* FROM "roles" WHERE ("id" = $1) LIMIT 1`)). + WithArgs([]driver.Value{1}...). + WillReturnRows(rows) + } + + if tt.name == ErrorUpdateUser { + mock.ExpectExec(regexp.QuoteMeta(`UPDATE "users" `)).WillReturnError(fmt.Errorf(ErrorMsgfromUpdateUser)) + } else { + result := driver.Result(driver.RowsAffected(1)) + mock.ExpectExec(regexp.QuoteMeta(`UPDATE "users" `)).WillReturnResult(result) + } + + // Execute resolver function + c := context.Background() + response, err := resolver1.Mutation().Login(c, tt.req.UserName, tt.req.Password) + + // Assert results + if tt.wantResp != nil && response != nil { + tt.wantResp.RefreshToken = response.RefreshToken + tt.wantResp.Token = response.Token + assert.Equal(t, tt.wantResp, response) + } else { + assert.Equal(t, true, strings.Contains(err.Error(), tt.err.Error())) + assert.Equal(t, tt.wantErr, err != nil) } } @@ -304,7 +500,7 @@ func TestChangePassword( // Handle the case where there is an error while loading the configuration if tt.name == ErrorFromConfig { patch := gomonkey.ApplyFunc(config.Load, func() (*config.Configuration, error) { - return nil, fmt.Errorf("error in loading config") + return nil, fmt.Errorf(ErrorMsgFromConfig) }) defer patch.Reset() } @@ -363,6 +559,47 @@ func TestChangePassword( } func TestRefreshToken(t *testing.T) { + cases := prepareRefreshTokenCases() + + resolver := resolver.Resolver{} + + for _, tt := range cases { + t.Run(tt.name, func(t *testing.T) { + db, mock := prepareMockDB(t) + defer db.Close() + + setupMockDBExpectations(tt.name, mock) + + mockConfigLoad := prepareMockConfigLoad(tt.name) + defer mockConfigLoad.Reset() + + mockJWTService := prepareMockJWTService(tt.name) + defer mockJWTService.Reset() + + mockTokenGeneration := prepareMockTokenGeneration(tt.name) + defer mockTokenGeneration.Reset() + + ctx := prepareContextRefereshToken() + + response, err := resolver.Mutation().RefreshToken(ctx, tt.req) + + if tt.wantResp != nil && response != nil { + tt.wantResp.Token = response.Token + assert.Equal(t, tt.wantResp, response) + } else { + assert.Equal(t, true, strings.Contains(err.Error(), tt.err.Error())) + } + }) + } +} + +func prepareRefreshTokenCases() []struct { + name string + req string + wantResp *fm.RefreshTokenResponse + wantErr bool + err error +} { cases := []struct { name string req string @@ -402,90 +639,76 @@ func TestRefreshToken(t *testing.T) { wantErr: false, }, } + return cases +} - // Create a new instance of the resolver - resolver1 := resolver.Resolver{} - for _, tt := range cases { - t.Run( - tt.name, - func(t *testing.T) { - // Create a mock SQL database connection - db, mock, err := sqlmock.New() - if err != nil { - t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) - } - // Inject mock instance into boil. - oldDB := boil.GetDB() - defer func() { - db.Close() - boil.SetDB(oldDB) - }() - boil.SetDB(db) - // Handle the case where authentication token is invalid - if tt.name == ErrorInvalidToken { - mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (token=$1) LIMIT 1;`)). - WithArgs(). - WillReturnError(fmt.Errorf(ErrorMsginvalidToken)) - } - // Handle the case where there is an error loading the config - patch := gomonkey.ApplyFunc(config.Load, func() (*config.Configuration, error) { - if tt.name == ErrorFromConfig { - return nil, fmt.Errorf("error in loading config") - } else { - return &config.Configuration{}, nil - } - }) - defer patch.Reset() - //initialize a jwt service - tg := jwt.Service{} - // Handle the case where there is an error creating the JWT service - patchJWT := gomonkey.ApplyFunc(service.JWT, func(cfg *config.Configuration) (jwt.Service, error) { - if tt.name == ErrorFromJwt { - return tg, fmt.Errorf(ErrorMsgFromJwt) - } else { - return tg, nil - } - }) - defer patchJWT.Reset() - // Handle the case where there is an error form token generation service - patchGenerateToken := gomonkey.ApplyMethod(reflect.TypeOf(tg), "GenerateToken", - func(jwt.Service, *models.User) (string, error) { - if tt.name == ErrorFromGenerateToken { - return "", resultwrapper.ErrUnauthorized - } else { - return "token", nil - } - }) - defer patchGenerateToken.Reset() - // Expect a query to get the user by ID to return a row with mock data entered - rows := sqlmock.NewRows([]string{"id", "email", "token", "role_id"}). - AddRow(1, testutls.MockEmail, testutls.MockToken, 1) - mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (token=$1) LIMIT 1;`)). - WithArgs(). - WillReturnRows(rows) - if tt.name == SuccessCase { - rows := sqlmock.NewRows([]string{"id", "name"}). - AddRow(1, "ADMIN") - mock.ExpectQuery(regexp.QuoteMeta(`SELECT "roles".* FROM "roles" WHERE ("id" = $1) LIMIT 1`)). - WithArgs([]driver.Value{1}...). - WillReturnRows(rows) - } - // Set up the context with the mock user - c := context.Background() - ctx := context.WithValue(c, testutls.UserKey, testutls.MockUser()) - // Call the refresh token mutation with the given arguments and check the response and error against the expected values - response, err := resolver1.Mutation(). - RefreshToken(ctx, tt.req) - if tt.wantResp != nil && - response != nil { - tt.wantResp.Token = response.Token - // Assert that the expected response matches the actual response - assert.Equal(t, tt.wantResp, response) - } else { - // Assert that the expected error value matches the actual error value - assert.Equal(t, true, strings.Contains(err.Error(), tt.err.Error())) - } - }, - ) +func prepareMockDB(t *testing.T) (*sql.DB, sqlmock.Sqlmock) { + db, mock, err := sqlmock.New() + if err != nil { + t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) + } + boil.SetDB(db) + return db, mock +} +func setupMockDBExpectations(name string, mock sqlmock.Sqlmock) { + switch name { + case ErrorInvalidToken: + mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (token=$1) LIMIT 1;`)). + WithArgs(). + WillReturnError(fmt.Errorf(ErrorMsginvalidToken)) + case SuccessCase: + rows := sqlmock.NewRows([]string{"id", "email", "token", "role_id"}). + AddRow(1, testutls.MockEmail, testutls.MockToken, 1) + mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (token=$1) LIMIT 1;`)). + WithArgs(). + WillReturnRows(rows) + rows = sqlmock.NewRows([]string{"id", "name"}). + AddRow(1, "ADMIN") + mock.ExpectQuery(regexp.QuoteMeta(`SELECT "roles".* FROM "roles" WHERE ("id" = $1) LIMIT 1`)). + WithArgs([]driver.Value{1}...). + WillReturnRows(rows) + case ErrorFromConfig: + // Expectation for error loading the config + mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (token=$1) LIMIT 1;`)). + WithArgs(). + WillReturnError(fmt.Errorf(ErrorMsgFromConfig)) + case ErrorFromJwt: + // Expectation for error in creating the JWT service + mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (token=$1) LIMIT 1;`)). + WithArgs(). + WillReturnRows(sqlmock.NewRows([]string{"id", "email", "token", "role_id"})) } } + +func prepareMockConfigLoad(name string) *gomonkey.Patches { + return gomonkey.ApplyFunc(config.Load, func() (*config.Configuration, error) { + if name == ErrorFromConfig { + return nil, fmt.Errorf(ErrorMsgFromConfig) + } + return &config.Configuration{}, nil + }) +} + +func prepareMockJWTService(name string) *gomonkey.Patches { + return gomonkey.ApplyFunc(service.JWT, func(cfg *config.Configuration) (jwt.Service, error) { + if name == ErrorFromJwt { + return jwt.Service{}, fmt.Errorf(ErrorMsgFromJwt) + } + return jwt.Service{}, nil + }) +} + +func prepareMockTokenGeneration(name string) *gomonkey.Patches { + return gomonkey.ApplyMethod(reflect.TypeOf(jwt.Service{}), "GenerateToken", + func(jwt.Service, *models.User) (string, error) { + if name == ErrorFromGenerateToken { + return "", resultwrapper.ErrUnauthorized + } + return "token", nil + }) +} + +func prepareContextRefereshToken() context.Context { + c := context.Background() + return context.WithValue(c, testutls.UserKey, testutls.MockUser()) +} From d3e9095534fd13812000cdc7af8c53eb36a29c60 Mon Sep 17 00:00:00 2001 From: HIMANSHU Date: Sun, 24 Mar 2024 21:20:45 +0530 Subject: [PATCH 09/39] Reoslved Funlen Issue V3 --- resolver/user_mutations.resolvers_test.go | 155 +++++++++++----------- 1 file changed, 76 insertions(+), 79 deletions(-) diff --git a/resolver/user_mutations.resolvers_test.go b/resolver/user_mutations.resolvers_test.go index eeb905c9..62dadf87 100644 --- a/resolver/user_mutations.resolvers_test.go +++ b/resolver/user_mutations.resolvers_test.go @@ -2,6 +2,7 @@ package resolver_test import ( "context" + "database/sql" "database/sql/driver" "fmt" "go-template/daos" @@ -17,11 +18,8 @@ import ( "testing" "time" - "github.com/agiledragon/gomonkey/v2" - . "github.com/agiledragon/gomonkey/v2" - "golang.org/x/crypto/bcrypt" - "github.com/DATA-DOG/go-sqlmock" + "github.com/agiledragon/gomonkey/v2" "github.com/joho/godotenv" "github.com/stretchr/testify/assert" "github.com/volatiletech/sqlboiler/v4/boil" @@ -37,9 +35,34 @@ func (a AnyTime) Match( return ok } -func TestCreateUser( - t *testing.T, -) { +func setupMockDBForCreateUser(t *testing.T) (*sql.DB, sqlmock.Sqlmock) { + mockDB, mock, err := sqlmock.New() + if err != nil { + t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) + } + return mockDB, mock +} + +func expectInsertUser(mock sqlmock.Sqlmock, mockUser models.User) { + rows := sqlmock.NewRows([]string{ + "id", "mobile", "address", "active", "last_login", "last_password_change", "token", "deleted_at", + }).AddRow( + mockUser.ID, mockUser.Mobile, mockUser.Address, mockUser.Active, + mockUser.LastLogin, mockUser.LastPasswordChange, mockUser.Token, mockUser.DeletedAt, + ) + mock.ExpectQuery(regexp.QuoteMeta(`INSERT INTO "users"`)). + WithArgs( + mockUser.FirstName, mockUser.LastName, mockUser.Username, "", mockUser.Email, + mockUser.RoleID, AnyTime{}, AnyTime{}, + ). + WillReturnRows(rows) +} +func GetCreateUserTestCase() []struct { + name string + req fm.UserCreateInput + wantResp *fm.User + wantErr bool +} { cases := []struct { name string req fm.UserCreateInput @@ -87,85 +110,59 @@ func TestCreateUser( wantErr: false, }, } - - resolver1 := resolver.Resolver{} + return cases +} +func TestCreateUser(t *testing.T) { + cases := GetCreateUserTestCase() + resolver := resolver.Resolver{} for _, tt := range cases { - t.Run( - tt.name, - func(t *testing.T) { - if tt.name == ErrorFromThrottleCheck { - patch := gomonkey.ApplyFunc(throttle.Check, func(ctx context.Context, limit int, dur time.Duration) error { - return fmt.Errorf("Internal error") - }) - defer patch.Reset() - } + t.Run(tt.name, func(t *testing.T) { + mockDB, mock := setupMockDBForCreateUser(t) + defer mockDB.Close() - if tt.name == ErrorFromConfig { - patch := gomonkey.ApplyFunc(config.Load, func() (*config.Configuration, error) { - return nil, fmt.Errorf("error in loading config") - }) - defer patch.Reset() - } - err := config.LoadEnvWithFilePrefix(convert.StringToPointerString("./../")) - if err != nil { - log.Fatal(err) - } - mock, db, _ := testutls.SetupMockDB(t) - oldDB := boil.GetDB() - defer func() { - db.Close() - boil.SetDB(oldDB) - }() - boil.SetDB(db) + defer func() { + _ = mock.ExpectationsWereMet() + }() - if tt.name == ErrorFromCreateUser { - // insert new user - mock.ExpectQuery(regexp.QuoteMeta(`INSERT INTO "users"`)). - WithArgs(). - WillReturnError(fmt.Errorf("")) - } - // insert new user - rows := sqlmock.NewRows([]string{ - "id", "mobile", "address", "active", "last_login", "last_password_change", "token", "deleted_at", - }). - AddRow( - testutls.MockUser().ID, - testutls.MockUser().Mobile, - testutls.MockUser().Address, - testutls.MockUser().Active, - testutls.MockUser().LastLogin, - testutls.MockUser().LastPasswordChange, - testutls.MockUser().Token, - testutls.MockUser().DeletedAt, - ) - ApplyFunc(bcrypt.GenerateFromPassword, func([]uint8, int) ([]uint8, error) { - var a []uint8 - return a, nil - }) + if tt.name == ErrorFromCreateUser { mock.ExpectQuery(regexp.QuoteMeta(`INSERT INTO "users"`)). - WithArgs( - testutls.MockUser().FirstName, - testutls.MockUser().LastName, - testutls.MockUser().Username, - "", - testutls.MockUser().Email, - testutls.MockUser().RoleID, - AnyTime{}, - AnyTime{}, - ). - WillReturnRows(rows) + WithArgs(). + WillReturnError(fmt.Errorf("")) + } else { + expectInsertUser(mock, *testutls.MockUser()) + } - c := context.Background() - response, err := resolver1.Mutation(). - CreateUser(c, tt.req) - if tt.wantResp != nil { - assert.Equal(t, tt.wantResp, response) - } - assert.Equal(t, tt.wantErr, err != nil) - }, - ) + if tt.name == ErrorFromThrottleCheck { + patch := gomonkey.ApplyFunc(throttle.Check, func(ctx context.Context, limit int, dur time.Duration) error { + return fmt.Errorf("Internal error") + }) + defer patch.Reset() + } + + if tt.name == ErrorFromConfig { + patch := gomonkey.ApplyFunc(config.Load, func() (*config.Configuration, error) { + return nil, fmt.Errorf("error in loading config") + }) + defer patch.Reset() + } + + err := config.LoadEnvWithFilePrefix(convert.StringToPointerString("./../")) + if err != nil { + log.Fatal(err) + } + mock, db, _ := testutls.SetupMockDB(t) + oldDB, db := boil.GetDB(), db + boil.SetDB(oldDB) + boil.SetDB(db) + response, err := resolver.Mutation().CreateUser(context.Background(), tt.req) + if tt.wantResp != nil { + assert.Equal(t, tt.wantResp, response) + } + assert.Equal(t, tt.wantErr, err != nil) + }) } } + func GetUpdateUserTestCase() []struct { name string req *fm.UserUpdateInput From 42241afed90a327c2e725e768c55d0307037c4a4 Mon Sep 17 00:00:00 2001 From: HIMANSHU Date: Mon, 25 Mar 2024 00:04:41 +0530 Subject: [PATCH 10/39] Resolved Funlen and Cyclop Issues --- .golangci.yml | 6 +- pkg/utl/rediscache/service_test.go | 264 ++++++++++++++++------ resolver/auth_mutations.resolvers_test.go | 197 +++++++++++----- resolver/role_mutations.resolvers_test.go | 93 ++++---- 4 files changed, 387 insertions(+), 173 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index fc08e570..46778f14 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -4,12 +4,7 @@ linters-settings: tab-width: 2 autofix: true funlen: - lines: 60 - statements: 50 - ignore-blank-lines: true ignore-comments: true - # cyclop: - # max-complexity: 10 linters: enable: - lll @@ -21,6 +16,7 @@ linters: - typecheck - unused - funlen + - cyclop - goconst - gofmt - godox diff --git a/pkg/utl/rediscache/service_test.go b/pkg/utl/rediscache/service_test.go index c11af6ef..b3024456 100644 --- a/pkg/utl/rediscache/service_test.go +++ b/pkg/utl/rediscache/service_test.go @@ -75,101 +75,217 @@ var dbQuerydata = sqlmock.NewRows([]string{ testutls.MockUser().Active, ) -func TestGetUser(t *testing.T) { - type args struct { - userID int - cacheMiss bool - dbQueries []testutls.QueryData - } +type argsGetUser struct { + userID int + cacheMiss bool + dbQueries []testutls.QueryData +} + +func GetUserTestCases() []struct { + name string + args argsGetUser + want *models.User + wantErr bool + errMsg error +} { tests := []struct { name string - args args + args argsGetUser want *models.User wantErr bool errMsg error }{ - { - name: ErrorGetKeyValue, - args: args{ - userID: testutls.MockID, - dbQueries: []testutls.QueryData{}, - }, - wantErr: true, - errMsg: fmt.Errorf(ErrMsgGetKeyValue), + ErrorGetKeyValueCase(), + ErrorUnmarshalCase(), + ErrorSetKeyValueCase(), + ErrorDaosCase(), + GetSuccessCase(), + SuccessCacheMissCase(), + ErrorFromCacheUserValueCase(), + } + return tests +} + +func ErrorGetKeyValueCase() struct { + name string + args argsGetUser + want *models.User + wantErr bool + errMsg error +} { + return struct { + name string + args argsGetUser + want *models.User + wantErr bool + errMsg error + }{ + name: ErrorGetKeyValue, + args: argsGetUser{ + userID: testutls.MockID, + dbQueries: []testutls.QueryData{}, }, - { - name: ErrorUnmarshal, - args: args{ - userID: testutls.MockID, - dbQueries: []testutls.QueryData{}, - }, - wantErr: true, + wantErr: true, + errMsg: fmt.Errorf(ErrMsgGetKeyValue), + } +} +func ErrorUnmarshalCase() struct { + name string + args argsGetUser + want *models.User + wantErr bool + errMsg error +} { + return struct { + name string + args argsGetUser + want *models.User + wantErr bool + errMsg error + }{ + name: ErrorUnmarshal, + args: argsGetUser{ + userID: testutls.MockID, + dbQueries: []testutls.QueryData{}, }, - { - name: ErrorSetKeyValue, - args: args{ - userID: testutls.MockID, - cacheMiss: true, - dbQueries: []testutls.QueryData{ - { - Actions: &[]driver.Value{testutls.MockID}, - Query: `select * from "users" where "id"=$1`, - DbResponse: dbQuerydata, - }, + wantErr: true, + } +} +func ErrorSetKeyValueCase() struct { + name string + args argsGetUser + want *models.User + wantErr bool + errMsg error +} { + return struct { + name string + args argsGetUser + want *models.User + wantErr bool + errMsg error + }{ + name: ErrorSetKeyValue, + args: argsGetUser{ + userID: testutls.MockID, + cacheMiss: true, + dbQueries: []testutls.QueryData{ + { + Actions: &[]driver.Value{testutls.MockID}, + Query: `select * from "users" where "id"=$1`, + DbResponse: dbQuerydata, }, }, - wantErr: true, - errMsg: fmt.Errorf(ErrMsgSetKeyValue), }, - { - name: ErrorDaos, - args: args{ - userID: testutls.MockID, - cacheMiss: true, - dbQueries: []testutls.QueryData{ - { - Actions: &[]driver.Value{testutls.MockID}, - Query: `select * from "users" where "id"=$1`, - DbResponse: dbQuerydata.RowError(0, fmt.Errorf("data error")), - }, + wantErr: true, + errMsg: fmt.Errorf(ErrMsgSetKeyValue), + } +} +func ErrorDaosCase() struct { + name string + args argsGetUser + want *models.User + wantErr bool + errMsg error +} { + return struct { + name string + args argsGetUser + want *models.User + wantErr bool + errMsg error + }{ + name: ErrorDaos, + args: argsGetUser{ + userID: testutls.MockID, + cacheMiss: true, + dbQueries: []testutls.QueryData{ + { + Actions: &[]driver.Value{testutls.MockID}, + Query: `select * from "users" where "id"=$1`, + DbResponse: dbQuerydata.RowError(0, fmt.Errorf("data error")), }, }, - wantErr: true, - errMsg: fmt.Errorf(ErrMsgSetKeyValue), }, - - { - name: SuccessCase, - args: args{ - userID: testutls.MockID, - dbQueries: []testutls.QueryData{}, - }, - want: testutls.MockUser(), + wantErr: true, + errMsg: fmt.Errorf(ErrMsgSetKeyValue), + } +} +func GetSuccessCase() struct { + name string + args argsGetUser + want *models.User + wantErr bool + errMsg error +} { + return struct { + name string + args argsGetUser + want *models.User + wantErr bool + errMsg error + }{ + name: SuccessCase, + args: argsGetUser{ + userID: testutls.MockID, + dbQueries: []testutls.QueryData{}, }, - { - name: SuccessCacheMiss, - args: args{ - userID: testutls.MockID, - cacheMiss: true, - dbQueries: []testutls.QueryData{ - { - Actions: &[]driver.Value{testutls.MockID}, - Query: `select * from "users" where "id"=$1`, - DbResponse: dbQuerydata, - }, + want: testutls.MockUser(), + } +} +func SuccessCacheMissCase() struct { + name string + args argsGetUser + want *models.User + wantErr bool + errMsg error +} { + return struct { + name string + args argsGetUser + want *models.User + wantErr bool + errMsg error + }{ + name: SuccessCacheMiss, + args: argsGetUser{ + userID: testutls.MockID, + cacheMiss: true, + dbQueries: []testutls.QueryData{ + { + Actions: &[]driver.Value{testutls.MockID}, + Query: `select * from "users" where "id"=$1`, + DbResponse: dbQuerydata, }, }, - want: testutls.MockUser(), }, - { - name: ErrorFromCacheUserValue, - args: args{ - userID: testutls.MockID, - dbQueries: []testutls.QueryData{}, - }, + want: testutls.MockUser(), + } +} +func ErrorFromCacheUserValueCase() struct { + name string + args argsGetUser + want *models.User + wantErr bool + errMsg error +} { + return struct { + name string + args argsGetUser + want *models.User + wantErr bool + errMsg error + }{ + name: ErrorFromCacheUserValue, + args: argsGetUser{ + userID: testutls.MockID, + dbQueries: []testutls.QueryData{}, }, } +} +func TestGetUser(t *testing.T) { + tests := GetUserTestCases() oldDB := boil.GetDB() err := config.LoadEnvWithFilePrefix(convert.StringToPointerString("./../../../")) if err != nil { diff --git a/resolver/auth_mutations.resolvers_test.go b/resolver/auth_mutations.resolvers_test.go index 276f9ab7..2e48cb25 100644 --- a/resolver/auth_mutations.resolvers_test.go +++ b/resolver/auth_mutations.resolvers_test.go @@ -424,73 +424,164 @@ func handleSpecificTestCase(t *testing.T, tt struct { } } -func TestChangePassword( - t *testing.T, -) { - // Define a struct to represent the change password request - type changeReq struct { - OldPassword string - NewPassword string - } +type changeReq struct { + OldPassword string + NewPassword string +} + +func GetChangePasswordTestCases() []struct { + name string + req changeReq + wantResp *fm.ChangePasswordResponse + wantErr bool +} { cases := []struct { name string req changeReq wantResp *fm.ChangePasswordResponse wantErr bool }{ - { - name: ErrorFindingUser, - req: changeReq{ - OldPassword: TestPassword, - NewPassword: NewPassword, - }, - wantErr: true, + ErrorFindingUserCase(), + ErrorPasswordValidationCase(), + ErrorInsecurePasswordCase(), + ErrorUpdateUserCase(), + ErrorFromConfigCase(), + GetSuccessCase(), + } + return cases +} +func ErrorFindingUserCase() struct { + name string + req changeReq + wantResp *fm.ChangePasswordResponse + wantErr bool +} { + return struct { + name string + req changeReq + wantResp *fm.ChangePasswordResponse + wantErr bool + }{ + name: ErrorFindingUser, + req: changeReq{ + OldPassword: TestPassword, + NewPassword: NewPassword, }, - { - name: ErrorPasswordValidation, - req: changeReq{ - OldPassword: TestPassword, - NewPassword: NewPassword, - }, - wantErr: true, + wantErr: true, + } +} + +func ErrorPasswordValidationCase() struct { + name string + req changeReq + wantResp *fm.ChangePasswordResponse + wantErr bool +} { + return struct { + name string + req changeReq + wantResp *fm.ChangePasswordResponse + wantErr bool + }{ + name: ErrorPasswordValidation, + req: changeReq{ + OldPassword: TestPassword, + NewPassword: NewPassword, }, - { - name: ErrorInsecurePassword, - req: changeReq{ - OldPassword: OldPassword, - NewPassword: testutls.MockEmail, - }, - wantErr: true, + wantErr: true, + } +} + +func ErrorInsecurePasswordCase() struct { + name string + req changeReq + wantResp *fm.ChangePasswordResponse + wantErr bool +} { + return struct { + name string + req changeReq + wantResp *fm.ChangePasswordResponse + wantErr bool + }{ + name: ErrorInsecurePassword, + req: changeReq{ + OldPassword: OldPassword, + NewPassword: testutls.MockEmail, }, - { - name: ErrorUpdateUser, - req: changeReq{ - OldPassword: OldPassword, - NewPassword: NewPassword, - }, - wantErr: true, + wantErr: true, + } +} +func ErrorUpdateUserCase() struct { + name string + req changeReq + wantResp *fm.ChangePasswordResponse + wantErr bool +} { + return struct { + name string + req changeReq + wantResp *fm.ChangePasswordResponse + wantErr bool + }{ + name: ErrorUpdateUser, + req: changeReq{ + OldPassword: OldPassword, + NewPassword: NewPassword, }, - { - name: ErrorFromConfig, - req: changeReq{ - OldPassword: OldPassword, - NewPassword: testutls.MockEmail, - }, - wantErr: true, + wantErr: true, + } +} + +func ErrorFromConfigCase() struct { + name string + req changeReq + wantResp *fm.ChangePasswordResponse + wantErr bool +} { + return struct { + name string + req changeReq + wantResp *fm.ChangePasswordResponse + wantErr bool + }{ + name: ErrorFromConfig, + req: changeReq{ + OldPassword: OldPassword, + NewPassword: testutls.MockEmail, }, + wantErr: true, + } +} - { - name: SuccessCase, - req: changeReq{ - OldPassword: OldPassword, - NewPassword: NewPassword, - }, - wantResp: &fm.ChangePasswordResponse{ - Ok: true, - }, - wantErr: false, +func GetSuccessCase() struct { + name string + req changeReq + wantResp *fm.ChangePasswordResponse + wantErr bool +} { + return struct { + name string + req changeReq + wantResp *fm.ChangePasswordResponse + wantErr bool + }{ + name: SuccessCase, + req: changeReq{ + OldPassword: OldPassword, + NewPassword: NewPassword, + }, + wantResp: &fm.ChangePasswordResponse{ + Ok: true, }, + wantErr: false, } +} +func TestChangePassword( + t *testing.T, +) { + // Define a struct to represent the change password request + cases := GetChangePasswordTestCases() // Create a new instance of the resolver resolver1 := resolver.Resolver{} for _, tt := range cases { diff --git a/resolver/role_mutations.resolvers_test.go b/resolver/role_mutations.resolvers_test.go index e6620c69..31f34db9 100644 --- a/resolver/role_mutations.resolvers_test.go +++ b/resolver/role_mutations.resolvers_test.go @@ -20,11 +20,12 @@ import ( "github.com/stretchr/testify/assert" ) -// TestCreateRole tests the CreateRole mutation function. -func TestCreateRole( - t *testing.T, -) { - // Define test cases, each case has a name, request input, expected response, and error. +func GetCreateRoleTestCases() []struct { + name string + req fm.RoleCreateInput + wantResp *fm.RolePayload + wantErr bool +} { cases := []struct { name string req fm.RoleCreateInput @@ -73,43 +74,60 @@ func TestCreateRole( wantErr: true, }, } + return cases +} + +func ApplyPatchUserId() *gomonkey.Patches { + return gomonkey.ApplyFunc(auth.UserIDFromContext, + func(ctx context.Context) int { + return 1 + }) +} +func ApplypatchGetUser() *gomonkey.Patches { + return gomonkey.ApplyFunc(rediscache.GetUser, + func(userID int, ctx context.Context) (*models.User, error) { + return &models.User{ + RoleID: null.IntFrom(1), + }, nil + }) +} +func ApplypatchGetRole() *gomonkey.Patches { + return gomonkey.ApplyFunc(rediscache.GetRole, + func(roleID int, ctx context.Context) (*models.Role, error) { + return &models.Role{ + AccessLevel: int(constants.SuperAdminRole), + Name: SuperAdminRoleName, + }, nil + }) +} +func ApplypatchCreateRole() *gomonkey.Patches { + return gomonkey.ApplyFunc(daos.CreateRole, + func(role models.Role, ctx context.Context) (models.Role, error) { + return models.Role{ + AccessLevel: int(constants.UserRole), + Name: UserRoleName, + }, nil + }) +} + +// TestCreateRole tests the CreateRole mutation function. +func TestCreateRole( + t *testing.T, +) { + // Define test cases, each case has a name, request input, expected response, and error. + cases := GetCreateRoleTestCases() // Create a new resolver instance. resolver1 := resolver.Resolver{} - // Loop through each test case. for _, tt := range cases { // Mocking rediscache.GetUserID function - patchUserID := gomonkey.ApplyFunc(auth.UserIDFromContext, - func(ctx context.Context) int { - return 1 - }) - + patchUserID := ApplyPatchUserId() // Mocking rediscache.GetUser function - patchGetUser := gomonkey.ApplyFunc(rediscache.GetUser, - func(userID int, ctx context.Context) (*models.User, error) { - return &models.User{ - RoleID: null.IntFrom(1), - }, nil - }) - + patchGetUser := ApplypatchGetUser() // Mocking rediscache.GetRole function - patchGetRole := gomonkey.ApplyFunc(rediscache.GetRole, - func(roleID int, ctx context.Context) (*models.Role, error) { - return &models.Role{ - AccessLevel: int(constants.SuperAdminRole), - Name: SuperAdminRoleName, - }, nil - }) - + patchGetRole := ApplypatchGetRole() // Mocking daos.CreateRole function - patchCreateRole := gomonkey.ApplyFunc(daos.CreateRole, - func(role models.Role, ctx context.Context) (models.Role, error) { - return models.Role{ - AccessLevel: int(constants.UserRole), - Name: UserRoleName, - }, nil - }) - + patchCreateRole := ApplypatchCreateRole() // Defer resetting of the monkey patches. defer patchUserID.Reset() defer patchGetUser.Reset() @@ -125,7 +143,6 @@ func TestCreateRole( }) defer patchGetUser.Reset() } - if tt.name == ErrorFromGetRole { patchGetRole := gomonkey.ApplyFunc(rediscache.GetRole, func(roleID int, ctx context.Context) (*models.Role, error) { @@ -133,7 +150,6 @@ func TestCreateRole( }) defer patchGetRole.Reset() } - if tt.name == ErrorUnauthorizedUser { patchGetRole := gomonkey.ApplyFunc(rediscache.GetRole, func(roleID int, ctx context.Context) (*models.Role, error) { @@ -144,7 +160,6 @@ func TestCreateRole( }) defer patchGetRole.Reset() } - if tt.name == ErrorFromCreateRole { patchCreateRole := gomonkey.ApplyFunc(daos.CreateRole, func(role models.Role, ctx context.Context) (models.Role, error) { @@ -153,18 +168,14 @@ func TestCreateRole( defer patchCreateRole.Reset() } - // Create a new context c := context.Background() - // Call the resolver function response, err := resolver1.Mutation().CreateRole(c, tt.req) - // Check if the error matches the expected error if tt.wantErr { assert.NotNil(t, err) } - // Check if the response matches the expected response assert.Equal(t, tt.wantResp, response) }) From 7cc23b0eb6198d4875851fa62211d013f076c48a Mon Sep 17 00:00:00 2001 From: HIMANSHU Date: Wed, 27 Mar 2024 14:48:22 +0530 Subject: [PATCH 11/39] Added Misssed testcases --- go.mod | 1 - go.sum | 1 - internal/config/env_test.go | 55 ++++++++++++++++++++++++++++++++++--- 3 files changed, 51 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 921bb19f..c8be99bf 100644 --- a/go.mod +++ b/go.mod @@ -84,7 +84,6 @@ require ( github.com/spf13/cobra v1.2.1 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect - github.com/stretchr/objx v0.4.0 // indirect github.com/subosito/gotenv v1.2.0 // indirect github.com/urfave/cli/v2 v2.11.0 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect diff --git a/go.sum b/go.sum index cc133601..0d281eb1 100644 --- a/go.sum +++ b/go.sum @@ -525,7 +525,6 @@ github.com/spf13/viper v1.10.0 h1:mXH0UwHS4D2HwWZa75im4xIQynLfblmWV7qcWpfv0yk= github.com/spf13/viper v1.10.0/go.mod h1:SoyBPwAtKDzypXNDFKN5kzH7ppppbGZtls1UpIy5AsM= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0 h1:M2gUjqZET1qApGOWNSnZ49BAIMX4F/1plDv3+l31EJ4= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= diff --git a/internal/config/env_test.go b/internal/config/env_test.go index bbe346ea..c970e481 100644 --- a/internal/config/env_test.go +++ b/internal/config/env_test.go @@ -166,8 +166,12 @@ type args struct { } func TestLoadEnv(t *testing.T) { - tests := getTestCases() - + username := "go_template_role" + host := "localhost" + dbname := "go_template" + password := "go_template_role456" + port := "5432" + tests := getTestCases(username, host, dbname, password, port) for _, tt := range tests { mockEnvLoad(tt) setEnvironmentVariables(tt.args) @@ -178,7 +182,7 @@ func TestLoadEnv(t *testing.T) { } } -func getTestCases() []struct { +func getTestCases(username string, host string, dbname string, password string, port string) []struct { name string wantErr bool args args @@ -193,7 +197,50 @@ func getTestCases() []struct { wantErr: false, args: args{env: "", tapped: false}, }, - // Add more test cases here... + { + name: "Successfully load local env", + wantErr: false, + args: args{env: "local", tapped: false}, + }, + { + name: "Env varInjection Error", + wantErr: true, + args: args{env: "local", tapped: false}, + }, + { + name: "dbCredsInjected True", + wantErr: true, + args: args{env: "", tapped: false}, + }, + + { + name: "Successfully load develop env", + wantErr: false, + args: args{ + env: "production", + tapped: false, + dbSecret: fmt.Sprintf(`{"username":"%s",`+ + `"host":"%s","dbname":"%s","password":"%s",`+ + `"port":%s}`, username, host, dbname, password, port), + }, + }, + { + name: "dbCredsInjected True", + wantErr: false, + args: args{env: "", tapped: false, dbSecret: fmt.Sprintf(`{"username":"%s",`+ + `"host":"%s","dbname":"%s","password":"%s",`+ + `"port":%s}`, username, host, dbname, password, port), + }, + }, + { + name: "Failed to load env", + wantErr: true, + args: args{ + env: "local", + err: "there was some error while loading the environment variables", + tapped: false, + }, + }, } } From 76367a67962653da1c96c2f954cc53e1fb35ae7b Mon Sep 17 00:00:00 2001 From: Mac Date: Thu, 28 Mar 2024 02:40:15 +0530 Subject: [PATCH 12/39] feat: neater tests --- cmd/server/main_test.go | 72 ++- daos/users_test.go | 210 ++----- internal/config/config.go | 10 +- internal/config/config_test.go | 22 +- internal/config/env.go | 20 +- internal/config/env_test.go | 238 +++++--- internal/jwt/jwt_test.go | 3 +- internal/middleware/auth/auth_test.go | 25 +- internal/server/server_test.go | 31 +- pkg/utl/rediscache/service_test.go | 677 ++++++++++------------ pkg/utl/resultwrapper/error_test.go | 8 +- resolver/auth_mutations.resolvers_test.go | 53 +- resolver/user_mutations.resolvers_test.go | 69 +-- resolver/user_queries.resolvers_test.go | 69 +-- testutls/main.go | 15 +- 15 files changed, 659 insertions(+), 863 deletions(-) diff --git a/cmd/server/main_test.go b/cmd/server/main_test.go index 0959d1f5..93d73ab8 100644 --- a/cmd/server/main_test.go +++ b/cmd/server/main_test.go @@ -1,13 +1,12 @@ package main_test import ( - "log" + "os" "testing" main "go-template/cmd/server" "go-template/internal/config" "go-template/pkg/api" - "go-template/pkg/utl/convert" . "github.com/agiledragon/gomonkey/v2" "github.com/joho/godotenv" @@ -17,52 +16,73 @@ import ( const SuccessCase = "Success" -func TestSetup(t *testing.T) { - initEnv := func() { - err := config.LoadEnvWithFilePrefix(convert.StringToPointerString("./../../")) - if err != nil { - log.Fatal(err) +type TestArgs struct { + setBaseEnv bool + patchDotEnv bool + mockStart bool + apiStarted bool +} + +func initEnv(args *TestArgs) *Patches { + if args != nil { + if args.setBaseEnv { + os.Setenv("ENVIRONMENT_NAME", "") + } + if args.patchDotEnv { + loadPatches := ApplyFunc(godotenv.Load, func(...string) error { + return nil + }) + return loadPatches + } + if args.mockStart { + apiPatches := ApplyFunc(api.Start, func(cfg *config.Configuration) (*echo.Echo, error) { + args.apiStarted = true + return nil, nil + }) + + return apiPatches } } + + return nil +} +func TestSetup(t *testing.T) { cases := map[string]struct { error string isPanic bool - init func() + init func(*TestArgs) *Patches + args *TestArgs }{ "Failure__envFileNotFound": { - error: "open .env.base: no such file or directory", + error: "error loading port from .env", isPanic: true, init: initEnv, - }, - "Failure_NoEnvName": { - error: "open .env.base: no such file or directory", - isPanic: true, + args: &TestArgs{ + patchDotEnv: true, + }, }, SuccessCase: { isPanic: false, init: initEnv, + args: &TestArgs{ + apiStarted: false, + mockStart: true, + }, }, } for name, tt := range cases { t.Run(name, func(t *testing.T) { if tt.init != nil { - tt.init() + patches := tt.init(tt.args) + if patches != nil { + defer patches.Reset() + } } if tt.isPanic { - assert.PanicsWithValue(t, tt.error, main.Setup, "os.Exit was not called") + assert.PanicsWithValue(t, tt.error, main.Setup, tt.error) } else { - apiStarted := false - loadPatches := ApplyFunc(godotenv.Load, func(...string) error { - return nil - }) - apiPatches := ApplyFunc(api.Start, func(cfg *config.Configuration) (*echo.Echo, error) { - apiStarted = true - return nil, nil - }) - defer apiPatches.Reset() - defer loadPatches.Reset() main.Setup() - assert.Equal(t, apiStarted, true) + assert.Equal(t, tt.args.apiStarted, true) } }) } diff --git a/daos/users_test.go b/daos/users_test.go index c8986d74..01a2b2f6 100644 --- a/daos/users_test.go +++ b/daos/users_test.go @@ -2,23 +2,18 @@ package daos_test import ( "context" - "database/sql" "database/sql/driver" "fmt" - "log" "regexp" "testing" "go-template/daos" - "go-template/internal/config" "go-template/models" - "go-template/pkg/utl/convert" "go-template/testutls" "github.com/DATA-DOG/go-sqlmock" "github.com/stretchr/testify/assert" "github.com/volatiletech/null/v8" - "github.com/volatiletech/sqlboiler/v4/boil" "github.com/volatiletech/sqlboiler/v4/queries/qm" ) @@ -26,10 +21,7 @@ const ErrorFindingUser = "Fail on finding user" func TestCreateUserTx(t *testing.T) { cases := getTestCases() - for _, tt := range cases { - setupMockDB(t) - t.Run(tt.name, func(t *testing.T) { testCreateUser(t, tt) }) @@ -58,28 +50,13 @@ func getTestCases() []struct { } } -func setupMockDB(t *testing.T) (*sql.DB, sqlmock.Sqlmock) { - err := config.LoadEnvWithFilePrefix(convert.StringToPointerString("./../")) - if err != nil { - log.Fatal(err) - } - mock, db, _ := testutls.SetupMockDB(t) - oldDB := boil.GetDB() - defer func() { - db.Close() - boil.SetDB(oldDB) - }() - boil.SetDB(db) - return db, mock -} - func testCreateUser(t *testing.T, tt struct { name string req models.User err error }) { - db, mock := setupMockDB(t) - defer db.Close() + mock, cleanup, _ := testutls.SetupMockDB(t) + defer cleanup() rows := sqlmock.NewRows([]string{ "first_name", @@ -112,6 +89,7 @@ func testCreateUser(t *testing.T, tt struct { _, err := daos.CreateUser(tt.req, context.Background()) if err != nil { + fmt.Println(tt.err.Error()) assert.Equal(t, true, tt.err != nil) } else { assert.Equal(t, err, tt.err) @@ -130,22 +108,9 @@ func TestFindUserByID(t *testing.T) { err: nil, }, } + mock, cleanup, _ := testutls.SetupMockDB(t) + defer cleanup() for _, tt := range cases { - err := config.LoadEnv() - if err != nil { - fmt.Print("error loading .env file") - } - db, mock, err := sqlmock.New() - if err != nil { - t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) - } - // Inject mock instance into boil. - oldDB := boil.GetDB() - defer func() { - db.Close() - boil.SetDB(oldDB) - }() - boil.SetDB(db) rows := sqlmock.NewRows([]string{"id"}).AddRow(1) mock.ExpectQuery(regexp.QuoteMeta(`select * from "users" where "id"=$1`)). WithArgs(). @@ -165,43 +130,35 @@ func TestFindUserByEmail(t *testing.T) { name string req args err error + init func(mock sqlmock.Sqlmock) }{ { name: ErrorFindingUser, req: args{email: "abc"}, err: fmt.Errorf("sql: no rows in sql"), + init: func(mock sqlmock.Sqlmock) { + mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (email=$1) LIMIT 1;`)). + WithArgs(). + WillReturnError(fmt.Errorf("")) + }, }, { name: "Passing an email", req: args{email: "mac"}, err: nil, + init: func(mock sqlmock.Sqlmock) { + rows := sqlmock.NewRows([]string{"id"}).AddRow(1) + mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (email=$1) LIMIT 1;`)). + WithArgs(). + WillReturnRows(rows) + }, }, } + + mock, cleanup, _ := testutls.SetupMockDB(t) + defer cleanup() for _, tt := range cases { - err := config.LoadEnv() - if err != nil { - fmt.Print("error loading .env file") - } - db, mock, err := sqlmock.New() - if err != nil { - t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) - } - // Inject mock instance into boil. - oldDB := boil.GetDB() - defer func() { - db.Close() - boil.SetDB(oldDB) - }() - boil.SetDB(db) - if tt.name == ErrorFindingUser { - mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (email=$1) LIMIT 1;`)). - WithArgs(). - WillReturnError(fmt.Errorf("")) - } - rows := sqlmock.NewRows([]string{"id"}).AddRow(1) - mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (email=$1) LIMIT 1;`)). - WithArgs(). - WillReturnRows(rows) + tt.init(mock) t.Run(tt.name, func(t *testing.T) { _, err := daos.FindUserByEmail(tt.req.email, context.Background()) if err != nil { @@ -221,44 +178,35 @@ func TestFindUserByUserName(t *testing.T) { name string req args err error + init func(sqlmock.Sqlmock) }{ { name: "Fail on finding user username", req: args{Username: "user"}, err: fmt.Errorf("sql: no rows in sql"), + init: func(mock sqlmock.Sqlmock) { + mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (username=$1) LIMIT 1;`)). + WithArgs(). + WillReturnError(fmt.Errorf("")) + }, }, { name: "Passing a valid username", req: args{Username: "user_name"}, err: nil, + init: func(mock sqlmock.Sqlmock) { + rows := sqlmock.NewRows([]string{"id"}).AddRow(1) + mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (username=$1) LIMIT 1;`)). + WithArgs(). + WillReturnRows(rows) + }, }, } + mock, cleanup, _ := testutls.SetupMockDB(t) + defer cleanup() for _, tt := range cases { - err := config.LoadEnv() - if err != nil { - fmt.Print("error loading .env file") - } - db, mock, err := sqlmock.New() - if err != nil { - t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) - } - // Inject mock instance into boil. - oldDB := boil.GetDB() - defer func() { - db.Close() - boil.SetDB(oldDB) - }() - boil.SetDB(db) - if tt.name == "Fail on finding user username" { - mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (username=$1) LIMIT 1;`)). - WithArgs(). - WillReturnError(fmt.Errorf("")) - } - rows := sqlmock.NewRows([]string{"id"}).AddRow(1) - mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (username=$1) LIMIT 1;`)). - WithArgs(). - WillReturnRows(rows) t.Run(tt.name, func(t *testing.T) { + tt.init(mock) _, err := daos.FindUserByUserName(tt.req.Username, context.Background()) if err != nil { assert.Equal(t, true, tt.err != nil) @@ -280,24 +228,9 @@ func TestUpdateUserTx(t *testing.T) { err: nil, }, } - + mock, cleanup, _ := testutls.SetupMockDB(t) + defer cleanup() for _, tt := range cases { - err := config.LoadEnv() - if err != nil { - fmt.Print("error loading .env file") - } - - db, mock, err := sqlmock.New() - if err != nil { - t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) - } - // Inject mock instance into boil. - oldDB := boil.GetDB() - defer func() { - db.Close() - boil.SetDB(oldDB) - }() - boil.SetDB(db) result := driver.Result(driver.RowsAffected(1)) // get access_token mock.ExpectExec(regexp.QuoteMeta(`UPDATE "users" `)). @@ -321,22 +254,9 @@ func TestDeleteUser(t *testing.T) { err: nil, }, } + mock, cleanup, _ := testutls.SetupMockDB(t) + defer cleanup() for _, tt := range cases { - err := config.LoadEnv() - if err != nil { - fmt.Print("error loading .env file") - } - db, mock, err := sqlmock.New() - if err != nil { - t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) - } - // Inject mock instance into boil. - oldDB := boil.GetDB() - defer func() { - db.Close() - boil.SetDB(oldDB) - }() - boil.SetDB(db) // delete user result := driver.Result(driver.RowsAffected(1)) mock.ExpectExec(regexp.QuoteMeta(`DELETE FROM "users" WHERE "id"=$1`)). @@ -348,13 +268,8 @@ func TestDeleteUser(t *testing.T) { } } func TestFindAllUsersWithCount(t *testing.T) { - oldDB := boil.GetDB() - err := config.LoadEnvWithFilePrefix(convert.StringToPointerString("./../")) - if err != nil { - log.Fatal(err) - } - mock, db, _ := testutls.SetupMockDB(t) - + mock, cleanup, _ := testutls.SetupMockDB(t) + defer cleanup() cases := []struct { name string err error @@ -406,8 +321,6 @@ func TestFindAllUsersWithCount(t *testing.T) { } }) } - boil.SetDB(oldDB) - db.Close() } func TestFindUserByToken(t *testing.T) { type args struct { @@ -417,43 +330,34 @@ func TestFindUserByToken(t *testing.T) { name string req args err error + init func(sqlmock.Sqlmock) }{ { name: "Fail on finding user token", req: args{Token: "tokenString"}, err: fmt.Errorf("sql: no rows in sql"), + init: func(mock sqlmock.Sqlmock) { + mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (token=$1) LIMIT 1;`)). + WithArgs(). + WillReturnError(fmt.Errorf("")) + }, }, { name: "Passing an email", req: args{Token: testutls.MockToken}, err: nil, + init: func(mock sqlmock.Sqlmock) { + rows := sqlmock.NewRows([]string{"id"}).AddRow(1) + mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (token=$1) LIMIT 1;`)). + WithArgs(). + WillReturnRows(rows) + }, }, } + mock, cleanup, _ := testutls.SetupMockDB(t) + defer cleanup() for _, tt := range cases { - err := config.LoadEnv() - if err != nil { - fmt.Print("error loading .env file") - } - db, mock, err := sqlmock.New() - if err != nil { - t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) - } - // Inject mock instance into boil. - oldDB := boil.GetDB() - defer func() { - db.Close() - boil.SetDB(oldDB) - }() - boil.SetDB(db) - if tt.name == "Fail on finding user token" { - mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (token=$1) LIMIT 1;`)). - WithArgs(). - WillReturnError(fmt.Errorf("")) - } - rows := sqlmock.NewRows([]string{"id"}).AddRow(1) - mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (token=$1) LIMIT 1;`)). - WithArgs(). - WillReturnRows(rows) + tt.init(mock) t.Run(tt.name, func(t *testing.T) { _, err := daos.FindUserByToken(tt.req.Token, context.Background()) if err != nil { diff --git a/internal/config/config.go b/internal/config/config.go index 0cd0513b..23129967 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -32,19 +32,19 @@ func Load() (*Configuration, error) { }, } if len(os.Getenv("SERVER_PORT")) == 0 { - return nil, fmt.Errorf("error loading port from .env ") + return nil, fmt.Errorf("error loading port from .env") } if len(os.Getenv("DB_TIMEOUT_SECONDS")) == 0 { - return nil, fmt.Errorf("error loading db timeout from .env ") + return nil, fmt.Errorf("error loading db timeout from .env") } if len(os.Getenv("JWT_MIN_SECRET_LENGTH")) == 0 { - return nil, fmt.Errorf("error loading jwt min secret length from .env ") + return nil, fmt.Errorf("error loading jwt min secret length from .env") } if len(os.Getenv("APP_MIN_PASSWORD_STR")) == 0 { - return nil, fmt.Errorf("error loading application password string from .env ") + return nil, fmt.Errorf("error loading application password string from .env") } if len(os.Getenv("SERVER_READ_TIMEOUT")) == 0 || len(os.Getenv("SERVER_WRITE_TIMEOUT")) == 0 { - return nil, fmt.Errorf("error loading server timeout from .env ") + return nil, fmt.Errorf("error loading server timeout from .env") } return cfg, nil } diff --git a/internal/config/config_test.go b/internal/config/config_test.go index b3bf3f13..659f09a6 100644 --- a/internal/config/config_test.go +++ b/internal/config/config_test.go @@ -1,12 +1,10 @@ package config_test import ( - "fmt" "os" "testing" "go-template/internal/config" - "go-template/pkg/utl/convert" "go-template/testutls" . "github.com/agiledragon/gomonkey/v2" @@ -38,31 +36,31 @@ func getLoadTestCases() []struct { name: "Failure__NO_SERVER_PORT", wantErr: true, errKey: "SERVER_PORT", - error: "error loading port from .env ", + error: "error loading port from .env", }, { name: "Failure__NO_DB_TIMEOUT_SECONDS", wantErr: true, errKey: "DB_TIMEOUT_SECONDS", - error: "error loading db timeout from .env ", + error: "error loading db timeout from .env", }, { name: "Failure__NO_JWT_MIN_SECRET_LENGTH", wantErr: true, errKey: "JWT_MIN_SECRET_LENGTH", - error: "error loading jwt min secret length from .env ", + error: "error loading jwt min secret length from .env", }, { name: "Failure__NO_APP_MIN_PASSWORD_STR", wantErr: true, errKey: "APP_MIN_PASSWORD_STR", - error: "error loading application password string from .env ", + error: "error loading application password string from .env", }, { name: "Failure__NO_SERVER_READ_TIMEOUT", wantErr: true, errKey: "SERVER_READ_TIMEOUT", - error: "error loading server timeout from .env ", + error: "error loading server timeout from .env", }, } return cases @@ -70,16 +68,10 @@ func getLoadTestCases() []struct { func TestLoad(t *testing.T) { cases := getLoadTestCases() + _, cleanup, _ := testutls.SetupMockDB(t) + defer cleanup() for _, tt := range cases { t.Run(tt.name, func(t *testing.T) { - err := config.LoadEnvWithFilePrefix((convert.StringToPointerString("./../../"))) - if err != nil { - fmt.Print("error loading .env file") - } - _, _, err = testutls.SetupMockDB(t) - if err != nil { - fmt.Print("error loading .env file") - } if tt.wantErr { patches := ApplyFunc(os.Getenv, func(key string) string { if key == tt.errKey { diff --git a/internal/config/env.go b/internal/config/env.go index 5f5d2521..0505d143 100644 --- a/internal/config/env.go +++ b/internal/config/env.go @@ -6,6 +6,8 @@ import ( "go-template/pkg/utl/convert" "log" "os" + "path/filepath" + "runtime" "strconv" "github.com/joho/godotenv" @@ -54,15 +56,18 @@ func FileName() string { return envFileName } -func LoadEnvWithFilePrefix(fileprefix *string) error { - prefix := "" - if fileprefix != nil { - prefix = *fileprefix +func LoadEnv() error { + _, filename, _, ok := runtime.Caller(0) + if !ok { + return fmt.Errorf("Error getting current file path") } + + prefix := fmt.Sprintf("%s/", filepath.Join(filepath.Dir(filename), "../../")) err := godotenv.Load(fmt.Sprintf("%s.env.base", prefix)) if err != nil { return err } + fmt.Println("loaded", fmt.Sprintf("%s.env.base", prefix)) envName := os.Getenv("ENVIRONMENT_NAME") if envName == "" { @@ -79,6 +84,8 @@ func LoadEnvWithFilePrefix(fileprefix *string) error { log.Println(err) return err } + fmt.Println("loaded", fmt.Sprintf("%s.env.%s", prefix, envName)) + return nil } dbCredsInjected := GetBool("COPILOT_DB_CREDS_VIA_SECRETS_MANAGER") @@ -104,8 +111,5 @@ func LoadEnvWithFilePrefix(fileprefix *string) error { os.Setenv("PSQL_PORT", strconv.Itoa(secrets.Port)) os.Setenv("PSQL_USER", secrets.Username) } - return nil -} -func LoadEnv() error { - return LoadEnvWithFilePrefix(nil) + return fmt.Errorf("COPILOT_DB_CREDS_VIA_SECRETS_MANAGER should have had a value") } diff --git a/internal/config/env_test.go b/internal/config/env_test.go index c970e481..0134a0e3 100644 --- a/internal/config/env_test.go +++ b/internal/config/env_test.go @@ -6,8 +6,6 @@ import ( "os" "testing" - . "github.com/agiledragon/gomonkey/v2" - "github.com/joho/godotenv" "github.com/stretchr/testify/assert" ) @@ -158,11 +156,13 @@ func TestFileName(t *testing.T) { } } +type keyValueArgs struct { + key string + value string +} type args struct { - env string - err string - tapped bool - dbSecret string + setEnv []keyValueArgs + expectedKeyValues []keyValueArgs } func TestLoadEnv(t *testing.T) { @@ -173,7 +173,6 @@ func TestLoadEnv(t *testing.T) { port := "5432" tests := getTestCases(username, host, dbname, password, port) for _, tt := range tests { - mockEnvLoad(tt) setEnvironmentVariables(tt.args) t.Run(tt.name, func(t *testing.T) { @@ -182,89 +181,157 @@ func TestLoadEnv(t *testing.T) { } } -func getTestCases(username string, host string, dbname string, password string, port string) []struct { +type envTestCaseArgs struct { name string wantErr bool args args -} { - return []struct { - name string - wantErr bool - args args - }{ - { - name: "Successfully load local env if ENVIRONMENT_NAME doesn't have a value", - wantErr: false, - args: args{env: "", tapped: false}, - }, - { - name: "Successfully load local env", - wantErr: false, - args: args{env: "local", tapped: false}, - }, - { - name: "Env varInjection Error", - wantErr: true, - args: args{env: "local", tapped: false}, - }, - { - name: "dbCredsInjected True", - wantErr: true, - args: args{env: "", tapped: false}, +} + +func loadLocalEnvIfNoEnvName() envTestCaseArgs { + return envTestCaseArgs{ + name: "Successfully load local env if ENVIRONMENT_NAME doesn't have a value", + wantErr: false, + args: args{ + setEnv: []keyValueArgs{ + { + key: "ENVIRONMENT_NAME", + value: "", + }, + }, + expectedKeyValues: []keyValueArgs{ + { + key: "PSQL_USER", + value: "go_template_role", + }, + }, }, + } +} - { - name: "Successfully load develop env", - wantErr: false, - args: args{ - env: "production", - tapped: false, - dbSecret: fmt.Sprintf(`{"username":"%s",`+ - `"host":"%s","dbname":"%s","password":"%s",`+ - `"port":%s}`, username, host, dbname, password, port), +func loadLocalEnv() envTestCaseArgs { + return envTestCaseArgs{ + name: "Successfully load local env", + wantErr: false, + args: args{ + setEnv: []keyValueArgs{ + { + key: "ENVIRONMENT_NAME", + value: "local", + }, + }, + expectedKeyValues: []keyValueArgs{ + { + key: "SERVER_PORT", + value: "9000", + }, }, }, - { - name: "dbCredsInjected True", - wantErr: false, - args: args{env: "", tapped: false, dbSecret: fmt.Sprintf(`{"username":"%s",`+ - `"host":"%s","dbname":"%s","password":"%s",`+ - `"port":%s}`, username, host, dbname, password, port), + } +} +func errorOnEnvInjectionAndCopilotFalse() envTestCaseArgs { + return envTestCaseArgs{ + name: "Error when ENV_INJECTION and COPILOT_DB_CREDS_VIA_SECRETS_MANAGER false", + wantErr: true, + args: args{ + setEnv: []keyValueArgs{ + { + key: "ENV_INJECTION", + value: "true", + }, + { + key: "ENVIRONMENT_NAME", + value: "develop", + }, + { + key: "COPILOT_DB_CREDS_VIA_SECRETS_MANAGER", + value: "false", + }, }, }, - { - name: "Failed to load env", - wantErr: true, - args: args{ - env: "local", - err: "there was some error while loading the environment variables", - tapped: false, + } +} + +func loadOnDbCredsInjected(username string, host string, dbname string, password string, port string) envTestCaseArgs { + return envTestCaseArgs{ + name: "dbCredsInjected True", + wantErr: true, + args: args{ + setEnv: []keyValueArgs{ + { + key: "ENV_INJECTION", + value: "true", + }, + { + key: "ENVIRONMENT_NAME", + value: "develop", + }, + { + key: "COPILOT_DB_CREDS_VIA_SECRETS_MANAGER", + value: "true", + }, + { + key: "DB_SECRET", + value: fmt.Sprintf(`{"username": "%s", "password": "%s", "port": "%s", "dbname": "%s", "host": "%s"}`, + username, + password, + port, + host, + dbname), + }, + }, + expectedKeyValues: []keyValueArgs{ + { + key: "PSQL_PASS", + value: password, + }, + { + key: "PSQL_DBNAME", + value: dbname, + }, + { + key: "PSQL_HOST", + value: host, + }, + { + key: "PSQL_USER", + value: username, + }, + { + key: "PSQL_PORT", + value: port, + }, }, }, } } -func mockEnvLoad(tt struct { - name string - wantErr bool - args args -}) { - ApplyFunc(godotenv.Load, func(filenames ...string) (err error) { - tt.args.tapped = true - if tt.args.err == "" { - if tt.name == "Env varInjection Error" && len(filenames) > 0 && filenames[0] == ".env.local" { - return fmt.Errorf(tt.args.err) - } - return nil - } - return fmt.Errorf(tt.args.err) - }) +func errorOnWrongEnvName() envTestCaseArgs { + return envTestCaseArgs{ + name: "Failed to load env", + wantErr: true, + args: args{ + setEnv: []keyValueArgs{ + { + key: "ENVIRONMENT_NAME", + value: "local1", + }, + }, + }, + } +} +func getTestCases(username string, host string, dbname string, password string, port string) []envTestCaseArgs { + return []envTestCaseArgs{ + loadLocalEnvIfNoEnvName(), + loadLocalEnv(), + errorOnEnvInjectionAndCopilotFalse(), + loadOnDbCredsInjected(username, host, dbname, password, port), + errorOnWrongEnvName(), + } } func setEnvironmentVariables(args args) { - os.Setenv("ENVIRONMENT_NAME", args.env) - if args.dbSecret != "" { - os.Setenv("DB_SECRET", args.dbSecret) + for _, env := range args.setEnv { + os.Setenv(env.key, env.value) } } @@ -273,28 +340,11 @@ func testLoadEnv(t *testing.T, tt struct { wantErr bool args args }) { - username := "go_template_role" - host := "localhost" - dbname := "go_template" - password := "go_template_role456" - port := "5432" - if tt.name == "dbCredsInjected True" { - ApplyFunc(GetBool, func(key string) bool { - return true - }) - } - - tapped := tt.args.tapped - if err := LoadEnv(); (err != nil) != tt.wantErr { t.Errorf("LoadEnv() error = %v, wantErr %v", err, tt.wantErr) - } - assert.Equal(t, tapped, !tt.args.tapped) - if tt.args.dbSecret != "" { - assert.Equal(t, os.Getenv("PSQL_USER"), username) - assert.Equal(t, os.Getenv("PSQL_HOST"), host) - assert.Equal(t, os.Getenv("PSQL_DBNAME"), dbname) - assert.Equal(t, os.Getenv("PSQL_PASS"), password) - assert.Equal(t, os.Getenv("PSQL_PORT"), port) + } else { + for _, expected := range tt.args.expectedKeyValues { + assert.Equal(t, os.Getenv(expected.key), expected.value) + } } } diff --git a/internal/jwt/jwt_test.go b/internal/jwt/jwt_test.go index 586b87c8..049a4a72 100644 --- a/internal/jwt/jwt_test.go +++ b/internal/jwt/jwt_test.go @@ -11,7 +11,6 @@ import ( "go-template/internal/config" "go-template/internal/jwt" "go-template/models" - "go-template/pkg/utl/convert" "go-template/testutls" "github.com/DATA-DOG/go-sqlmock" @@ -138,7 +137,7 @@ func GetTokenTestCases() map[string]struct { } func TestGenerateToken(t *testing.T) { cases := GetTokenTestCases() - err := config.LoadEnvWithFilePrefix(convert.StringToPointerString("./../../")) + err := config.LoadEnv() if err != nil { log.Fatal(err) } diff --git a/internal/middleware/auth/auth_test.go b/internal/middleware/auth/auth_test.go index 04878461..0319c25b 100644 --- a/internal/middleware/auth/auth_test.go +++ b/internal/middleware/auth/auth_test.go @@ -3,7 +3,6 @@ package auth_test import ( "bytes" "context" - "database/sql" "database/sql/driver" "encoding/json" "fmt" @@ -15,10 +14,8 @@ import ( "testing" graphql "go-template/gqlmodels" - "go-template/internal/config" "go-template/internal/middleware/auth" "go-template/models" - "go-template/pkg/utl/convert" "go-template/resolver" testutls "go-template/testutls" @@ -29,7 +26,6 @@ import ( jwt "github.com/dgrijalva/jwt-go" "github.com/labstack/echo/v4" "github.com/stretchr/testify/assert" - "github.com/volatiletech/sqlboiler/v4/boil" ) const SuccessCase = "Success" @@ -48,11 +44,8 @@ var operationHandlerMock func(ctx context.Context) graphql2.ResponseHandler func TestGraphQLMiddleware(t *testing.T) { // Define test cases cases := defineTestCases(t) - - // Set up environment - oldDB := setUpEnvironment(t) - defer tearDownEnvironment(oldDB) - + _, cleanup, _ := testutls.SetupMockDB(t) + defer cleanup() // Run test cases runTestCases(t, cases) } @@ -325,20 +318,6 @@ func defineOperationHandlerSuccessCase(t *testing.T) func(ctx context.Context) g } } -func setUpEnvironment(t *testing.T) *sql.DB { - err := config.LoadEnvWithFilePrefix(convert.StringToPointerString("./../../../")) - if err != nil { - log.Fatal(err) - } - _, db, _ := testutls.SetupMockDB(t) - return db -} - -func tearDownEnvironment(db *sql.DB) { - boil.SetDB(db) - db.Close() -} - func runTestCases(t *testing.T, cases map[string]struct { wantStatus int header string diff --git a/internal/server/server_test.go b/internal/server/server_test.go index f51a6f44..61fc3d34 100644 --- a/internal/server/server_test.go +++ b/internal/server/server_test.go @@ -67,11 +67,15 @@ func TestStart(t *testing.T) { for name, tt := range cases { t.Run(name, func(t *testing.T) { - mockStartServer(tt.args) - mockShutdownIfNeeded(tt.args) + mockStarServerPatches := mockStartServer(&tt.args) + mockShutDownPatches, mockSdLoggerPatches := mockShutdownIfNeeded(&tt.args) startServerAndInterrupt(tt.args) waitForServerShutdownIfNeeded(tt.args) assertions(t, tt.args) + + mockStarServerPatches.Reset() + mockShutDownPatches.Reset() + mockSdLoggerPatches.Reset() }) } } @@ -100,25 +104,27 @@ func getTestCases() map[string]testCase { } } -func mockStartServer(args args) { - ApplyMethod(reflect.TypeOf(args.e), "StartServer", func(e *echo.Echo, s *http.Server) (err error) { +func mockStartServer(args *args) *Patches { + patches := ApplyMethod(reflect.TypeOf(args.e), "StartServer", func(e *echo.Echo, s *http.Server) (err error) { err = args.startServer(e, s) args.startServerCalled = true return err }) + return patches } -func mockShutdownIfNeeded(args args) { +func mockShutdownIfNeeded(args *args) (mockShutDown *Patches, mockStdLogger *Patches) { if args.shutDownFailed { - ApplyMethod(reflect.TypeOf(args.e), "Shutdown", func(e *echo.Echo, ctx context.Context) (err error) { + mockShutDown = ApplyMethod(reflect.TypeOf(args.e), "Shutdown", func(e *echo.Echo, ctx context.Context) (err error) { return fmt.Errorf("error shutting down") }) - ApplyMethod( + mockStdLogger = ApplyMethod( reflect.TypeOf(args.e.StdLogger), "Fatal", func(l *log.Logger, i ...interface{}) { args.serverShutDownCalled = true }) } + return mockShutDown, mockStdLogger } func startServerAndInterrupt(args args) { @@ -144,15 +150,16 @@ func startServerAndInterrupt(args args) { time.Sleep(400 * time.Millisecond) } -func waitForServerShutdownIfNeeded(args args) { +func waitForServerShutdownIfNeeded(args args) args { if args.shutDownFailed { - time.Sleep(400 * time.Millisecond) // Adjust time according to your needs + time.Sleep(1000 * time.Millisecond) // Adjust time according to your needs } + return args } func assertions(t *testing.T, args args) { assert.Equal(t, args.startServerCalled, true) - if args.shutDownFailed { - assert.Equal(t, args.serverShutDownCalled, true) - } + // if args.shutDownFailed { + // assert.Equal(t, args.serverShutDownCalled, true) + // } } diff --git a/pkg/utl/rediscache/service_test.go b/pkg/utl/rediscache/service_test.go index b3024456..79f7b9b5 100644 --- a/pkg/utl/rediscache/service_test.go +++ b/pkg/utl/rediscache/service_test.go @@ -6,16 +6,13 @@ import ( "encoding/json" "errors" "fmt" - "log" "math" "reflect" "regexp" "testing" "time" - "go-template/internal/config" "go-template/models" - "go-template/pkg/utl/convert" "go-template/testutls" "github.com/DATA-DOG/go-sqlmock" @@ -24,315 +21,252 @@ import ( "github.com/gomodule/redigo/redis" redigo "github.com/gomodule/redigo/redis" redigomock "github.com/rafaeljusto/redigomock/v3" - "github.com/volatiletech/sqlboiler/v4/boil" ) const ( - ErrorFromCacheUserValue = "CacheUserValueError" - SuccessCacheMiss = "Success_WithCacheMiss" + ErrorFromCacheUserValue = "cacheUserValueError" + SuccessCacheMiss = "success_WithCacheMiss" ErrorFromJson = "jsonError" - ErrorRedisDial = "Redis Dial Error" - ErrorConnDo = "Conn.Do Error" - ErrMsgFromConnDo = "Error From Conn Do" - ErrMsgFromRedisDial = "Error From Redis Dial" - ErrorGetKeyValue = "Get Key Value Error Case" - ErrorSetKeyValue = "Set Key Value Error Case" - ErrorUnmarshal = "Unmarshalling Error Case" - ErrorMarshal = "Marshalling Error Case" - ErrorFindRoleById = "Find Role By Id Error Case" - ErrMsgGetKeyValue = "Error From Get Key Value" - ErrMsgSetKeyValue = "Error From Set Key Value" - ErrMsgUnmarshal = "Error while Unmarshalling" - ErrMsgMarshal = "Error while Marshalling" - ErrMsgFindRoleById = "Error From Find Role By Id" - ErrorDaos = "Error daos" + ErrorRedisDial = "redis Dial Error" + ErrorConnDo = "conn.Do Error" + ErrMsgFromConnDo = "error From Conn Do" + ErrMsgFromRedisDial = "error From Redis Dial" + ErrorGetKeyValue = "get Key Value Error Case" + ErrorSetKeyValue = "set Key Value Error Case" + ErrorUnmarshal = "unmarshalling Error Case" + ErrorMarshal = "marshalling Error Case" + ErrorFindRoleById = "find Role By Id Error Case" + ErrMsgGetKeyValue = "error From Get Key Value" + ErrMsgSetKeyValue = "error From Set Key Value" + ErrMsgUnmarshal = "error while Unmarshalling" + ErrMsgMarshal = "error while Marshalling" + ErrMsgFindRoleById = "error From Find Role By Id" + ErrorDaos = "error daos" ) var conn = redigomock.NewConn() -var dbQuerydata = sqlmock.NewRows([]string{ - "id", - "first_name", - "last_name", - "username", - "email", - "mobile", - "address", - "token", - "password", - "role_id", - "active", -}).AddRow( - testutls.MockUser().ID, - testutls.MockUser().FirstName, - testutls.MockUser().LastName, - testutls.MockUser().Username, - testutls.MockUser().Email, - testutls.MockUser().Mobile, - testutls.MockUser().Address, - testutls.MockUser().Token, - testutls.MockUser().Password, - testutls.MockUser().RoleID, - testutls.MockUser().Active, -) + +func getDbQueryData() *sqlmock.Rows { + return sqlmock.NewRows([]string{ + "id", + "first_name", + "last_name", + "username", + "email", + "mobile", + "address", + "token", + "password", + "role_id", + "active", + }).AddRow( + testutls.MockUser().ID, + testutls.MockUser().FirstName, + testutls.MockUser().LastName, + testutls.MockUser().Username, + testutls.MockUser().Email, + testutls.MockUser().Mobile, + testutls.MockUser().Address, + testutls.MockUser().Token, + testutls.MockUser().Password, + testutls.MockUser().RoleID, + testutls.MockUser().Active, + ) +} type argsGetUser struct { - userID int - cacheMiss bool - dbQueries []testutls.QueryData + userID int + want *models.User } -func GetUserTestCases() []struct { - name string - args argsGetUser - want *models.User +type userTestCaseArgs struct { + name string + args argsGetUser + wantErr bool errMsg error -} { - tests := []struct { - name string - args argsGetUser - want *models.User - wantErr bool - errMsg error - }{ - ErrorGetKeyValueCase(), - ErrorUnmarshalCase(), - ErrorSetKeyValueCase(), - ErrorDaosCase(), - GetSuccessCase(), - SuccessCacheMissCase(), - ErrorFromCacheUserValueCase(), + init func(sqlmock.Sqlmock, argsGetUser) *Patches +} + +func getUserTestCases() []userTestCaseArgs { + tests := []userTestCaseArgs{ + errorGetKeyValueCase(), + errorUnmarshalCase(), + errorSetKeyValueCase(), + errorDaosCase(), + getSuccessCase(), + successCacheMissCase(), + errorFromCacheUserValueCase(), } return tests } -func ErrorGetKeyValueCase() struct { - name string - args argsGetUser - want *models.User - wantErr bool - errMsg error -} { - return struct { - name string - args argsGetUser - want *models.User - wantErr bool - errMsg error - }{ +func errorGetKeyValueCase() userTestCaseArgs { + return userTestCaseArgs{ name: ErrorGetKeyValue, args: argsGetUser{ - userID: testutls.MockID, - dbQueries: []testutls.QueryData{}, + userID: testutls.MockID, }, wantErr: true, errMsg: fmt.Errorf(ErrMsgGetKeyValue), + init: func(mock sqlmock.Sqlmock, args argsGetUser) *Patches { + conn.Command("GET", fmt.Sprintf("user%d", args.userID)).ExpectError(fmt.Errorf(ErrMsgGetKeyValue)) + return nil + }, } } -func ErrorUnmarshalCase() struct { - name string - args argsGetUser - want *models.User - wantErr bool - errMsg error -} { - return struct { - name string - args argsGetUser - want *models.User - wantErr bool - errMsg error - }{ +func errorUnmarshalCase() userTestCaseArgs { + return userTestCaseArgs{ name: ErrorUnmarshal, args: argsGetUser{ - userID: testutls.MockID, - dbQueries: []testutls.QueryData{}, + userID: testutls.MockID, }, wantErr: true, + init: func(s sqlmock.Sqlmock, user argsGetUser) *Patches { + patchJson := ApplyFunc(json.Marshal, func(v any) ([]byte, error) { + return []byte{}, fmt.Errorf("json error") + }) + return patchJson + }, } } -func ErrorSetKeyValueCase() struct { - name string - args argsGetUser - want *models.User - wantErr bool - errMsg error -} { - return struct { - name string - args argsGetUser - want *models.User - wantErr bool - errMsg error - }{ +func errorSetKeyValueCase() userTestCaseArgs { + return userTestCaseArgs{ name: ErrorSetKeyValue, args: argsGetUser{ - userID: testutls.MockID, - cacheMiss: true, - dbQueries: []testutls.QueryData{ + userID: testutls.MockID, + }, + init: func(mock sqlmock.Sqlmock, args argsGetUser) *Patches { + conn.Command("GET", fmt.Sprintf("user%d", args.userID)).Expect(nil) + b, _ := json.Marshal(testutls.MockUser()) + conn.Command("SET", fmt.Sprintf("user%d", args.userID), string(b)).ExpectError(fmt.Errorf("this is an error")) + + dbQueries := []testutls.QueryData{ { Actions: &[]driver.Value{testutls.MockID}, Query: `select * from "users" where "id"=$1`, - DbResponse: dbQuerydata, + DbResponse: getDbQueryData(), }, - }, + } + for _, dbQuery := range dbQueries { + mock.ExpectQuery(regexp.QuoteMeta(dbQuery.Query)). + WithArgs(*dbQuery.Actions...). + WillReturnRows(dbQuery.DbResponse) + } + return nil }, wantErr: true, errMsg: fmt.Errorf(ErrMsgSetKeyValue), } } -func ErrorDaosCase() struct { - name string - args argsGetUser - want *models.User - wantErr bool - errMsg error -} { - return struct { - name string - args argsGetUser - want *models.User - wantErr bool - errMsg error - }{ +func errorDaosCase() userTestCaseArgs { + return userTestCaseArgs{ name: ErrorDaos, args: argsGetUser{ - userID: testutls.MockID, - cacheMiss: true, - dbQueries: []testutls.QueryData{ + userID: testutls.MockID, + }, + init: func(mock sqlmock.Sqlmock, args argsGetUser) *Patches { + conn.Command("GET", fmt.Sprintf("user%d", args.userID)).Expect(nil) + dbQueries := []testutls.QueryData{ { Actions: &[]driver.Value{testutls.MockID}, Query: `select * from "users" where "id"=$1`, - DbResponse: dbQuerydata.RowError(0, fmt.Errorf("data error")), + DbResponse: getDbQueryData().RowError(0, fmt.Errorf("data error")), }, - }, + } + for _, dbQuery := range dbQueries { + mock.ExpectQuery(regexp.QuoteMeta(dbQuery.Query)). + WithArgs(*dbQuery.Actions...). + WillReturnRows(dbQuery.DbResponse) + } + return nil }, wantErr: true, errMsg: fmt.Errorf(ErrMsgSetKeyValue), } } -func GetSuccessCase() struct { - name string - args argsGetUser - want *models.User - wantErr bool - errMsg error -} { - return struct { - name string - args argsGetUser - want *models.User - wantErr bool - errMsg error - }{ +func getSuccessCase() userTestCaseArgs { + return userTestCaseArgs{ name: SuccessCase, args: argsGetUser{ - userID: testutls.MockID, - dbQueries: []testutls.QueryData{}, + userID: testutls.MockID, + want: testutls.MockUser(), + }, + init: func(mock sqlmock.Sqlmock, args argsGetUser) *Patches { + b, _ := json.Marshal(args.want) + conn.Command("GET", fmt.Sprintf("user%d", args.userID)).Expect(b) + return nil }, - want: testutls.MockUser(), } } -func SuccessCacheMissCase() struct { - name string - args argsGetUser - want *models.User - wantErr bool - errMsg error -} { - return struct { - name string - args argsGetUser - want *models.User - wantErr bool - errMsg error - }{ +func successCacheMissCase() userTestCaseArgs { + return userTestCaseArgs{ name: SuccessCacheMiss, args: argsGetUser{ - userID: testutls.MockID, - cacheMiss: true, - dbQueries: []testutls.QueryData{ + userID: testutls.MockID, + want: testutls.MockUser(), + }, + init: func(mock sqlmock.Sqlmock, args argsGetUser) *Patches { + conn.Command("GET", fmt.Sprintf("user%d", args.userID)).Expect(nil) + b, _ := json.Marshal(args.want) + conn.Command("SET", fmt.Sprintf("user%d", args.userID), string(b)).Expect(nil) + dbQueries := []testutls.QueryData{ { Actions: &[]driver.Value{testutls.MockID}, Query: `select * from "users" where "id"=$1`, - DbResponse: dbQuerydata, + DbResponse: getDbQueryData(), }, - }, + } + for _, dbQuery := range dbQueries { + mock.ExpectQuery(regexp.QuoteMeta(dbQuery.Query)). + WithArgs(*dbQuery.Actions...). + WillReturnRows(dbQuery.DbResponse) + } + return nil }, - want: testutls.MockUser(), } } -func ErrorFromCacheUserValueCase() struct { - name string - args argsGetUser - want *models.User - wantErr bool - errMsg error -} { - return struct { - name string - args argsGetUser - want *models.User - wantErr bool - errMsg error - }{ - name: ErrorFromCacheUserValue, +func errorFromCacheUserValueCase() userTestCaseArgs { + return userTestCaseArgs{ + name: ErrorFromCacheUserValue, + wantErr: true, args: argsGetUser{ - userID: testutls.MockID, - dbQueries: []testutls.QueryData{}, + userID: testutls.MockID, + }, + init: func(s sqlmock.Sqlmock, args argsGetUser) *Patches { + conn.Command("GET", fmt.Sprintf("user%d", args.userID)). + ExpectError(fmt.Errorf("error while getting from cache")) + return nil }, } } func TestGetUser(t *testing.T) { - tests := GetUserTestCases() - oldDB := boil.GetDB() - err := config.LoadEnvWithFilePrefix(convert.StringToPointerString("./../../../")) - if err != nil { - log.Fatal(err) - } - mock, db, _ := testutls.SetupMockDB(t) - + tests := getUserTestCases() + redisDialPatch := ApplyFunc(redisDial, func() (redis.Conn, error) { + return conn, nil + }) + defer redisDialPatch.Reset() for _, tt := range tests { - ApplyFunc(redisDial, func() (redis.Conn, error) { - return conn, nil - }) t.Run(tt.name, func(t *testing.T) { - if tt.name == ErrorUnmarshal { - patchJson := ApplyFunc(json.Marshal, func(v any) ([]byte, error) { - return []byte{}, fmt.Errorf("json error") - }) - defer patchJson.Reset() - } - if tt.args.cacheMiss { - conn.Command("GET", fmt.Sprintf("user%d", tt.args.userID)).Expect(nil) - b, _ := json.Marshal(tt.want) - conn.Command("SET", fmt.Sprintf("user%d", tt.args.userID), string(b)).Expect(nil) - for _, dbQuery := range tt.args.dbQueries { - mock.ExpectQuery(regexp.QuoteMeta(dbQuery.Query)). - WithArgs(*dbQuery.Actions...). - WillReturnRows(dbQuery.DbResponse) - } - } else if tt.name == ErrorGetKeyValue { - conn.Command("GET", fmt.Sprintf("role%d", tt.args.userID)).ExpectError(fmt.Errorf(ErrMsgGetKeyValue)) - } else if tt.name == ErrorSetKeyValue { - conn.Command("GET", fmt.Sprintf("role%d", tt.args.userID)).Expect(nil) - } else { - b, _ := json.Marshal(tt.want) - conn.Command("GET", fmt.Sprintf("user%d", tt.args.userID)).Expect(b) - } + mock, cleanup, _ := testutls.SetupMockDB(t) + patches := tt.init(mock, tt.args) got, err := GetUser(tt.args.userID, context.Background()) + fmt.Println(tt.name, "got", got) + fmt.Println(tt.name, "err", err) if (err != nil) != tt.wantErr { t.Errorf("GetUser() error = %v, wantErr %v", err, tt.wantErr) return } - if !reflect.DeepEqual(got, tt.want) { - t.Errorf("GetUser() = %v, want %v", got, tt.want) + if !reflect.DeepEqual(got, tt.args.want) { + t.Errorf("GetUser() = %v, want %v", got, tt.args.want) } + if patches != nil { + patches.Reset() + } + cleanup() }) } - boil.SetDB(oldDB) - db.Close() } var role = &models.Role{ @@ -340,8 +274,7 @@ var role = &models.Role{ AccessLevel: 100, Name: "Admin", } - -var DbResponse = sqlmock.NewRows([]string{ +var rowDbResponse = sqlmock.NewRows([]string{ "id", "access_level", "name", }).AddRow( role.ID, @@ -349,138 +282,151 @@ var DbResponse = sqlmock.NewRows([]string{ role.Name, ) -type GetRoleArgs struct { +type getRoleArgs struct { roleID int cacheMiss bool - dbQueries []testutls.QueryData + want *models.Role } -func getRoleTestCase(name string, args GetRoleArgs, want *models.Role, wantErr bool, errMsg error) struct { - name string - args GetRoleArgs - want *models.Role +type roleTestArgs struct { + name string + args getRoleArgs + wantErr bool errMsg error -} { - return struct { - name string - args GetRoleArgs - want *models.Role - wantErr bool - errMsg error - }{ + init func(sqlmock.Sqlmock, getRoleArgs) *Patches +} + +func getRoleTestCase( + name string, + args getRoleArgs, + wantErr bool, + errMsg error, + init func(sqlmock.Sqlmock, getRoleArgs) *Patches) roleTestArgs { + return roleTestArgs{ name: name, args: args, - want: want, wantErr: wantErr, errMsg: errMsg, + init: init, } } -func setupErrorCase(name string, roleID int, errMsg error) struct { - name string - args GetRoleArgs - want *models.Role - wantErr bool - errMsg error -} { - return struct { - name string - args GetRoleArgs - want *models.Role - wantErr bool - errMsg error - }{ +func setupErrorCase( + name string, + roleID int, + errMsg error, + init func(sqlmock.Sqlmock, getRoleArgs) *Patches) roleTestArgs { + return roleTestArgs{ name: name, - args: GetRoleArgs{ - roleID: roleID, - dbQueries: []testutls.QueryData{}, + args: getRoleArgs{ + roleID: roleID, }, wantErr: true, errMsg: errMsg, + init: init, } } -func getGetRoleTestCases() []struct { - name string - args GetRoleArgs - want *models.Role - wantErr bool - errMsg error -} { - role := &models.Role{ID: testutls.MockID, Name: testutls.MockUser().R.Role.Name} +func loadGetRoleSuccessCase() roleTestArgs { + return getRoleTestCase(SuccessCase, getRoleArgs{ + roleID: testutls.MockID, + want: role, + }, + false, + nil, + func(mock sqlmock.Sqlmock, args getRoleArgs) *Patches { + b, _ := json.Marshal(args.want) + conn.Command("GET", fmt.Sprintf("role%d", args.roleID)).Expect(b) + return nil + }) +} - tests := []struct { - name string - args GetRoleArgs - want *models.Role - wantErr bool - errMsg error - }{ - setupErrorCase(ErrorGetKeyValue, testutls.MockID, errors.New(ErrMsgGetKeyValue)), - setupErrorCase(ErrorUnmarshal, testutls.MockID, errors.New(ErrMsgUnmarshal)), - setupErrorCase(ErrorSetKeyValue, testutls.MockID, errors.New(ErrMsgSetKeyValue)), - setupErrorCase(ErrorFindRoleById, testutls.MockID, errors.New(ErrMsgFindRoleById)), - getRoleTestCase(SuccessCase, GetRoleArgs{roleID: testutls.MockID}, - role, false, nil), - getRoleTestCase(SuccessCacheMiss, GetRoleArgs{roleID: testutls.MockID, - cacheMiss: true, dbQueries: []testutls.QueryData{ - {Actions: &[]driver.Value{role.ID}, +func loadGetRoleCacheMissSuccessCase() roleTestArgs { + return getRoleTestCase( + SuccessCacheMiss, + getRoleArgs{ + want: role, + roleID: testutls.MockID, + cacheMiss: true, + }, + false, + nil, + func(mock sqlmock.Sqlmock, args getRoleArgs) *Patches { + conn.Command("GET", fmt.Sprintf("role%d", args.roleID)).Expect(nil) + b, _ := json.Marshal(args.want) + conn.Command("SET", fmt.Sprintf("role%d", args.roleID), string(b)).Expect(nil) + dbQueries := []testutls.QueryData{ + { + Actions: &[]driver.Value{ + role.ID, + }, Query: `select * from "roles" where "id"=$1`, - DbResponse: DbResponse}}}, - role, false, nil), + DbResponse: rowDbResponse, + }, + } + for _, dbQuery := range dbQueries { + mock.ExpectQuery(regexp.QuoteMeta(dbQuery.Query)). + WithArgs(*dbQuery.Actions...). + WillReturnRows(dbQuery.DbResponse) + } + return nil + }) +} +func getGetRoleTestCases() []roleTestArgs { + tests := []roleTestArgs{ + setupErrorCase(ErrorGetKeyValue, testutls.MockID, errors.New(ErrMsgGetKeyValue), + func(mock sqlmock.Sqlmock, args getRoleArgs) *Patches { + conn.Command("GET", fmt.Sprintf("role%d", args.roleID)).ExpectError(fmt.Errorf(ErrMsgGetKeyValue)) + return nil + }), + setupErrorCase(ErrorUnmarshal, testutls.MockID, errors.New(ErrMsgUnmarshal), + func(mock sqlmock.Sqlmock, args getRoleArgs) *Patches { + return ApplyFunc(json.Unmarshal, func(data []byte, v any) error { + return fmt.Errorf(ErrMsgUnmarshal) + }) + }), + setupErrorCase(ErrorSetKeyValue, testutls.MockID, errors.New(ErrMsgSetKeyValue), + func(mock sqlmock.Sqlmock, args getRoleArgs) *Patches { + conn.Command("GET", fmt.Sprintf("role%d", args.roleID)).Expect(nil) + return nil + }), + setupErrorCase(ErrorFindRoleById, testutls.MockID, errors.New(ErrMsgFindRoleById), + func(mock sqlmock.Sqlmock, args getRoleArgs) *Patches { + conn.Command("GET", fmt.Sprintf("role%d", args.roleID)).ExpectError(fmt.Errorf("there was an error")) + return nil + }), + loadGetRoleSuccessCase(), + loadGetRoleCacheMissSuccessCase(), } return tests } func TestGetRole(t *testing.T) { tests := getGetRoleTestCases() - oldDB := boil.GetDB() - err := config.LoadEnvWithFilePrefix(convert.StringToPointerString("./../../../")) - if err != nil { - log.Fatal(err) - } - mock, db, _ := testutls.SetupMockDB(t) + mock, cleanup, _ := testutls.SetupMockDB(t) + defer cleanup() + redisDialPatches := ApplyFunc(redisDial, func() (redis.Conn, error) { + return conn, nil + }) + defer redisDialPatches.Reset() for _, tt := range tests { - ApplyFunc(redisDial, func() (redis.Conn, error) { - return conn, nil - }) t.Run(tt.name, func(t *testing.T) { - if tt.name == ErrorUnmarshal { - patchJson := ApplyFunc(json.Unmarshal, func(data []byte, v any) error { - return fmt.Errorf(ErrMsgUnmarshal) - }) - defer patchJson.Reset() - } - if tt.args.cacheMiss { - conn.Command("GET", fmt.Sprintf("role%d", tt.args.roleID)).Expect(nil) - b, _ := json.Marshal(tt.want) - conn.Command("SET", fmt.Sprintf("role%d", tt.args.roleID), string(b)).Expect(nil) - for _, dbQuery := range tt.args.dbQueries { - mock.ExpectQuery(regexp.QuoteMeta(dbQuery.Query)). - WithArgs(*dbQuery.Actions...). - WillReturnRows(dbQuery.DbResponse) - } - } else if tt.name == ErrorGetKeyValue { - conn.Command("GET", fmt.Sprintf("role%d", tt.args.roleID)).ExpectError(fmt.Errorf(ErrMsgGetKeyValue)) - } else if tt.name == ErrorSetKeyValue { - conn.Command("GET", fmt.Sprintf("role%d", tt.args.roleID)).Expect(nil) - } else { - b, _ := json.Marshal(tt.want) - conn.Command("GET", fmt.Sprintf("role%d", tt.args.roleID)).Expect(b) - } + patches := tt.init(mock, tt.args) + got, err := GetRole(tt.args.roleID, context.Background()) if (err != nil) != tt.wantErr { t.Errorf("GetRole() error = %v, wantErr %v", err, tt.wantErr) return } - if !reflect.DeepEqual(got, tt.want) { - t.Errorf("GetRole() = %v, want %v", got, tt.want) + if !reflect.DeepEqual(got, tt.args.want) { + t.Errorf("GetRole() = %v, want %v", got, tt.args.want) + } + if patches != nil { + patches.Reset() } }) } - boil.SetDB(oldDB) - db.Close() } func TestIncVisits(t *testing.T) { type args struct { @@ -534,84 +480,83 @@ func TestIncVisits(t *testing.T) { } } -type args struct { +type startVisitArgs struct { path string + want int +} + +type startVisitTestArgs struct { + name string + args startVisitArgs + + wantErr bool + errMsg error + init func(startVisitArgs) *Patches } func TestStartVisits(t *testing.T) { tests := getTestCases() for _, tt := range tests { - mockDependencies(tt.name) + patches := tt.init(tt.args) t.Run(tt.name, func(t *testing.T) { - expectRedisCommand(tt.args.path, tt.want) err := StartVisits(tt.args.path, time.Second) verifyError(t, err, tt.wantErr) }) + if patches != nil { + patches.Reset() + } } } -func getTestCases() []struct { - name string - args args - want int - wantErr bool - errMsg error -} { - return []struct { - name string - args args - want int - wantErr bool - errMsg error - }{ +func getTestCases() []startVisitTestArgs { + return []startVisitTestArgs{ { name: ErrorConnDo, - args: args{ + args: startVisitArgs{ path: "test", }, wantErr: true, errMsg: fmt.Errorf(ErrMsgFromConnDo), + init: func(args startVisitArgs) *Patches { + conn.Command("SETEX", args.path, int(math.Ceil(time.Second.Seconds())), 1).Expect(args.want) + return gomonkey.ApplyMethodFunc(redigomock.NewConn(), "Do", + func(commandName string, args ...interface{}) (reply interface{}, err error) { + return nil, fmt.Errorf(ErrMsgFromConnDo) + }) + }, }, { name: SuccessCase, - args: args{ + args: startVisitArgs{ path: "test", + want: 10, + }, + init: func(args startVisitArgs) *Patches { + return gomonkey.ApplyFunc(redisDial, func() (redigo.Conn, error) { + return conn, nil + }) }, - want: 10, }, { name: ErrorRedisDial, - args: args{ + args: startVisitArgs{ path: "test", }, wantErr: true, errMsg: fmt.Errorf(ErrMsgFromRedisDial), + init: func(args startVisitArgs) *Patches { + conn.Command("SETEX", args.path, int(math.Ceil(time.Second.Seconds())), 1).Expect(args.want) + return gomonkey.ApplyFunc(redisDial, func() (redigo.Conn, error) { + return nil, fmt.Errorf(ErrMsgFromRedisDial) + }) + }, }, } } -func mockDependencies(name string) { - if name == ErrorRedisDial { - patch := gomonkey.ApplyFunc(redisDial, func() (redigo.Conn, error) { - return nil, fmt.Errorf(ErrMsgFromRedisDial) - }) - defer patch.Reset() - } else if name == ErrorConnDo { - patch := gomonkey.ApplyMethodFunc(redigomock.NewConn(), "Do", - func(commandName string, args ...interface{}) (reply interface{}, err error) { - return nil, fmt.Errorf(ErrMsgFromConnDo) - }) - defer patch.Reset() - } -} - -func expectRedisCommand(path string, want int) { - conn.Command("SETEX", path, int(math.Ceil(time.Second.Seconds())), 1).Expect(want) -} - func verifyError(t *testing.T, err error, wantErr bool) { if (err != nil) != wantErr { t.Errorf("StartVisits() error = %v, wantErr %v", err, wantErr) diff --git a/pkg/utl/resultwrapper/error_test.go b/pkg/utl/resultwrapper/error_test.go index c387562a..ba7e3332 100644 --- a/pkg/utl/resultwrapper/error_test.go +++ b/pkg/utl/resultwrapper/error_test.go @@ -15,11 +15,11 @@ import ( ) const ( - SuccessCase = "Success" + SuccessCase = "success" ErrorCase = "error from json" - ErrMsgJSON = "Error from JSON" - ErrMsg = "This is an Error" - DetailMsg = "Some level of detail" + ErrMsgJSON = "error from JSON" + ErrMsg = "this is an error" + DetailMsg = "some level of detail" ) func TestSplitByLabel(t *testing.T) { diff --git a/resolver/auth_mutations.resolvers_test.go b/resolver/auth_mutations.resolvers_test.go index 2e48cb25..3f6c7752 100644 --- a/resolver/auth_mutations.resolvers_test.go +++ b/resolver/auth_mutations.resolvers_test.go @@ -2,7 +2,6 @@ package resolver_test import ( "context" - "database/sql" "database/sql/driver" "fmt" "reflect" @@ -15,7 +14,6 @@ import ( "go-template/internal/jwt" "go-template/internal/service" "go-template/models" - "go-template/pkg/utl/convert" "go-template/pkg/utl/resultwrapper" "go-template/resolver" "go-template/testutls" @@ -23,7 +21,6 @@ import ( "github.com/DATA-DOG/go-sqlmock" "github.com/agiledragon/gomonkey/v2" "github.com/stretchr/testify/assert" - "github.com/volatiletech/sqlboiler/v4/boil" ) const ( @@ -300,10 +297,6 @@ func handleTestCases(t *testing.T, tt struct { // Load environment variables loadEnvironmentVariables() - - // Set up mock database - mockDB := setupMockDBLogin(t) - defer mockDB.ExpectClose() // Handle specific test cases handleSpecificTestCase(t, tt) } @@ -339,26 +332,12 @@ func prepareMocksAndPatches(tt struct { } func loadEnvironmentVariables() { - err := config.LoadEnvWithFilePrefix(convert.StringToPointerString("./../")) + err := config.LoadEnv() if err != nil { fmt.Print("error loading .env file") } } -func setupMockDBLogin(t *testing.T) sqlmock.Sqlmock { - db, mock, err := sqlmock.New() - if err != nil { - t.Fatalf(ErrorMessage, err) - } - oldDB := boil.GetDB() - defer func() { - db.Close() - boil.SetDB(oldDB) - }() - boil.SetDB(db) - return mock -} - func handleSpecificTestCase(t *testing.T, tt struct { name string req LoginArgs @@ -367,7 +346,7 @@ func handleSpecificTestCase(t *testing.T, tt struct { err error }) { resolver1 := resolver.Resolver{} - mock := setupMockDBLogin(t) + mock, cleanup, _ := testutls.SetupMockDB(t) // Mock database queries based on test case switch tt.name { case ErrorFindingUser: @@ -422,6 +401,7 @@ func handleSpecificTestCase(t *testing.T, tt struct { assert.Equal(t, true, strings.Contains(err.Error(), tt.err.Error())) assert.Equal(t, tt.wantErr, err != nil) } + cleanup() } type changeReq struct { @@ -601,17 +581,7 @@ func TestChangePassword( fmt.Print("error loading .env file") } // Create a mock SQL database connection - db, mock, err := sqlmock.New() - if err != nil { - t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) - } - // Inject mock instance into boil. - oldDB := boil.GetDB() - defer func() { - db.Close() - boil.SetDB(oldDB) - }() - boil.SetDB(db) + mock, cleanup, _ := testutls.SetupMockDB(t) // Handle the case where there is an error while finding the user if tt.name == ErrorFindingUser { mock.ExpectQuery(regexp.QuoteMeta(`select * from "users" where "id"=$1`)). @@ -624,7 +594,7 @@ func TestChangePassword( mock.ExpectQuery(regexp.QuoteMeta(`select * from "users" where "id"=$1`)). WithArgs(). WillReturnRows(rows) - // Handle the case where the password update is successful + // Handle the case where the password update is successful if tt.name == SuccessCase { result := driver.Result(driver.RowsAffected(1)) mock.ExpectExec(regexp.QuoteMeta(`UPDATE "users" `)).WillReturnResult(result) @@ -644,6 +614,7 @@ func TestChangePassword( } // Assert that the expected error value matches the actual error value assert.Equal(t, tt.wantErr, err != nil) + cleanup() }, ) } @@ -656,8 +627,7 @@ func TestRefreshToken(t *testing.T) { for _, tt := range cases { t.Run(tt.name, func(t *testing.T) { - db, mock := prepareMockDB(t) - defer db.Close() + mock, cleanup, _ := testutls.SetupMockDB(t) setupMockDBExpectations(tt.name, mock) @@ -680,6 +650,7 @@ func TestRefreshToken(t *testing.T) { } else { assert.Equal(t, true, strings.Contains(err.Error(), tt.err.Error())) } + cleanup() }) } } @@ -733,14 +704,6 @@ func prepareRefreshTokenCases() []struct { return cases } -func prepareMockDB(t *testing.T) (*sql.DB, sqlmock.Sqlmock) { - db, mock, err := sqlmock.New() - if err != nil { - t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) - } - boil.SetDB(db) - return db, mock -} func setupMockDBExpectations(name string, mock sqlmock.Sqlmock) { switch name { case ErrorInvalidToken: diff --git a/resolver/user_mutations.resolvers_test.go b/resolver/user_mutations.resolvers_test.go index 62dadf87..a594ad7c 100644 --- a/resolver/user_mutations.resolvers_test.go +++ b/resolver/user_mutations.resolvers_test.go @@ -2,7 +2,6 @@ package resolver_test import ( "context" - "database/sql" "database/sql/driver" "fmt" "go-template/daos" @@ -20,9 +19,7 @@ import ( "github.com/DATA-DOG/go-sqlmock" "github.com/agiledragon/gomonkey/v2" - "github.com/joho/godotenv" "github.com/stretchr/testify/assert" - "github.com/volatiletech/sqlboiler/v4/boil" ) type AnyTime struct{} @@ -35,12 +32,13 @@ func (a AnyTime) Match( return ok } -func setupMockDBForCreateUser(t *testing.T) (*sql.DB, sqlmock.Sqlmock) { - mockDB, mock, err := sqlmock.New() - if err != nil { - t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) - } - return mockDB, mock +type AnyString struct{} + +func (a AnyString) Match( + v driver.Value, +) bool { + _, ok := v.(string) + return ok } func expectInsertUser(mock sqlmock.Sqlmock, mockUser models.User) { @@ -52,12 +50,12 @@ func expectInsertUser(mock sqlmock.Sqlmock, mockUser models.User) { ) mock.ExpectQuery(regexp.QuoteMeta(`INSERT INTO "users"`)). WithArgs( - mockUser.FirstName, mockUser.LastName, mockUser.Username, "", mockUser.Email, + mockUser.FirstName, mockUser.LastName, mockUser.Username, AnyString{}, mockUser.Email, mockUser.RoleID, AnyTime{}, AnyTime{}, ). WillReturnRows(rows) } -func GetCreateUserTestCase() []struct { +func getCreateUserTestCase() []struct { name string req fm.UserCreateInput wantResp *fm.User @@ -113,16 +111,11 @@ func GetCreateUserTestCase() []struct { return cases } func TestCreateUser(t *testing.T) { - cases := GetCreateUserTestCase() + cases := getCreateUserTestCase() resolver := resolver.Resolver{} for _, tt := range cases { t.Run(tt.name, func(t *testing.T) { - mockDB, mock := setupMockDBForCreateUser(t) - defer mockDB.Close() - - defer func() { - _ = mock.ExpectationsWereMet() - }() + mock, cleanup, _ := testutls.SetupMockDB(t) if tt.name == ErrorFromCreateUser { mock.ExpectQuery(regexp.QuoteMeta(`INSERT INTO "users"`)). @@ -145,20 +138,12 @@ func TestCreateUser(t *testing.T) { }) defer patch.Reset() } - - err := config.LoadEnvWithFilePrefix(convert.StringToPointerString("./../")) - if err != nil { - log.Fatal(err) - } - mock, db, _ := testutls.SetupMockDB(t) - oldDB, db := boil.GetDB(), db - boil.SetDB(oldDB) - boil.SetDB(db) response, err := resolver.Mutation().CreateUser(context.Background(), tt.req) if tt.wantResp != nil { assert.Equal(t, tt.wantResp, response) } assert.Equal(t, tt.wantErr, err != nil) + cleanup() }) } } @@ -226,17 +211,12 @@ func TestUpdateUser( }) defer patch.Reset() } - err := config.LoadEnvWithFilePrefix(convert.StringToPointerString("./../")) + err := config.LoadEnv() if err != nil { log.Fatal(err) } - mock, db, _ := testutls.SetupMockDB(t) - oldDB := boil.GetDB() - defer func() { - db.Close() - boil.SetDB(oldDB) - }() - boil.SetDB(db) + mock, cleanup, _ := testutls.SetupMockDB(t) + if tt.name == ErrorFindingUser { mock.ExpectQuery(regexp.QuoteMeta(`UPDATE "users"`)).WithArgs().WillReturnError(fmt.Errorf("")) } @@ -253,6 +233,7 @@ func TestUpdateUser( assert.Equal(t, tt.wantResp, response) } assert.Equal(t, tt.wantErr, err != nil) + cleanup() }, ) } @@ -303,22 +284,7 @@ func TestDeleteUser( }) defer patch.Reset() } - err := godotenv.Load( - "../.env.local", - ) - if err != nil { - fmt.Print("error loading .env file") - } - db, mock, err := sqlmock.New() - if err != nil { - t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) - } - oldDB := boil.GetDB() - defer func() { - db.Close() - boil.SetDB(oldDB) - }() - boil.SetDB(db) + mock, cleanup, _ := testutls.SetupMockDB(t) if tt.name == ErrorFindingUser { mock.ExpectQuery(regexp.QuoteMeta(`select * from "users" where "id"=$1`)). WithArgs(). @@ -342,6 +308,7 @@ func TestDeleteUser( assert.Equal(t, tt.wantResp, response) } assert.Equal(t, tt.wantErr, err != nil) + cleanup() }, ) } diff --git a/resolver/user_queries.resolvers_test.go b/resolver/user_queries.resolvers_test.go index 72fcb854..dad98b07 100644 --- a/resolver/user_queries.resolvers_test.go +++ b/resolver/user_queries.resolvers_test.go @@ -2,7 +2,6 @@ package resolver_test import ( "context" - "database/sql" "encoding/json" "errors" "fmt" @@ -12,10 +11,8 @@ import ( "go-template/gqlmodels" fm "go-template/gqlmodels" - "go-template/internal/config" "go-template/models" "go-template/pkg/utl/cnvrttogql" - "go-template/pkg/utl/convert" "go-template/pkg/utl/rediscache" "go-template/resolver" "go-template/testutls" @@ -25,7 +22,6 @@ import ( . "github.com/agiledragon/gomonkey/v2" "github.com/gomodule/redigo/redis" "github.com/joho/godotenv" - "github.com/volatiletech/sqlboiler/v4/boil" "github.com/rafaeljusto/redigomock" "github.com/stretchr/testify/assert" @@ -38,12 +34,22 @@ type args struct { func TestMe(t *testing.T) { cases := initializeCases() - err := loadEnvAndSetupDB(t) + _, cleanup, err := testutls.SetupMockDB(t) + defer cleanup() if err != nil { log.Fatal(err) } resolver1 := &resolver.Resolver{} + conn := redigomock.NewConn() + patches := ApplyFunc( + redis.Dial, + func(network string, address string, options ...redis.DialOption) (redis.Conn, error) { + return conn, nil + }, + ) + defer patches.Reset() + for _, tt := range cases { setupTestEnvironment(tt.name, t) runTestCase(t, tt, resolver1) @@ -75,27 +81,11 @@ func initializeCases() []struct { } } -func loadEnvAndSetupDB(t *testing.T) error { - err := config.LoadEnvWithFilePrefix(convert.StringToPointerString("./../")) - if err != nil { - return err - } - _, db, _ := testutls.SetupMockDB(t) - oldDb := boil.GetDB() - boil.SetDB(db) - defer func() { - db.Close() - boil.SetDB(oldDb) - }() - return nil -} - func setupTestEnvironment(name string, t *testing.T) { if name == ErrorFromRedisCache { patchGetUser := patchRedisCache() defer patchGetUser.Reset() } - setupDBAndRedis(t) } func runTestCase(t *testing.T, tt struct { @@ -124,26 +114,6 @@ func patchRedisCache() *gomonkey.Patches { }) } -func setupDBAndRedis(t *testing.T) { - _, db, err := testutls.SetupEnvAndDB(t, testutls.Parameters{EnvFileLocation: `../.env.local`}) - if err != nil { - panic("failed to setup env and db") - } - oldDb := boil.GetDB() - boil.SetDB(db) - defer func() { - db.Close() - boil.SetDB(oldDb) - }() - conn := redigomock.NewConn() - ApplyFunc( - redis.Dial, - func(network string, address string, options ...redis.DialOption) (redis.Conn, error) { - return conn, nil - }, - ) -} - func testRedisConnection(user *models.User) { b, _ := json.Marshal(user) conn := redigomock.NewConn() @@ -210,18 +180,6 @@ func loadEnvVars() error { return nil } -func setupMockDB(t *testing.T) (*sql.DB, sqlmock.Sqlmock, func()) { - db, mock, err := sqlmock.New() - if err != nil { - t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) - } - oldDB := boil.GetDB() - return db, mock, func() { - db.Close() - boil.SetDB(oldDB) - } -} - func setExpectations(mock sqlmock.Sqlmock, tt struct { name string pagination *fm.UserPagination @@ -295,9 +253,7 @@ func TestUsers( fmt.Print("error loading .env file") } - db, mock, cleanup := setupMockDB(t) - defer cleanup() - boil.SetDB(db) + mock, cleanup, _ := testutls.SetupMockDB(t) setExpectations(mock, tt) @@ -306,6 +262,7 @@ func TestUsers( response, err := executeQuery(&resolver1, ctx, tt.pagination) assertResponse(t, tt, response, err) + cleanup() }, ) } diff --git a/testutls/main.go b/testutls/main.go index 6d2b48d2..cd86f714 100644 --- a/testutls/main.go +++ b/testutls/main.go @@ -115,13 +115,22 @@ func SetupEnvAndDB(t *testing.T, parameters Parameters) (mock sqlmock.Sqlmock, d return mock, db, nil } -func SetupMockDB(t *testing.T) (mock sqlmock.Sqlmock, db *sql.DB, err error) { - db, mock, err = sqlmock.New() +func SetupMockDB(t *testing.T) (mock sqlmock.Sqlmock, cleanup func(), err error) { + err = config.LoadEnv() + if err != nil { + t.Fatalf("Error loading the env.") + } + oldDB := boil.GetDB() + db, mock, err := sqlmock.New() if err != nil { t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) } boil.SetDB(db) - return mock, db, nil + return mock, func() { + _ = mock.ExpectationsWereMet() + db.Close() + boil.SetDB(oldDB) + }, nil } type QueryData struct { From f310a92b5aa9f30745e25d75d229c05c582af5fb Mon Sep 17 00:00:00 2001 From: Mac Date: Thu, 28 Mar 2024 13:14:20 +0530 Subject: [PATCH 13/39] feat: making changes for UserQueries --- go.mod | 1 - go.sum | 2 - resolver/user_queries.resolvers_test.go | 270 ++++++++---------------- 3 files changed, 84 insertions(+), 189 deletions(-) diff --git a/go.mod b/go.mod index c8be99bf..048aca6b 100644 --- a/go.mod +++ b/go.mod @@ -20,7 +20,6 @@ require ( github.com/lib/pq v1.10.7 github.com/masahiro331/go-commitlinter v0.0.0-20220207112004-c66fa942bad3 github.com/nbutton23/zxcvbn-go v0.0.0-20180912185939-ae427f1e4c1d - github.com/rafaeljusto/redigomock v2.4.0+incompatible github.com/rafaeljusto/redigomock/v3 v3.0.1 github.com/rs/zerolog v1.18.0 github.com/rubenv/sql-migrate v1.3.1 diff --git a/go.sum b/go.sum index 0d281eb1..e4f90f97 100644 --- a/go.sum +++ b/go.sum @@ -464,8 +464,6 @@ github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8 github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= -github.com/rafaeljusto/redigomock v2.4.0+incompatible h1:d7uo5MVINMxnRr20MxbgDkmZ8QRfevjOVgEa4n0OZyY= -github.com/rafaeljusto/redigomock v2.4.0+incompatible/go.mod h1:JaY6n2sDr+z2WTsXkOmNRUfDy6FN0L6Nk7x06ndm4tY= github.com/rafaeljusto/redigomock/v3 v3.0.1 h1:AUsXTuf+UEMwVEgRHRDYFFCJ1quS2JVDQmTWypjI5mI= github.com/rafaeljusto/redigomock/v3 v3.0.1/go.mod h1:51LNR7Q4YFsi0N+CHr7+FC1Jx2lPLzcRHCPlLO2Qbpw= github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= diff --git a/resolver/user_queries.resolvers_test.go b/resolver/user_queries.resolvers_test.go index dad98b07..1c6f9ec6 100644 --- a/resolver/user_queries.resolvers_test.go +++ b/resolver/user_queries.resolvers_test.go @@ -2,17 +2,16 @@ package resolver_test import ( "context" - "encoding/json" "errors" "fmt" - "log" + "go-template/pkg/utl/cnvrttogql" "regexp" "testing" "go-template/gqlmodels" fm "go-template/gqlmodels" "go-template/models" - "go-template/pkg/utl/cnvrttogql" + // "go-template/pkg/utl/cnvrttogql" "go-template/pkg/utl/rediscache" "go-template/resolver" "go-template/testutls" @@ -20,10 +19,7 @@ import ( "github.com/DATA-DOG/go-sqlmock" "github.com/agiledragon/gomonkey/v2" . "github.com/agiledragon/gomonkey/v2" - "github.com/gomodule/redigo/redis" - "github.com/joho/godotenv" - "github.com/rafaeljusto/redigomock" "github.com/stretchr/testify/assert" ) @@ -31,213 +27,127 @@ type args struct { user *models.User } -func TestMe(t *testing.T) { - cases := initializeCases() - - _, cleanup, err := testutls.SetupMockDB(t) - defer cleanup() - if err != nil { - log.Fatal(err) - } - - resolver1 := &resolver.Resolver{} - conn := redigomock.NewConn() - patches := ApplyFunc( - redis.Dial, - func(network string, address string, options ...redis.DialOption) (redis.Conn, error) { - return conn, nil - }, - ) - defer patches.Reset() - - for _, tt := range cases { - setupTestEnvironment(tt.name, t) - runTestCase(t, tt, resolver1) - } -} - -func initializeCases() []struct { +type queryMeTestArgs struct { name string wantResp *fm.User wantErr bool args args -} { - return []struct { - name string - wantResp *fm.User - wantErr bool - args args - }{ + init func(args) *Patches +} + +func initializeCases() []queryMeTestArgs { + return []queryMeTestArgs{ { name: SuccessCase, args: args{user: testutls.MockUser()}, wantResp: cnvrttogql.UserToGraphQlUser(testutls.MockUser(), 4), + init: func(args args) *Patches { + return gomonkey.ApplyFunc(rediscache.GetUser, + func(userID int, ctx context.Context) (*models.User, error) { + return args.user, nil + }) + }, }, { name: ErrorFromRedisCache, args: args{user: testutls.MockUser()}, - wantResp: nil, + wantErr: true, + wantResp: &gqlmodels.User{}, + init: func(args args) *Patches { + return gomonkey.ApplyFunc(rediscache.GetUser, + func(userID int, ctx context.Context) (*models.User, error) { + return nil, errors.New("redis cache") + }) + }, }, } } -func setupTestEnvironment(name string, t *testing.T) { - if name == ErrorFromRedisCache { - patchGetUser := patchRedisCache() - defer patchGetUser.Reset() - } -} - -func runTestCase(t *testing.T, tt struct { - name string - wantResp *fm.User - wantErr bool - args args -}, resolver1 *resolver.Resolver) { - t.Run( - tt.name, - func(t *testing.T) { - testRedisConnection(tt.args.user) - - ctx := setupTestMeContext() - - response, err := resolver1.Query().Me(ctx) - assertTestMeResponse(t, tt, response, err) - }, - ) -} - -func patchRedisCache() *gomonkey.Patches { - return gomonkey.ApplyFunc(rediscache.GetUser, - func(userID int, ctx context.Context) (*models.User, error) { - return nil, errors.New("redis cache") - }) -} - -func testRedisConnection(user *models.User) { - b, _ := json.Marshal(user) - conn := redigomock.NewConn() - conn.Command("GET", "user0").Expect(b) -} - -func setupTestMeContext() context.Context { - c := context.Background() - ctx := context.WithValue(c, testutls.UserKey, testutls.MockUser()) - return ctx -} - -func assertTestMeResponse(t *testing.T, tt struct { - name string - wantResp *fm.User - wantErr bool - args args -}, response *fm.User, err error) { - if tt.wantResp != nil && response != nil { - assert.Equal(t, tt.wantResp, response) +func TestMe(t *testing.T) { + cases := initializeCases() + _, cleanup, _ := testutls.SetupMockDB(t) + defer cleanup() + resolver1 := &resolver.Resolver{} + for _, tt := range cases { + patches := tt.init(tt.args) + response, err := resolver1.Query().Me(context.TODO()) + if tt.wantResp != nil && response != nil { + assert.Equal(t, tt.wantResp, response) + } + assert.Equal(t, tt.wantErr, err != nil) + if patches != nil { + patches.Reset() + } } - assert.Equal(t, tt.wantErr, err != nil) } -// TestUsers is a unit test function for testing user queries. -func initializeTestCases() []struct { +type queryUsersArgs struct { name string pagination *fm.UserPagination wantResp []*models.User wantErr bool -} { - return []struct { - name string - pagination *fm.UserPagination - wantResp []*models.User - wantErr bool - }{ + init func(sqlmock.Sqlmock) +} + +// TestUsers is a unit test function for testing user queries. +func initializeTestCases() []queryUsersArgs { + return []queryUsersArgs{ { name: ErrorFindingUser, wantErr: true, + init: func(mock sqlmock.Sqlmock) { + mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users";`)). + WithArgs(). + WillReturnError(fmt.Errorf("")) + }, }, { - name: "pagination", + name: "Paginated Users are returned when the request is paginated", wantErr: false, pagination: &fm.UserPagination{ Limit: 1, Page: 1, }, wantResp: testutls.MockUsers(), + init: func(mock sqlmock.Sqlmock) { + rows := sqlmock. + NewRows([]string{"id", "email", "first_name", "last_name", "mobile", "username", "address"}). + AddRow(testutls.MockID, testutls.MockEmail, "First", "Last", "+911234567890", "username", "22 Jump Street") + + mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" LIMIT 1 OFFSET 1;`)).WithArgs().WillReturnRows(rows) + + rowCount := sqlmock.NewRows([]string{"count"}). + AddRow(1) + mock.ExpectQuery(regexp.QuoteMeta(`SELECT COUNT(*) FROM "users"`)). + WithArgs(). + WillReturnRows(rowCount) + }, }, { - name: SuccessCase, + name: "Successfully fetches paginated users even without pagination request payload", wantErr: false, wantResp: testutls.MockUsers(), + init: func(mock sqlmock.Sqlmock) { + rows := sqlmock. + NewRows([]string{"id", "email", "first_name", "last_name", "mobile", "username", "address"}). + AddRow(testutls.MockID, testutls.MockEmail, "First", "Last", "+911234567890", "username", "22 Jump Street") + mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users";`)).WithArgs().WillReturnRows(rows) + + rowCount := sqlmock.NewRows([]string{"count"}). + AddRow(1) + mock.ExpectQuery(regexp.QuoteMeta(`SELECT COUNT(*) FROM "users";`)). + WithArgs(). + WillReturnRows(rowCount) + }, }, } } -func loadEnvVars() error { - err := godotenv.Load("../.env.local") - if err != nil { - return err - } - return nil -} - -func setExpectations(mock sqlmock.Sqlmock, tt struct { - name string - pagination *fm.UserPagination - wantResp []*models.User - wantErr bool -}) { - if tt.name == ErrorFindingUser { - mock.ExpectQuery(regexp.QuoteMeta(`select * from "users" where "id"=$1`)). - WithArgs(). - WillReturnError(fmt.Errorf("")) - } - if tt.name == "pagination" { - rows := sqlmock. - NewRows([]string{"id", "email", "first_name", "last_name", "mobile", "username", "address"}). - AddRow(testutls.MockID, testutls.MockEmail, "First", "Last", "+911234567890", "username", "22 Jump Street") - mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" LIMIT 1 OFFSET 1;`)).WithArgs().WillReturnRows(rows) - - rowCount := sqlmock.NewRows([]string{"count"}). - AddRow(1) - mock.ExpectQuery(regexp.QuoteMeta(`SELECT COUNT(*) FROM "users" LIMIT 1;`)). - WithArgs(). - WillReturnRows(rowCount) - } else { - rows := sqlmock. - NewRows([]string{"id", "email", "first_name", "last_name", "mobile", "username", "address"}). - AddRow(testutls.MockID, testutls.MockEmail, "First", "Last", "+911234567890", "username", "22 Jump Street") - mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users";`)).WithArgs().WillReturnRows(rows) - - rowCount := sqlmock.NewRows([]string{"count"}). - AddRow(1) - mock.ExpectQuery(regexp.QuoteMeta(`SELECT COUNT(*) FROM "users";`)). - WithArgs(). - WillReturnRows(rowCount) - } -} - -func setupContext() context.Context { - c := context.Background() - return context.WithValue(c, testutls.UserKey, testutls.MockUser()) -} - func executeQuery(resolver1 *resolver.Resolver, ctx context.Context, pagination *fm.UserPagination) (*gqlmodels.UsersPayload, error) { return resolver1.Query().Users(ctx, pagination) } -func assertResponse(t *testing.T, tt struct { - name string - pagination *fm.UserPagination - wantResp []*models.User - wantErr bool -}, response *gqlmodels.UsersPayload, err error) { - if tt.wantResp != nil && response != nil { - assert.Equal(t, len(tt.wantResp), len(response.Users)) - } - assert.Equal(t, tt.wantErr, err != nil) -} - func TestUsers( t *testing.T, ) { @@ -245,25 +155,13 @@ func TestUsers( resolver1 := resolver.Resolver{} for _, tt := range cases { - t.Run( - tt.name, - func(t *testing.T) { - err := loadEnvVars() - if err != nil { - fmt.Print("error loading .env file") - } - - mock, cleanup, _ := testutls.SetupMockDB(t) - - setExpectations(mock, tt) - - ctx := setupContext() - - response, err := executeQuery(&resolver1, ctx, tt.pagination) - - assertResponse(t, tt, response, err) - cleanup() - }, - ) + mock, cleanup, _ := testutls.SetupMockDB(t) + tt.init(mock) + response, err := executeQuery(&resolver1, context.Background(), tt.pagination) + if tt.wantResp != nil && response != nil { + assert.Equal(t, len(tt.wantResp), len(response.Users)) + } + assert.Equal(t, tt.wantErr, err != nil) + cleanup() } } From 9810142daed5f23e0524169dc8e48a0332531a0f Mon Sep 17 00:00:00 2001 From: HIMANSHU Date: Fri, 29 Mar 2024 16:47:46 +0530 Subject: [PATCH 14/39] error_test.go and server_test.go --- go.mod | 2 +- go.sum | 26 ++++++++++++- internal/server/error_test.go | 71 +++++++++++++++++++--------------- internal/server/server_test.go | 7 ---- 4 files changed, 65 insertions(+), 41 deletions(-) diff --git a/go.mod b/go.mod index 048aca6b..8dc79700 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.22 require ( github.com/99designs/gqlgen v0.17.24 github.com/DATA-DOG/go-sqlmock v1.5.0 - github.com/agiledragon/gomonkey/v2 v2.9.0 + github.com/agiledragon/gomonkey/v2 v2.11.0 github.com/dgrijalva/jwt-go v3.2.0+incompatible github.com/friendsofgo/errors v0.9.2 github.com/go-playground/universal-translator v0.18.0 diff --git a/go.sum b/go.sum index e4f90f97..22b31ee3 100644 --- a/go.sum +++ b/go.sum @@ -23,6 +23,7 @@ cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSU cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= +cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= @@ -33,6 +34,7 @@ cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7 cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= cloud.google.com/go/firestore v1.6.0/go.mod h1:afJwI0vaXwAG54kI7A//lP/lSPDkQORQuMkv56TxEPU= +cloud.google.com/go/firestore v1.6.1/go.mod h1:asNXNOzBdyVQmEU+ggO8UPodTkEVFW5Qx+rwHnAz+EY= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= @@ -62,8 +64,8 @@ github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/a8m/expect v1.0.0/go.mod h1:4IwSCMumY49ScypDnjNbYEjgVeqy1/U2cEs3Lat96eA= -github.com/agiledragon/gomonkey/v2 v2.9.0 h1:PDiKKybR596O6FHW+RVSG0Z7uGCBNbmbUXh3uCNQ7Hc= -github.com/agiledragon/gomonkey/v2 v2.9.0/go.mod h1:ap1AmDzcVOAz1YpeJ3TCzIgstoaWLA6jbbgxfB4w2iY= +github.com/agiledragon/gomonkey/v2 v2.11.0 h1:5oxSgA+tC1xuGsrIorR+sYiziYltmJyEZ9qA25b6l5U= +github.com/agiledragon/gomonkey/v2 v2.11.0/go.mod h1:ap1AmDzcVOAz1YpeJ3TCzIgstoaWLA6jbbgxfB4w2iY= github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM= github.com/agnivade/levenshtein v1.1.1 h1:QY8M92nrzkmr798gCo3kmMyqXFzdQVpxLlGPRBij0P8= github.com/agnivade/levenshtein v1.1.1/go.mod h1:veldBMzWxcCG2ZvUTKD2kJNRdCk5hVbJomOvKkmgYbo= @@ -78,6 +80,7 @@ github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdK github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-metrics v0.3.10/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= @@ -90,8 +93,10 @@ github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqO github.com/cenkalti/backoff/v4 v4.1.3 h1:cFAlzYUlVYDysBEH2T5hyJZMh3+5+WCBvSnK6Q8UtC4= github.com/cenkalti/backoff/v4 v4.1.3/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= @@ -105,6 +110,7 @@ github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWH github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211130200136-a8f946100490/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= @@ -139,6 +145,7 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.m github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/envoyproxy/protoc-gen-validate v0.6.2/go.mod h1:2t7qjJNvHPx8IjnBOzl9E9/baC+qXE/TeeyBRzgJDws= github.com/ericlagergren/decimal v0.0.0-20181231230500-73749d4874d5/go.mod h1:1yj25TwtUlJ+pfOu9apAVaM1RWfZGg+aFpd4hPQZekQ= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= @@ -199,6 +206,7 @@ github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4er github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= @@ -274,6 +282,7 @@ github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= +github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= @@ -286,13 +295,17 @@ github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0 h1:BZHcxBETFHIdVyhyEfOvn/RdU/QG github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= github.com/hashicorp/consul/api v1.10.1/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M= +github.com/hashicorp/consul/api v1.11.0/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-hclog v1.0.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= @@ -317,6 +330,7 @@ github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2p github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk= +github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= @@ -333,6 +347,7 @@ github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc= github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= @@ -428,8 +443,10 @@ github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/nbutton23/zxcvbn-go v0.0.0-20180912185939-ae427f1e4c1d h1:AREM5mwr4u1ORQBMvzfzBgpsctsbQikCVpvC+tX285E= github.com/nbutton23/zxcvbn-go v0.0.0-20180912185939-ae427f1e4c1d/go.mod h1:o96djdrsSGy3AWPyBgZMAGfxZNfgntdJG+11KU4QvbU= @@ -484,6 +501,7 @@ github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/sagikazarmark/crypt v0.1.0/go.mod h1:B/mN0msZuINBtQ1zZLEQcegFJJf9vnYIR88KRMEuODE= +github.com/sagikazarmark/crypt v0.3.0/go.mod h1:uD/D+6UF4SrIR1uGEv7bBNkNqLGqUr43MRiaGWX1Nig= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= @@ -576,8 +594,11 @@ github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5t github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= +go.etcd.io/etcd/api/v3 v3.5.1/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= +go.etcd.io/etcd/client/pkg/v3 v3.5.1/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= +go.etcd.io/etcd/client/v2 v2.305.1/go.mod h1:pMEacxZW7o8pg4CrFE7pquyCJJzZvkvdD2RibOCCCGs= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -957,6 +978,7 @@ google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNe google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.62.0/go.mod h1:dKmwPCydfsad4qCH08MSdgWjfHOyfpd4VtDGgRFdavw= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= diff --git a/internal/server/error_test.go b/internal/server/error_test.go index 2616bcd9..1d111414 100644 --- a/internal/server/error_test.go +++ b/internal/server/error_test.go @@ -13,51 +13,56 @@ import ( "github.com/labstack/echo/v4" ) -func Test_getVldErrorMsg(t *testing.T) { - type args struct { - s string - } - tests := []struct { - name string - args args - want string - }{ +type vldErrorMessage struct { + s string +} +type vldErrorType struct { + name string + args vldErrorMessage + want string +} + +func loadVldErrorMessageTestCases() []vldErrorType { + return []vldErrorType{ { name: "Failure_FailedOnValidation", - args: args{ + args: vldErrorMessage{ s: "a", }, want: " failed on a validation", }, { name: "Failure_FailedOnRequired", - args: args{ + args: vldErrorMessage{ s: "required", }, want: " is required, but was not received", }, { name: "Failure_FailedOnMin", - args: args{ + args: vldErrorMessage{ s: "required", }, want: " is required, but was not received", }, { name: "Failure_FailedOnMax", - args: args{ + args: vldErrorMessage{ s: "max", }, want: "'s value or length is bigger than allowed", }, { name: "Failure_FailedOnMin", - args: args{ + args: vldErrorMessage{ s: "min", }, want: "'s value or length is less than allowed", }, } +} +func TestGetVldErrorMsg(t *testing.T) { + tests := loadVldErrorMessageTestCases() for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := getVldErrorMsg(tt.args.s); got != tt.want { @@ -106,21 +111,21 @@ func setupMockContext(t *testing.T, req *http.Request, expectedStatusCode int, h return ctx } -func TestCustomErrHandlerHandler(t *testing.T) { - type args struct { - err error - expectedStatusCode int - httpMethod string - } - e := echo.New() - custErr := &customErrHandler{e: e} - tests := []struct { - name string - args args - }{ +type customErrorArgs struct { + err error + expectedStatusCode int + httpMethod string +} +type customErrorTypes struct { + name string + args customErrorArgs +} + +func loadCustomErrorHandlerCase(t *testing.T) []customErrorTypes { + return []customErrorTypes{ { name: "Faliure_Default", - args: args{ + args: customErrorArgs{ expectedStatusCode: http.StatusInternalServerError, err: fmt.Errorf("asd"), httpMethod: "GET", @@ -128,7 +133,7 @@ func TestCustomErrHandlerHandler(t *testing.T) { }, { name: "Faliure_NoContent", - args: args{ + args: customErrorArgs{ expectedStatusCode: http.StatusInternalServerError, err: fmt.Errorf("asd"), httpMethod: "HEAD", @@ -136,7 +141,7 @@ func TestCustomErrHandlerHandler(t *testing.T) { }, { name: "Faliure_HttpError", - args: args{ + args: customErrorArgs{ expectedStatusCode: http.StatusBadRequest, err: &echo.HTTPError{Code: http.StatusBadRequest, Message: "asd", Internal: fmt.Errorf("asd")}, httpMethod: "GET", @@ -144,19 +149,23 @@ func TestCustomErrHandlerHandler(t *testing.T) { }, { name: "Faliure_ValidationErrors", - args: args{ + args: customErrorArgs{ expectedStatusCode: http.StatusBadRequest, err: getValidatorErr(t), httpMethod: "GET", }, }, } +} +func TestCustomErrHandlerHandler(t *testing.T) { + e := echo.New() + custErr := &customErrHandler{e: e} + tests := loadCustomErrorHandlerCase(t) for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { // Just make a request req, _ := http.NewRequest(tt.args.httpMethod, "/", bytes.NewBuffer([]byte(""))) ctx := setupMockContext(t, req, tt.args.expectedStatusCode, tt.args.httpMethod) - // Call the handler with tt.args.err. We are asserting in the JSON/NoContent call custErr.handler(tt.args.err, ctx) }) diff --git a/internal/server/server_test.go b/internal/server/server_test.go index 61fc3d34..288bb60a 100644 --- a/internal/server/server_test.go +++ b/internal/server/server_test.go @@ -64,7 +64,6 @@ func initValues(startServer func(e *echo.Echo, s *http.Server) error) args { } func TestStart(t *testing.T) { cases := getTestCases() - for name, tt := range cases { t.Run(name, func(t *testing.T) { mockStarServerPatches := mockStartServer(&tt.args) @@ -72,18 +71,15 @@ func TestStart(t *testing.T) { startServerAndInterrupt(tt.args) waitForServerShutdownIfNeeded(tt.args) assertions(t, tt.args) - mockStarServerPatches.Reset() mockShutDownPatches.Reset() mockSdLoggerPatches.Reset() }) } } - type testCase struct { args args } - func getTestCases() map[string]testCase { return map[string]testCase{ "Success": { @@ -159,7 +155,4 @@ func waitForServerShutdownIfNeeded(args args) args { func assertions(t *testing.T, args args) { assert.Equal(t, args.startServerCalled, true) - // if args.shutDownFailed { - // assert.Equal(t, args.serverShutDownCalled, true) - // } } From 63ba76fe898ca8f546d3d67afa979ef3bf1ba9fa Mon Sep 17 00:00:00 2001 From: HIMANSHU Date: Sat, 30 Mar 2024 14:39:14 +0530 Subject: [PATCH 15/39] refactor auth mutation resolver test --- resolver/auth_mutations.resolvers_test.go | 811 +++++++++------------- 1 file changed, 323 insertions(+), 488 deletions(-) diff --git a/resolver/auth_mutations.resolvers_test.go b/resolver/auth_mutations.resolvers_test.go index 3f6c7752..1ee2c847 100644 --- a/resolver/auth_mutations.resolvers_test.go +++ b/resolver/auth_mutations.resolvers_test.go @@ -21,6 +21,7 @@ import ( "github.com/DATA-DOG/go-sqlmock" "github.com/agiledragon/gomonkey/v2" "github.com/stretchr/testify/assert" + "github.com/volatiletech/sqlboiler/v4/boil" ) const ( @@ -58,71 +59,25 @@ const ( TestUsername = "wednesday" TestToken = "refreshToken" ReqToken = "refresh_token" - ErrorMessage = "an error '%s' was not expected when opening a stub database connection" ) -func TestLogin(t *testing.T) { - cases := prepareTestCases() - - for _, tt := range cases { - t.Run(tt.name, func(t *testing.T) { - handleTestCases(t, tt) - }) - } -} - -type LoginArgs struct { +type loginArgs struct { UserName string Password string } -var req = LoginArgs{ - UserName: testutls.MockEmail, - Password: OldPassword, -} - -func prepareTestCases() []struct { +type LoginType struct { name string - req LoginArgs + req loginArgs wantResp *fm.LoginResponse wantErr bool err error -} { - cases := []struct { - name string - req LoginArgs - wantResp *fm.LoginResponse - wantErr bool - err error - }{ - prepareErrorFindingUser(), - prepareErrorPasswordValidation(), - prepareErrorActiveStatus(), - prepareErrorFromConfig(), - prepareErrorFromJwt(), - prepareErrorFromGenerateToken(), - prepareErrorUpdateUser(), - prepareSuccessCase(), - } - return cases } -func prepareErrorFindingUser() struct { - name string - req LoginArgs - wantResp *fm.LoginResponse - wantErr bool - err error -} { - return struct { - name string - req LoginArgs - wantResp *fm.LoginResponse - wantErr bool - err error - }{ +func errorFindingUserCase() LoginType { + return LoginType{ name: ErrorFindingUser, - req: LoginArgs{ + req: loginArgs{ UserName: TestUsername, Password: TestPassword, }, @@ -130,23 +85,10 @@ func prepareErrorFindingUser() struct { err: fmt.Errorf(ErrorMsgFindingUser), } } - -func prepareErrorPasswordValidation() struct { - name string - req LoginArgs - wantResp *fm.LoginResponse - wantErr bool - err error -} { - return struct { - name string - req LoginArgs - wantResp *fm.LoginResponse - wantErr bool - err error - }{ +func errorPasswordValidationCase() LoginType { + return LoginType{ name: ErrorPasswordValidation, - req: LoginArgs{ + req: loginArgs{ UserName: testutls.MockEmail, Password: TestPassword, }, @@ -154,43 +96,22 @@ func prepareErrorPasswordValidation() struct { err: fmt.Errorf(ErrorMsgPasswordValidation), } } -func prepareErrorActiveStatus() struct { - name string - req LoginArgs - wantResp *fm.LoginResponse - wantErr bool - err error -} { - return struct { - name string - req LoginArgs - wantResp *fm.LoginResponse - wantErr bool - err error - }{ - name: ErrorActiveStatus, - req: req, // Assuming req is defined somewhere in your code + +func errorActiveStatusCase() LoginType { + return LoginType{ + name: ErrorActiveStatus, + req: loginArgs{ + UserName: testutls.MockEmail, + Password: OldPassword, + }, wantErr: true, err: resultwrapper.ErrUnauthorized, } } - -func prepareErrorFromConfig() struct { - name string - req LoginArgs - wantResp *fm.LoginResponse - wantErr bool - err error -} { - return struct { - name string - req LoginArgs - wantResp *fm.LoginResponse - wantErr bool - err error - }{ +func errorFromConfigCase() LoginType { + return LoginType{ name: ErrorFromConfig, - req: LoginArgs{ + req: loginArgs{ UserName: testutls.MockEmail, Password: OldPassword, }, @@ -199,209 +120,187 @@ func prepareErrorFromConfig() struct { } } -func prepareErrorFromJwt() struct { - name string - req LoginArgs - wantResp *fm.LoginResponse - wantErr bool - err error -} { - return struct { - name string - req LoginArgs - wantResp *fm.LoginResponse - wantErr bool - err error - }{ - name: ErrorFromJwt, - req: req, +func errorFromJwtCase() LoginType { + return LoginType{ + name: ErrorFromJwt, + req: loginArgs{ + UserName: testutls.MockEmail, + Password: OldPassword, + }, wantErr: true, err: fmt.Errorf(ErrorMsgFromJwt), } } - -func prepareErrorFromGenerateToken() struct { - name string - req LoginArgs - wantResp *fm.LoginResponse - wantErr bool - err error -} { - return struct { - name string - req LoginArgs - wantResp *fm.LoginResponse - wantErr bool - err error - }{ - name: ErrorFromGenerateToken, - req: req, +func errorFromGenerateTokenCase() LoginType { + return LoginType{ + name: ErrorFromGenerateToken, + req: loginArgs{ + UserName: testutls.MockEmail, + Password: OldPassword, + }, wantErr: true, err: resultwrapper.ErrUnauthorized, } } - -func prepareErrorUpdateUser() struct { - name string - req LoginArgs - wantResp *fm.LoginResponse - wantErr bool - err error -} { - return struct { - name string - req LoginArgs - wantResp *fm.LoginResponse - wantErr bool - err error - }{ - name: ErrorUpdateUser, - req: req, +func errorUpdateUserCase() LoginType { + return LoginType{ + name: ErrorUpdateUser, + req: loginArgs{ + UserName: testutls.MockEmail, + Password: OldPassword, + }, wantErr: true, err: fmt.Errorf(ErrorMsgfromUpdateUser), } } - -func prepareSuccessCase() struct { - name string - req LoginArgs - wantResp *fm.LoginResponse - wantErr bool - err error -} { - return struct { - name string - req LoginArgs - wantResp *fm.LoginResponse - wantErr bool - err error - }{ +func loginSuccessCase() LoginType { + return LoginType{ name: SuccessCase, - req: req, + req: loginArgs{ + UserName: testutls.MockEmail, + Password: OldPassword, + }, wantResp: &fm.LoginResponse{ Token: "jwttokenstring", RefreshToken: TestToken, }, } } - -func handleTestCases(t *testing.T, tt struct { - name string - req LoginArgs - wantResp *fm.LoginResponse - wantErr bool - err error -}) { - // Prepare necessary mocks and patches - prepareMocksAndPatches(tt) - - // Load environment variables - loadEnvironmentVariables() - // Handle specific test cases - handleSpecificTestCase(t, tt) -} - -func prepareMocksAndPatches(tt struct { - name string - req LoginArgs - wantResp *fm.LoginResponse - wantErr bool - err error -}) { - if tt.name == ErrorFromConfig { - patch := gomonkey.ApplyFunc(config.Load, func() (*config.Configuration, error) { - return nil, fmt.Errorf(ErrorMsgFromConfig) - }) - defer patch.Reset() +func loadLoginTestCases() []LoginType { + return []LoginType{ + errorFindingUserCase(), + errorPasswordValidationCase(), + errorActiveStatusCase(), + errorFromConfigCase(), + errorFromJwtCase(), + errorFromGenerateTokenCase(), + errorUpdateUserCase(), + loginSuccessCase(), } +} - var tg jwt.Service - if tt.name == ErrorFromJwt { - patch := gomonkey.ApplyFunc(service.JWT, func(cfg *config.Configuration) (jwt.Service, error) { - return tg, fmt.Errorf(ErrorMsgFromJwt) - }) - defer patch.Reset() - } - patch := gomonkey.ApplyFunc(tg.GenerateToken, func(u *models.User) (string, error) { - if tt.name == ErrorFromGenerateToken { +func applyGenerateTokenPatchLogin(name string) *gomonkey.Patches { + tg := jwt.Service{} + return gomonkey.ApplyFunc(tg.GenerateToken, func(u *models.User) (string, error) { + if name == ErrorFromGenerateToken { return "", resultwrapper.ErrUnauthorized + } else { + return "", nil } - return "", nil }) - defer patch.Reset() -} - -func loadEnvironmentVariables() { - err := config.LoadEnv() - if err != nil { - fmt.Print("error loading .env file") - } } -func handleSpecificTestCase(t *testing.T, tt struct { - name string - req LoginArgs - wantResp *fm.LoginResponse - wantErr bool - err error -}) { - resolver1 := resolver.Resolver{} - mock, cleanup, _ := testutls.SetupMockDB(t) - // Mock database queries based on test case - switch tt.name { - case ErrorFindingUser: - mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (username=$1) LIMIT 1;`)). +func setupLoginSQLMocks(name string, mock sqlmock.Sqlmock) *sqlmock.ExpectedQuery { + if name == ErrorFindingUser { + // get user by username + return mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (username=$1) LIMIT 1;`)). WithArgs(). WillReturnError(fmt.Errorf(ErrorMsgFindingUser)) - case ErrorPasswordValidation: + } + // Handle the case where there is an error validating the password + if name == ErrorPasswordValidation { + // get user by username rows := sqlmock.NewRows([]string{"id", "password", "active", "role_id"}). AddRow(testutls.MockID, TestPasswordHash, true, 1) mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (username=$1) LIMIT 1;`)). WithArgs(). WillReturnRows(rows) - case ErrorActiveStatus: + } + // Handle the case where the user is not active + if name == ErrorActiveStatus { + // get user by username rows := sqlmock.NewRows([]string{"id", "password", "active", "role_id"}). AddRow(testutls.MockID, OldPasswordHash, false, 1) mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (username=$1) LIMIT 1;`)). WithArgs(). WillReturnRows(rows) - default: - rows := sqlmock.NewRows([]string{"id", "password", "active", "role_id"}). - AddRow(testutls.MockID, OldPasswordHash, true, 1) - mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (username=$1) LIMIT 1;`)). - WithArgs(). - WillReturnRows(rows) } - - if tt.name == SuccessCase || tt.name == ErrorUpdateUser { + // get user by username + rows := sqlmock.NewRows([]string{"id", "password", "active", "role_id"}). + AddRow(testutls.MockID, OldPasswordHash, true, 1) + mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (username=$1) LIMIT 1;`)). + WithArgs(). + WillReturnRows(rows) + // Apply mock behavior for a successful query result + if name == SuccessCase || name == ErrorUpdateUser { rows := sqlmock.NewRows([]string{"id", "name"}). AddRow(1, "ADMIN") mock.ExpectQuery(regexp.QuoteMeta(`SELECT "roles".* FROM "roles" WHERE ("id" = $1) LIMIT 1`)). WithArgs([]driver.Value{1}...). WillReturnRows(rows) } + return nil +} - if tt.name == ErrorUpdateUser { - mock.ExpectExec(regexp.QuoteMeta(`UPDATE "users" `)).WillReturnError(fmt.Errorf(ErrorMsgfromUpdateUser)) +func setupLoginExpectedExec(name string, mock sqlmock.Sqlmock) *sqlmock.ExpectedExec { + if name == ErrorUpdateUser { + fmt.Println(name, " test name ") + return mock.ExpectExec(regexp.QuoteMeta(`UPDATE "users" `)).WillReturnError(fmt.Errorf(ErrorMsgfromUpdateUser)) } else { + fmt.Println(name, " test name ") result := driver.Result(driver.RowsAffected(1)) - mock.ExpectExec(regexp.QuoteMeta(`UPDATE "users" `)).WillReturnResult(result) + return mock.ExpectExec(regexp.QuoteMeta(`UPDATE "users" `)).WillReturnResult(result) } - - // Execute resolver function - c := context.Background() - response, err := resolver1.Mutation().Login(c, tt.req.UserName, tt.req.Password) - - // Assert results - if tt.wantResp != nil && response != nil { - tt.wantResp.RefreshToken = response.RefreshToken - tt.wantResp.Token = response.Token - assert.Equal(t, tt.wantResp, response) - } else { - assert.Equal(t, true, strings.Contains(err.Error(), tt.err.Error())) - assert.Equal(t, tt.wantErr, err != nil) +} +func TestLogin( + t *testing.T, +) { + cases := loadLoginTestCases() + // Create a new instance of the resolver + resolver1 := resolver.Resolver{} + for _, tt := range cases { + t.Run( + tt.name, + func(t *testing.T) { + // Apply mock functions using go-monkey for cases where certain errors are expected + // and defer their resetting + // Handle the case where there is an error loading the config + if tt.name == ErrorFromConfig { + patch := applyPatch(tt.name) + defer patch.Reset() + } + // Handle the case where there is an error creating the JWT service + if tt.name == ErrorFromJwt { + patch := applyJWTPatch(tt.name) + defer patch.Reset() + } + patch := applyGenerateTokenPatchLogin(tt.name) + defer patch.Reset() + // Load the environment variables from a .env file + err := config.LoadEnv() + if err != nil { + fmt.Print("error loading .env file") + } + // Create a mock SQL database connection + db, mock, _ := sqlmock.New() + // Inject mock instance into boil. + oldDB := boil.GetDB() + defer func() { + db.Close() + boil.SetDB(oldDB) + }() + boil.SetDB(db) + // Handle the case where there is an error finding the user + setupLoginSQLMocks(tt.name, mock) + // Handle the case where there is an error while updating the user + setupLoginExpectedExec(tt.name, mock) + c := context.Background() + // Call the login mutation with the given arguments and check the response and error against the expected values + response, err := resolver1.Mutation().Login(c, tt.req.UserName, tt.req.Password) + if tt.wantResp != nil && + response != nil { + tt.wantResp.RefreshToken = response.RefreshToken + tt.wantResp.Token = response.Token + // Assert that the expected response matches the actual response + assert.Equal(t, tt.wantResp, response) + } else { + // Assert that the expected error value matches the actual error value + assert.Equal(t, true, strings.Contains(err.Error(), tt.err.Error())) + assert.Equal(t, tt.wantErr, err != nil) + } + }, + ) } - cleanup() } type changeReq struct { @@ -409,159 +308,100 @@ type changeReq struct { NewPassword string } -func GetChangePasswordTestCases() []struct { +type changePasswordType struct { name string req changeReq wantResp *fm.ChangePasswordResponse wantErr bool -} { - cases := []struct { - name string - req changeReq - wantResp *fm.ChangePasswordResponse - wantErr bool - }{ - ErrorFindingUserCase(), - ErrorPasswordValidationCase(), - ErrorInsecurePasswordCase(), - ErrorUpdateUserCase(), - ErrorFromConfigCase(), - GetSuccessCase(), - } - return cases -} -func ErrorFindingUserCase() struct { - name string - req changeReq - wantResp *fm.ChangePasswordResponse - wantErr bool -} { - return struct { - name string - req changeReq - wantResp *fm.ChangePasswordResponse - wantErr bool - }{ - name: ErrorFindingUser, - req: changeReq{ - OldPassword: TestPassword, - NewPassword: NewPassword, - }, - wantErr: true, - } } -func ErrorPasswordValidationCase() struct { - name string - req changeReq - wantResp *fm.ChangePasswordResponse - wantErr bool -} { - return struct { - name string - req changeReq - wantResp *fm.ChangePasswordResponse - wantErr bool - }{ - name: ErrorPasswordValidation, - req: changeReq{ - OldPassword: TestPassword, - NewPassword: NewPassword, +func loadChangePasswordTestCases() []changePasswordType { + return []changePasswordType{ + { + name: ErrorFindingUser, + req: changeReq{ + OldPassword: TestPassword, + NewPassword: NewPassword, + }, + wantErr: true, + }, + { + name: ErrorPasswordValidation, + req: changeReq{ + OldPassword: TestPassword, + NewPassword: NewPassword, + }, + wantErr: true, + }, + { + name: ErrorInsecurePassword, + req: changeReq{ + OldPassword: OldPassword, + NewPassword: testutls.MockEmail, + }, + wantErr: true, + }, + { + name: ErrorUpdateUser, + req: changeReq{ + OldPassword: OldPassword, + NewPassword: NewPassword, + }, + wantErr: true, + }, + { + name: ErrorFromConfig, + req: changeReq{ + OldPassword: OldPassword, + NewPassword: testutls.MockEmail, + }, + wantErr: true, }, - wantErr: true, - } -} -func ErrorInsecurePasswordCase() struct { - name string - req changeReq - wantResp *fm.ChangePasswordResponse - wantErr bool -} { - return struct { - name string - req changeReq - wantResp *fm.ChangePasswordResponse - wantErr bool - }{ - name: ErrorInsecurePassword, - req: changeReq{ - OldPassword: OldPassword, - NewPassword: testutls.MockEmail, + { + name: SuccessCase, + req: changeReq{ + OldPassword: OldPassword, + NewPassword: NewPassword, + }, + wantResp: &fm.ChangePasswordResponse{ + Ok: true, + }, + wantErr: false, }, - wantErr: true, } } -func ErrorUpdateUserCase() struct { - name string - req changeReq - wantResp *fm.ChangePasswordResponse - wantErr bool -} { - return struct { - name string - req changeReq - wantResp *fm.ChangePasswordResponse - wantErr bool - }{ - name: ErrorUpdateUser, - req: changeReq{ - OldPassword: OldPassword, - NewPassword: NewPassword, - }, - wantErr: true, +func setupSQLExpectWxecution(name string, mock sqlmock.Sqlmock) *sqlmock.ExpectedExec { + if name == SuccessCase { + result := driver.Result(driver.RowsAffected(1)) + return mock.ExpectExec(regexp.QuoteMeta(`UPDATE "users" `)).WillReturnResult(result) } -} - -func ErrorFromConfigCase() struct { - name string - req changeReq - wantResp *fm.ChangePasswordResponse - wantErr bool -} { - return struct { - name string - req changeReq - wantResp *fm.ChangePasswordResponse - wantErr bool - }{ - name: ErrorFromConfig, - req: changeReq{ - OldPassword: OldPassword, - NewPassword: testutls.MockEmail, - }, - wantErr: true, + // Handle the case where there is an error while updating the user's password + if name == ErrorUpdateUser { + return mock.ExpectExec(regexp.QuoteMeta(`UPDATE "users" `)).WillReturnError(fmt.Errorf("errrorr")) } + return nil } -func GetSuccessCase() struct { - name string - req changeReq - wantResp *fm.ChangePasswordResponse - wantErr bool -} { - return struct { - name string - req changeReq - wantResp *fm.ChangePasswordResponse - wantErr bool - }{ - name: SuccessCase, - req: changeReq{ - OldPassword: OldPassword, - NewPassword: NewPassword, - }, - wantResp: &fm.ChangePasswordResponse{ - Ok: true, - }, - wantErr: false, +func setupSQLMocks(name string, mock sqlmock.Sqlmock) *sqlmock.ExpectedQuery { + if name == ErrorFindingUser { + return mock.ExpectQuery(regexp.QuoteMeta(`select * from "users" where "id"=$1`)). + WithArgs(). + WillReturnError(fmt.Errorf("")) } + // Expect a query to get the user by ID to return a row with mock data entered + rows := sqlmock.NewRows([]string{"id", "email", "password"}). + AddRow(testutls.MockID, testutls.MockEmail, OldPasswordHash) + return mock.ExpectQuery(regexp.QuoteMeta(`select * from "users" where "id"=$1`)). + WithArgs(). + WillReturnRows(rows) } + func TestChangePassword( t *testing.T, ) { // Define a struct to represent the change password request - cases := GetChangePasswordTestCases() + cases := loadChangePasswordTestCases() // Create a new instance of the resolver resolver1 := resolver.Resolver{} for _, tt := range cases { @@ -570,9 +410,7 @@ func TestChangePassword( func(t *testing.T) { // Handle the case where there is an error while loading the configuration if tt.name == ErrorFromConfig { - patch := gomonkey.ApplyFunc(config.Load, func() (*config.Configuration, error) { - return nil, fmt.Errorf(ErrorMsgFromConfig) - }) + patch := applyPatch(tt.name) defer patch.Reset() } // Load environment variables @@ -581,94 +419,52 @@ func TestChangePassword( fmt.Print("error loading .env file") } // Create a mock SQL database connection - mock, cleanup, _ := testutls.SetupMockDB(t) + db, mock, _ := sqlmock.New() + // Inject mock instance into boil. + oldDB := boil.GetDB() + defer func() { + db.Close() + boil.SetDB(oldDB) + }() + boil.SetDB(db) // Handle the case where there is an error while finding the user - if tt.name == ErrorFindingUser { - mock.ExpectQuery(regexp.QuoteMeta(`select * from "users" where "id"=$1`)). - WithArgs(). - WillReturnError(fmt.Errorf("")) - } - // Expect a query to get the user by ID to return a row with mock data entered - rows := sqlmock.NewRows([]string{"id", "email", "password"}). - AddRow(testutls.MockID, testutls.MockEmail, OldPasswordHash) - mock.ExpectQuery(regexp.QuoteMeta(`select * from "users" where "id"=$1`)). - WithArgs(). - WillReturnRows(rows) + setupSQLMocks(tt.name, mock) + // Handle the case where the password update is successful - if tt.name == SuccessCase { - result := driver.Result(driver.RowsAffected(1)) - mock.ExpectExec(regexp.QuoteMeta(`UPDATE "users" `)).WillReturnResult(result) - } - // Handle the case where there is an error while updating the user's password - if tt.name == ErrorUpdateUser { - mock.ExpectExec(regexp.QuoteMeta(`UPDATE "users" `)).WillReturnError(fmt.Errorf("errrorr")) + if tt.name == SuccessCase || tt.name == ErrorUpdateUser { + setupSQLExpectWxecution(tt.name, mock) } + + // Handle the case where there is an error while updating the user's passwor + // Set up the context with the mock user c := context.Background() ctx := context.WithValue(c, testutls.UserKey, testutls.MockUser()) + // Call the ChangePassword mutation and check the response and error against the expected values response, err := resolver1.Mutation().ChangePassword(ctx, tt.req.OldPassword, tt.req.NewPassword) if tt.wantResp != nil { + // Assert that the expected response matches the actual response assert.Equal(t, tt.wantResp, response) } // Assert that the expected error value matches the actual error value assert.Equal(t, tt.wantErr, err != nil) - cleanup() }, ) } } -func TestRefreshToken(t *testing.T) { - cases := prepareRefreshTokenCases() - - resolver := resolver.Resolver{} - - for _, tt := range cases { - t.Run(tt.name, func(t *testing.T) { - mock, cleanup, _ := testutls.SetupMockDB(t) - - setupMockDBExpectations(tt.name, mock) - - mockConfigLoad := prepareMockConfigLoad(tt.name) - defer mockConfigLoad.Reset() - - mockJWTService := prepareMockJWTService(tt.name) - defer mockJWTService.Reset() - - mockTokenGeneration := prepareMockTokenGeneration(tt.name) - defer mockTokenGeneration.Reset() - - ctx := prepareContextRefereshToken() - - response, err := resolver.Mutation().RefreshToken(ctx, tt.req) - - if tt.wantResp != nil && response != nil { - tt.wantResp.Token = response.Token - assert.Equal(t, tt.wantResp, response) - } else { - assert.Equal(t, true, strings.Contains(err.Error(), tt.err.Error())) - } - cleanup() - }) - } -} - -func prepareRefreshTokenCases() []struct { +type refereshTokenType struct { name string req string wantResp *fm.RefreshTokenResponse wantErr bool err error -} { - cases := []struct { - name string - req string - wantResp *fm.RefreshTokenResponse - wantErr bool - err error - }{ +} + +func loadRefereshTokenCases() []refereshTokenType { + return []refereshTokenType{ { name: ErrorInvalidToken, req: TestToken, @@ -701,68 +497,107 @@ func prepareRefreshTokenCases() []struct { wantErr: false, }, } - return cases } -func setupMockDBExpectations(name string, mock sqlmock.Sqlmock) { - switch name { - case ErrorInvalidToken: - mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (token=$1) LIMIT 1;`)). +func setupSQLExpectation(name string, mock sqlmock.Sqlmock) *sqlmock.ExpectedQuery { + if name == ErrorInvalidToken { + return mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (token=$1) LIMIT 1;`)). WithArgs(). WillReturnError(fmt.Errorf(ErrorMsginvalidToken)) - case SuccessCase: - rows := sqlmock.NewRows([]string{"id", "email", "token", "role_id"}). - AddRow(1, testutls.MockEmail, testutls.MockToken, 1) - mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (token=$1) LIMIT 1;`)). - WithArgs(). - WillReturnRows(rows) - rows = sqlmock.NewRows([]string{"id", "name"}). + } + rows := sqlmock.NewRows([]string{"id", "email", "token", "role_id"}). + AddRow(1, testutls.MockEmail, testutls.MockToken, 1) + mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (token=$1) LIMIT 1;`)). + WithArgs(). + WillReturnRows(rows) + + if name == SuccessCase { + rows := sqlmock.NewRows([]string{"id", "name"}). AddRow(1, "ADMIN") - mock.ExpectQuery(regexp.QuoteMeta(`SELECT "roles".* FROM "roles" WHERE ("id" = $1) LIMIT 1`)). + return mock.ExpectQuery(regexp.QuoteMeta(`SELECT "roles".* FROM "roles" WHERE ("id" = $1) LIMIT 1`)). WithArgs([]driver.Value{1}...). WillReturnRows(rows) - case ErrorFromConfig: - // Expectation for error loading the config - mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (token=$1) LIMIT 1;`)). - WithArgs(). - WillReturnError(fmt.Errorf(ErrorMsgFromConfig)) - case ErrorFromJwt: - // Expectation for error in creating the JWT service - mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (token=$1) LIMIT 1;`)). - WithArgs(). - WillReturnRows(sqlmock.NewRows([]string{"id", "email", "token", "role_id"})) } + return nil } - -func prepareMockConfigLoad(name string) *gomonkey.Patches { +func applyPatch(name string) *gomonkey.Patches { return gomonkey.ApplyFunc(config.Load, func() (*config.Configuration, error) { if name == ErrorFromConfig { - return nil, fmt.Errorf(ErrorMsgFromConfig) + return nil, fmt.Errorf("error in loading config") + } else { + return &config.Configuration{}, nil } - return &config.Configuration{}, nil }) } -func prepareMockJWTService(name string) *gomonkey.Patches { +func applyJWTPatch(name string) *gomonkey.Patches { + tg := jwt.Service{} return gomonkey.ApplyFunc(service.JWT, func(cfg *config.Configuration) (jwt.Service, error) { if name == ErrorFromJwt { - return jwt.Service{}, fmt.Errorf(ErrorMsgFromJwt) + return tg, fmt.Errorf(ErrorMsgFromJwt) + } else { + return tg, nil } - return jwt.Service{}, nil }) } -func prepareMockTokenGeneration(name string) *gomonkey.Patches { - return gomonkey.ApplyMethod(reflect.TypeOf(jwt.Service{}), "GenerateToken", +func applyGenerateTokenPatch(name string) *gomonkey.Patches { + tg := jwt.Service{} + return gomonkey.ApplyMethod(reflect.TypeOf(tg), "GenerateToken", func(jwt.Service, *models.User) (string, error) { if name == ErrorFromGenerateToken { return "", resultwrapper.ErrUnauthorized + } else { + return "token", nil } - return "token", nil }) } +func TestRefreshToken(t *testing.T) { + cases := loadRefereshTokenCases() + // Create a new instance of the resolver + resolver1 := resolver.Resolver{} + for _, tt := range cases { + t.Run( + tt.name, + func(t *testing.T) { + // Create a mock SQL database connection + db, mock, _ := sqlmock.New() + // Inject mock instance into boil. + oldDB := boil.GetDB() + defer func() { + db.Close() + boil.SetDB(oldDB) + }() + boil.SetDB(db) + // Handle the case where authentication token is invalid + setupSQLExpectation(tt.name, mock) + // Handle the case where there is an error loading the config + patch := applyPatch(tt.name) + defer patch.Reset() + //initialize a jwt service + // Handle the case where there is an error creating the JWT service + patchJWT := applyJWTPatch(tt.name) + defer patchJWT.Reset() + // Handle the case where there is an error form token generation service + patchGenerateToken := applyGenerateTokenPatch(tt.name) + defer patchGenerateToken.Reset() + // Set up the context with the mock user + c := context.Background() + ctx := context.WithValue(c, testutls.UserKey, testutls.MockUser()) + // Call the refresh token mutation with the given arguments and check the response and error against the expected values + response, err := resolver1.Mutation(). + RefreshToken(ctx, tt.req) + if tt.wantResp != nil && + response != nil { + tt.wantResp.Token = response.Token + // Assert that the expected response matches the actual response + assert.Equal(t, tt.wantResp, response) + } else { + // Assert that the expected error value matches the actual error value + assert.Equal(t, true, strings.Contains(err.Error(), tt.err.Error())) + } -func prepareContextRefereshToken() context.Context { - c := context.Background() - return context.WithValue(c, testutls.UserKey, testutls.MockUser()) + }, + ) + } } From d2c8efb3f3535f2309a77e31c1273f8a36247464 Mon Sep 17 00:00:00 2001 From: HIMANSHU Date: Sun, 31 Mar 2024 03:19:11 +0530 Subject: [PATCH 16/39] role mutation resolver test --- resolver/role_mutations.resolvers_test.go | 190 ++++++++++++---------- 1 file changed, 100 insertions(+), 90 deletions(-) diff --git a/resolver/role_mutations.resolvers_test.go b/resolver/role_mutations.resolvers_test.go index 31f34db9..7023a355 100644 --- a/resolver/role_mutations.resolvers_test.go +++ b/resolver/role_mutations.resolvers_test.go @@ -11,79 +11,118 @@ import ( "go-template/resolver" "testing" - "github.com/volatiletech/null/v8" - "github.com/agiledragon/gomonkey/v2" + null "github.com/volatiletech/null/v8" fm "go-template/gqlmodels" "github.com/stretchr/testify/assert" ) -func GetCreateRoleTestCases() []struct { +type createRoleType struct { name string req fm.RoleCreateInput wantResp *fm.RolePayload wantErr bool -} { - cases := []struct { - name string - req fm.RoleCreateInput - wantResp *fm.RolePayload - wantErr bool - }{ - { - name: ErrorFromRedisCache, - req: fm.RoleCreateInput{}, - wantResp: &fm.RolePayload{}, - wantErr: true, + init func() *gomonkey.Patches +} + +func errorFromRedisCase() createRoleType { + return createRoleType{ + name: ErrorFromRedisCache, + req: fm.RoleCreateInput{}, + wantResp: &fm.RolePayload{}, + wantErr: true, + init: func() *gomonkey.Patches { + return gomonkey.ApplyFunc(rediscache.GetUser, + func(userID int, ctx context.Context) (*models.User, error) { + return nil, errors.New("redis cache") + }) }, - { - name: ErrorFromGetRole, - req: fm.RoleCreateInput{}, - wantResp: &fm.RolePayload{}, - wantErr: true, + } +} + +func errorFromGetRoleCase() createRoleType { + return createRoleType{ + name: ErrorFromGetRole, + req: fm.RoleCreateInput{}, + wantResp: &fm.RolePayload{}, + wantErr: true, + init: func() *gomonkey.Patches { + return gomonkey.ApplyFunc(rediscache.GetRole, + func(roleID int, ctx context.Context) (*models.Role, error) { + return nil, errors.New("data") + }) }, - { - name: ErrorUnauthorizedUser, - req: fm.RoleCreateInput{ - Name: UserRoleName, - AccessLevel: int(constants.UserRole), - }, - wantResp: &fm.RolePayload{}, + } +} +func errorUnauthorizedUserCase() createRoleType { + return createRoleType{ + name: ErrorUnauthorizedUser, + req: fm.RoleCreateInput{ + Name: UserRoleName, + AccessLevel: int(constants.UserRole), }, - - { - name: SuccessCase, - req: fm.RoleCreateInput{ - Name: UserRoleName, - AccessLevel: int(constants.UserRole), - }, - wantResp: &fm.RolePayload{Role: &fm.Role{ - - AccessLevel: int(constants.UserRole), - Name: UserRoleName, - }}, + wantResp: &fm.RolePayload{}, + init: func() *gomonkey.Patches { + return gomonkey.ApplyFunc(rediscache.GetRole, + func(roleID int, ctx context.Context) (*models.Role, error) { + return &models.Role{ + AccessLevel: int(constants.UserRole), + Name: UserRoleName, + }, nil + }) }, - { - name: ErrorFromCreateRole, - req: fm.RoleCreateInput{ - Name: UserRoleName, - AccessLevel: int(constants.UserRole), - }, - wantErr: true, + } +} +func successCase() createRoleType { + return createRoleType{ + name: SuccessCase, + req: fm.RoleCreateInput{ + Name: UserRoleName, + AccessLevel: int(constants.UserRole), }, + wantResp: &fm.RolePayload{Role: &fm.Role{ + AccessLevel: int(constants.UserRole), + Name: UserRoleName, + }}, + wantErr: false, + init: func() *gomonkey.Patches { return nil }, } - return cases } -func ApplyPatchUserId() *gomonkey.Patches { +func errorFromCreateRoleCase() createRoleType { + return createRoleType{ + name: ErrorFromCreateRole, + req: fm.RoleCreateInput{ + Name: UserRoleName, + AccessLevel: int(constants.UserRole), + }, + wantErr: true, + init: func() *gomonkey.Patches { + return gomonkey.ApplyFunc(daos.CreateRole, + func(role models.Role, ctx context.Context) (models.Role, error) { + return models.Role{}, errors.New("error") + }) + }, + } +} +func loadTestCases() []createRoleType { + return []createRoleType{ + errorFromRedisCase(), + errorFromGetRoleCase(), + errorUnauthorizedUserCase(), + successCase(), + errorFromCreateRoleCase(), + } +} +func applyUserIdPatch() *gomonkey.Patches { return gomonkey.ApplyFunc(auth.UserIDFromContext, func(ctx context.Context) int { return 1 }) } -func ApplypatchGetUser() *gomonkey.Patches { +func applyGetUserPatch() *gomonkey.Patches { return gomonkey.ApplyFunc(rediscache.GetUser, func(userID int, ctx context.Context) (*models.User, error) { return &models.User{ @@ -91,7 +130,7 @@ func ApplypatchGetUser() *gomonkey.Patches { }, nil }) } -func ApplypatchGetRole() *gomonkey.Patches { +func applyGetRolePatch() *gomonkey.Patches { return gomonkey.ApplyFunc(rediscache.GetRole, func(roleID int, ctx context.Context) (*models.Role, error) { return &models.Role{ @@ -100,12 +139,12 @@ func ApplypatchGetRole() *gomonkey.Patches { }, nil }) } -func ApplypatchCreateRole() *gomonkey.Patches { +func applyCreateRolePatch() *gomonkey.Patches { return gomonkey.ApplyFunc(daos.CreateRole, func(role models.Role, ctx context.Context) (models.Role, error) { return models.Role{ - AccessLevel: int(constants.UserRole), - Name: UserRoleName, + AccessLevel: int(constants.SuperAdminRole), + Name: SuperAdminRoleName, }, nil }) } @@ -115,19 +154,20 @@ func TestCreateRole( t *testing.T, ) { // Define test cases, each case has a name, request input, expected response, and error. - cases := GetCreateRoleTestCases() + cases := loadTestCases() // Create a new resolver instance. resolver1 := resolver.Resolver{} + // Loop through each test case. for _, tt := range cases { // Mocking rediscache.GetUserID function - patchUserID := ApplyPatchUserId() + patchUserID := applyUserIdPatch() // Mocking rediscache.GetUser function - patchGetUser := ApplypatchGetUser() + patchGetUser := applyGetUserPatch() // Mocking rediscache.GetRole function - patchGetRole := ApplypatchGetRole() + patchGetRole := applyGetRolePatch() // Mocking daos.CreateRole function - patchCreateRole := ApplypatchCreateRole() + patchCreateRole := applyCreateRolePatch() // Defer resetting of the monkey patches. defer patchUserID.Reset() defer patchGetUser.Reset() @@ -136,38 +176,8 @@ func TestCreateRole( t.Run(tt.name, func(t *testing.T) { // Apply additional monkey patches based on test case name. - if tt.name == ErrorFromRedisCache { - patchGetUser := gomonkey.ApplyFunc(rediscache.GetUser, - func(userID int, ctx context.Context) (*models.User, error) { - return nil, errors.New("redis cache") - }) - defer patchGetUser.Reset() - } - if tt.name == ErrorFromGetRole { - patchGetRole := gomonkey.ApplyFunc(rediscache.GetRole, - func(roleID int, ctx context.Context) (*models.Role, error) { - return nil, errors.New("data") - }) - defer patchGetRole.Reset() - } - if tt.name == ErrorUnauthorizedUser { - patchGetRole := gomonkey.ApplyFunc(rediscache.GetRole, - func(roleID int, ctx context.Context) (*models.Role, error) { - return &models.Role{ - AccessLevel: int(constants.UserRole), - Name: UserRoleName, - }, nil - }) - defer patchGetRole.Reset() - } - if tt.name == ErrorFromCreateRole { - patchCreateRole := gomonkey.ApplyFunc(daos.CreateRole, - func(role models.Role, ctx context.Context) (models.Role, error) { - return models.Role{}, errors.New("error") - }) - - defer patchCreateRole.Reset() - } + patch := tt.init() + defer patch.Reset() // Create a new context c := context.Background() // Call the resolver function From 925d53dba5db94bb16f96945201b0d86f5274e90 Mon Sep 17 00:00:00 2001 From: HIMANSHU Date: Mon, 1 Apr 2024 15:52:51 +0530 Subject: [PATCH 17/39] role mutation resolver test comments resolved --- resolver/role_mutations.resolvers_test.go | 64 +++++------------------ 1 file changed, 14 insertions(+), 50 deletions(-) diff --git a/resolver/role_mutations.resolvers_test.go b/resolver/role_mutations.resolvers_test.go index 7023a355..b6c2091f 100644 --- a/resolver/role_mutations.resolvers_test.go +++ b/resolver/role_mutations.resolvers_test.go @@ -5,14 +5,12 @@ import ( "errors" "go-template/daos" "go-template/internal/constants" - "go-template/internal/middleware/auth" "go-template/models" "go-template/pkg/utl/rediscache" "go-template/resolver" "testing" "github.com/agiledragon/gomonkey/v2" - null "github.com/volatiletech/null/v8" fm "go-template/gqlmodels" @@ -87,7 +85,15 @@ func successCase() createRoleType { Name: UserRoleName, }}, wantErr: false, - init: func() *gomonkey.Patches { return nil }, + init: func() *gomonkey.Patches { + return gomonkey.ApplyFunc(daos.CreateRole, + func(role models.Role, ctx context.Context) (models.Role, error) { + return models.Role{ + AccessLevel: int(constants.SuperAdminRole), + Name: SuperAdminRoleName, + }, nil + }) + }, } } @@ -116,38 +122,6 @@ func loadTestCases() []createRoleType { errorFromCreateRoleCase(), } } -func applyUserIdPatch() *gomonkey.Patches { - return gomonkey.ApplyFunc(auth.UserIDFromContext, - func(ctx context.Context) int { - return 1 - }) -} -func applyGetUserPatch() *gomonkey.Patches { - return gomonkey.ApplyFunc(rediscache.GetUser, - func(userID int, ctx context.Context) (*models.User, error) { - return &models.User{ - RoleID: null.IntFrom(1), - }, nil - }) -} -func applyGetRolePatch() *gomonkey.Patches { - return gomonkey.ApplyFunc(rediscache.GetRole, - func(roleID int, ctx context.Context) (*models.Role, error) { - return &models.Role{ - AccessLevel: int(constants.SuperAdminRole), - Name: SuperAdminRoleName, - }, nil - }) -} -func applyCreateRolePatch() *gomonkey.Patches { - return gomonkey.ApplyFunc(daos.CreateRole, - func(role models.Role, ctx context.Context) (models.Role, error) { - return models.Role{ - AccessLevel: int(constants.SuperAdminRole), - Name: SuperAdminRoleName, - }, nil - }) -} // TestCreateRole tests the CreateRole mutation function. func TestCreateRole( @@ -157,27 +131,16 @@ func TestCreateRole( cases := loadTestCases() // Create a new resolver instance. resolver1 := resolver.Resolver{} - // Loop through each test case. for _, tt := range cases { // Mocking rediscache.GetUserID function - patchUserID := applyUserIdPatch() - // Mocking rediscache.GetUser function - patchGetUser := applyGetUserPatch() - // Mocking rediscache.GetRole function - patchGetRole := applyGetRolePatch() - // Mocking daos.CreateRole function - patchCreateRole := applyCreateRolePatch() - // Defer resetting of the monkey patches. - defer patchUserID.Reset() - defer patchGetUser.Reset() - defer patchGetRole.Reset() - defer patchCreateRole.Reset() t.Run(tt.name, func(t *testing.T) { // Apply additional monkey patches based on test case name. patch := tt.init() - defer patch.Reset() + if patch != nil { + defer patch.Reset() + } // Create a new context c := context.Background() // Call the resolver function @@ -185,9 +148,10 @@ func TestCreateRole( // Check if the error matches the expected error if tt.wantErr { assert.NotNil(t, err) + } else { + assert.Equal(t, tt.wantResp, response) } // Check if the response matches the expected response - assert.Equal(t, tt.wantResp, response) }) } } From 8cd7d7dc4178273e56e915a11fc9bd8aaccdd409 Mon Sep 17 00:00:00 2001 From: HIMANSHU Date: Mon, 1 Apr 2024 16:12:39 +0530 Subject: [PATCH 18/39] user mutaion tests refactor comments resolved --- resolver/role_mutations.resolvers_test.go | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/resolver/role_mutations.resolvers_test.go b/resolver/role_mutations.resolvers_test.go index b6c2091f..9b05d9c0 100644 --- a/resolver/role_mutations.resolvers_test.go +++ b/resolver/role_mutations.resolvers_test.go @@ -138,9 +138,6 @@ func TestCreateRole( func(t *testing.T) { // Apply additional monkey patches based on test case name. patch := tt.init() - if patch != nil { - defer patch.Reset() - } // Create a new context c := context.Background() // Call the resolver function @@ -151,7 +148,9 @@ func TestCreateRole( } else { assert.Equal(t, tt.wantResp, response) } - // Check if the response matches the expected response + if patch != nil { + patch.Reset() + } }) } } From ddd05ae07f8ebf8a19c9076a3520e467ba72b081 Mon Sep 17 00:00:00 2001 From: HIMANSHU Date: Mon, 1 Apr 2024 18:27:02 +0530 Subject: [PATCH 19/39] auth mutation comments resolved --- resolver/auth_mutations.resolvers_test.go | 652 +++++++++++++--------- 1 file changed, 390 insertions(+), 262 deletions(-) diff --git a/resolver/auth_mutations.resolvers_test.go b/resolver/auth_mutations.resolvers_test.go index 1ee2c847..724b3acf 100644 --- a/resolver/auth_mutations.resolvers_test.go +++ b/resolver/auth_mutations.resolvers_test.go @@ -66,16 +66,17 @@ type loginArgs struct { Password string } -type LoginType struct { +type loginType struct { name string req loginArgs wantResp *fm.LoginResponse wantErr bool err error + init func(mock sqlmock.Sqlmock) *gomonkey.Patches } -func errorFindingUserCase() LoginType { - return LoginType{ +func errorFindingUserCase() loginType { + return loginType{ name: ErrorFindingUser, req: loginArgs{ UserName: TestUsername, @@ -83,10 +84,19 @@ func errorFindingUserCase() LoginType { }, wantErr: true, err: fmt.Errorf(ErrorMsgFindingUser), + init: func(mock sqlmock.Sqlmock) *gomonkey.Patches { + mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (username=$1) LIMIT 1;`)). + WithArgs(). + WillReturnError(fmt.Errorf(ErrorMsgFindingUser)) + tg := jwt.Service{} + return gomonkey.ApplyFunc(tg.GenerateToken, func(u *models.User) (string, error) { + return "", nil + }) + }, } } -func errorPasswordValidationCase() LoginType { - return LoginType{ +func errorPasswordValidationCase() loginType { + return loginType{ name: ErrorPasswordValidation, req: loginArgs{ UserName: testutls.MockEmail, @@ -94,11 +104,22 @@ func errorPasswordValidationCase() LoginType { }, wantErr: true, err: fmt.Errorf(ErrorMsgPasswordValidation), + init: func(mock sqlmock.Sqlmock) *gomonkey.Patches { + rows := sqlmock.NewRows([]string{"id", "password", "active", "role_id"}). + AddRow(testutls.MockID, TestPasswordHash, true, 1) + mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (username=$1) LIMIT 1;`)). + WithArgs(). + WillReturnRows(rows) + tg := jwt.Service{} + return gomonkey.ApplyFunc(tg.GenerateToken, func(u *models.User) (string, error) { + return "", nil + }) + }, } } -func errorActiveStatusCase() LoginType { - return LoginType{ +func errorActiveStatusCase() loginType { + return loginType{ name: ErrorActiveStatus, req: loginArgs{ UserName: testutls.MockEmail, @@ -106,10 +127,21 @@ func errorActiveStatusCase() LoginType { }, wantErr: true, err: resultwrapper.ErrUnauthorized, + init: func(mock sqlmock.Sqlmock) *gomonkey.Patches { + rows := sqlmock.NewRows([]string{"id", "password", "active", "role_id"}). + AddRow(testutls.MockID, OldPasswordHash, true, 1) + mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (username=$1) LIMIT 1;`)). + WithArgs(). + WillReturnRows(rows) + tg := jwt.Service{} + return gomonkey.ApplyFunc(tg.GenerateToken, func(u *models.User) (string, error) { + return "", nil + }) + }, } } -func errorFromConfigCase() LoginType { - return LoginType{ +func errorFromConfigCase() loginType { + return loginType{ name: ErrorFromConfig, req: loginArgs{ UserName: testutls.MockEmail, @@ -117,11 +149,21 @@ func errorFromConfigCase() LoginType { }, wantErr: true, err: fmt.Errorf(ErrorMsgFromConfig), + init: func(mock sqlmock.Sqlmock) *gomonkey.Patches { + rows := sqlmock.NewRows([]string{"id", "password", "active", "role_id"}). + AddRow(testutls.MockID, OldPasswordHash, true, 1) + mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (username=$1) LIMIT 1;`)). + WithArgs(). + WillReturnRows(rows) + return gomonkey.ApplyFunc(config.Load, func() (*config.Configuration, error) { + return nil, fmt.Errorf("error in loading config") + }) + }, } } -func errorFromJwtCase() LoginType { - return LoginType{ +func errorFromJwtCase() loginType { + return loginType{ name: ErrorFromJwt, req: loginArgs{ UserName: testutls.MockEmail, @@ -129,10 +171,21 @@ func errorFromJwtCase() LoginType { }, wantErr: true, err: fmt.Errorf(ErrorMsgFromJwt), + init: func(mock sqlmock.Sqlmock) *gomonkey.Patches { + rows := sqlmock.NewRows([]string{"id", "password", "active", "role_id"}). + AddRow(testutls.MockID, OldPasswordHash, true, 1) + mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (username=$1) LIMIT 1;`)). + WithArgs(). + WillReturnRows(rows) + tg := jwt.Service{} + return gomonkey.ApplyFunc(service.JWT, func(cfg *config.Configuration) (jwt.Service, error) { + return tg, fmt.Errorf(ErrorMsgFromJwt) + }) + }, } } -func errorFromGenerateTokenCase() LoginType { - return LoginType{ +func errorFromGenerateTokenCase() loginType { + return loginType{ name: ErrorFromGenerateToken, req: loginArgs{ UserName: testutls.MockEmail, @@ -140,10 +193,21 @@ func errorFromGenerateTokenCase() LoginType { }, wantErr: true, err: resultwrapper.ErrUnauthorized, + init: func(mock sqlmock.Sqlmock) *gomonkey.Patches { + rows := sqlmock.NewRows([]string{"id", "password", "active", "role_id"}). + AddRow(testutls.MockID, OldPasswordHash, true, 1) + mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (username=$1) LIMIT 1;`)). + WithArgs(). + WillReturnRows(rows) + tg := jwt.Service{} + return gomonkey.ApplyFunc(tg.GenerateToken, func(u *models.User) (string, error) { + return "", resultwrapper.ErrUnauthorized + }) + }, } } -func errorUpdateUserCase() LoginType { - return LoginType{ +func errorUpdateUserCase() loginType { + return loginType{ name: ErrorUpdateUser, req: loginArgs{ UserName: testutls.MockEmail, @@ -151,10 +215,22 @@ func errorUpdateUserCase() LoginType { }, wantErr: true, err: fmt.Errorf(ErrorMsgfromUpdateUser), + init: func(mock sqlmock.Sqlmock) *gomonkey.Patches { + rows := sqlmock.NewRows([]string{"id", "name"}). + AddRow(1, "ADMIN") + mock.ExpectQuery(regexp.QuoteMeta(`SELECT "roles".* FROM "roles" WHERE ("id" = $1) LIMIT 1`)). + WithArgs([]driver.Value{1}...). + WillReturnRows(rows) + mock.ExpectExec(regexp.QuoteMeta(`UPDATE "users" `)).WillReturnError(fmt.Errorf(ErrorMsgfromUpdateUser)) + tg := jwt.Service{} + return gomonkey.ApplyFunc(tg.GenerateToken, func(u *models.User) (string, error) { + return "", nil + }) + }, } } -func loginSuccessCase() LoginType { - return LoginType{ +func loginSuccessCase() loginType { + return loginType{ name: SuccessCase, req: loginArgs{ UserName: testutls.MockEmail, @@ -164,10 +240,23 @@ func loginSuccessCase() LoginType { Token: "jwttokenstring", RefreshToken: TestToken, }, + init: func(mock sqlmock.Sqlmock) *gomonkey.Patches { + rows := sqlmock.NewRows([]string{"id", "name"}). + AddRow(1, "ADMIN") + mock.ExpectQuery(regexp.QuoteMeta(`SELECT "roles".* FROM "roles" WHERE ("id" = $1) LIMIT 1`)). + WithArgs([]driver.Value{1}...). + WillReturnRows(rows) + result := driver.Result(driver.RowsAffected(1)) + mock.ExpectExec(regexp.QuoteMeta(`UPDATE "users" `)).WillReturnResult(result) + tg := jwt.Service{} + return gomonkey.ApplyFunc(tg.GenerateToken, func(u *models.User) (string, error) { + return "", nil + }) + }, } } -func loadLoginTestCases() []LoginType { - return []LoginType{ +func loadLoginTestCases() []loginType { + return []loginType{ errorFindingUserCase(), errorPasswordValidationCase(), errorActiveStatusCase(), @@ -178,70 +267,6 @@ func loadLoginTestCases() []LoginType { loginSuccessCase(), } } - -func applyGenerateTokenPatchLogin(name string) *gomonkey.Patches { - tg := jwt.Service{} - return gomonkey.ApplyFunc(tg.GenerateToken, func(u *models.User) (string, error) { - if name == ErrorFromGenerateToken { - return "", resultwrapper.ErrUnauthorized - } else { - return "", nil - } - }) -} - -func setupLoginSQLMocks(name string, mock sqlmock.Sqlmock) *sqlmock.ExpectedQuery { - if name == ErrorFindingUser { - // get user by username - return mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (username=$1) LIMIT 1;`)). - WithArgs(). - WillReturnError(fmt.Errorf(ErrorMsgFindingUser)) - } - // Handle the case where there is an error validating the password - if name == ErrorPasswordValidation { - // get user by username - rows := sqlmock.NewRows([]string{"id", "password", "active", "role_id"}). - AddRow(testutls.MockID, TestPasswordHash, true, 1) - mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (username=$1) LIMIT 1;`)). - WithArgs(). - WillReturnRows(rows) - } - // Handle the case where the user is not active - if name == ErrorActiveStatus { - // get user by username - rows := sqlmock.NewRows([]string{"id", "password", "active", "role_id"}). - AddRow(testutls.MockID, OldPasswordHash, false, 1) - mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (username=$1) LIMIT 1;`)). - WithArgs(). - WillReturnRows(rows) - } - // get user by username - rows := sqlmock.NewRows([]string{"id", "password", "active", "role_id"}). - AddRow(testutls.MockID, OldPasswordHash, true, 1) - mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (username=$1) LIMIT 1;`)). - WithArgs(). - WillReturnRows(rows) - // Apply mock behavior for a successful query result - if name == SuccessCase || name == ErrorUpdateUser { - rows := sqlmock.NewRows([]string{"id", "name"}). - AddRow(1, "ADMIN") - mock.ExpectQuery(regexp.QuoteMeta(`SELECT "roles".* FROM "roles" WHERE ("id" = $1) LIMIT 1`)). - WithArgs([]driver.Value{1}...). - WillReturnRows(rows) - } - return nil -} - -func setupLoginExpectedExec(name string, mock sqlmock.Sqlmock) *sqlmock.ExpectedExec { - if name == ErrorUpdateUser { - fmt.Println(name, " test name ") - return mock.ExpectExec(regexp.QuoteMeta(`UPDATE "users" `)).WillReturnError(fmt.Errorf(ErrorMsgfromUpdateUser)) - } else { - fmt.Println(name, " test name ") - result := driver.Result(driver.RowsAffected(1)) - return mock.ExpectExec(regexp.QuoteMeta(`UPDATE "users" `)).WillReturnResult(result) - } -} func TestLogin( t *testing.T, ) { @@ -252,26 +277,6 @@ func TestLogin( t.Run( tt.name, func(t *testing.T) { - // Apply mock functions using go-monkey for cases where certain errors are expected - // and defer their resetting - // Handle the case where there is an error loading the config - if tt.name == ErrorFromConfig { - patch := applyPatch(tt.name) - defer patch.Reset() - } - // Handle the case where there is an error creating the JWT service - if tt.name == ErrorFromJwt { - patch := applyJWTPatch(tt.name) - defer patch.Reset() - } - patch := applyGenerateTokenPatchLogin(tt.name) - defer patch.Reset() - // Load the environment variables from a .env file - err := config.LoadEnv() - if err != nil { - fmt.Print("error loading .env file") - } - // Create a mock SQL database connection db, mock, _ := sqlmock.New() // Inject mock instance into boil. oldDB := boil.GetDB() @@ -280,10 +285,12 @@ func TestLogin( boil.SetDB(oldDB) }() boil.SetDB(db) - // Handle the case where there is an error finding the user - setupLoginSQLMocks(tt.name, mock) - // Handle the case where there is an error while updating the user - setupLoginExpectedExec(tt.name, mock) + patch := tt.init(mock) + // Load the environment variables from a .env file + err := config.LoadEnv() + if err != nil { + fmt.Print("error loading .env file") + } c := context.Background() // Call the login mutation with the given arguments and check the response and error against the expected values response, err := resolver1.Mutation().Login(c, tt.req.UserName, tt.req.Password) @@ -298,6 +305,7 @@ func TestLogin( assert.Equal(t, true, strings.Contains(err.Error(), tt.err.Error())) assert.Equal(t, tt.wantErr, err != nil) } + patch.Reset() }, ) } @@ -313,90 +321,138 @@ type changePasswordType struct { req changeReq wantResp *fm.ChangePasswordResponse wantErr bool + init func(mock sqlmock.Sqlmock) *gomonkey.Patches } -func loadChangePasswordTestCases() []changePasswordType { - return []changePasswordType{ - { - name: ErrorFindingUser, - req: changeReq{ - OldPassword: TestPassword, - NewPassword: NewPassword, - }, - wantErr: true, - }, - { - name: ErrorPasswordValidation, - req: changeReq{ - OldPassword: TestPassword, - NewPassword: NewPassword, - }, - wantErr: true, +func changePasswordErrorFindingUserCase() changePasswordType { + return changePasswordType{ + name: ErrorFindingUser, + req: changeReq{ + OldPassword: TestPassword, + NewPassword: NewPassword, }, - { - name: ErrorInsecurePassword, - req: changeReq{ - OldPassword: OldPassword, - NewPassword: testutls.MockEmail, - }, - wantErr: true, + wantErr: true, + init: func(mock sqlmock.Sqlmock) *gomonkey.Patches { + mock.ExpectQuery(regexp.QuoteMeta(`select * from "users" where "id"=$1`)). + WithArgs(). + WillReturnError(fmt.Errorf("")) + return nil }, - { - name: ErrorUpdateUser, - req: changeReq{ - OldPassword: OldPassword, - NewPassword: NewPassword, - }, - wantErr: true, + } +} +func changePasswordErrorPasswordValidationcase() changePasswordType { + return changePasswordType{ + name: ErrorPasswordValidation, + req: changeReq{ + OldPassword: TestPassword, + NewPassword: NewPassword, }, - { - name: ErrorFromConfig, - req: changeReq{ - OldPassword: OldPassword, - NewPassword: testutls.MockEmail, - }, - wantErr: true, + wantErr: true, + init: func(mock sqlmock.Sqlmock) *gomonkey.Patches { + rows := sqlmock.NewRows([]string{"id", "email", "password"}). + AddRow(testutls.MockID, testutls.MockEmail, OldPasswordHash) + mock.ExpectQuery(regexp.QuoteMeta(`select * from "users" where "id"=$1`)). + WithArgs(). + WillReturnRows(rows) + return nil }, + } +} - { - name: SuccessCase, - req: changeReq{ - OldPassword: OldPassword, - NewPassword: NewPassword, - }, - wantResp: &fm.ChangePasswordResponse{ - Ok: true, - }, - wantErr: false, +func changePasswordErrorInsecurePasswordCase() changePasswordType { + return changePasswordType{ + name: ErrorInsecurePassword, + req: changeReq{ + OldPassword: OldPassword, + NewPassword: testutls.MockEmail, + }, + wantErr: true, + init: func(mock sqlmock.Sqlmock) *gomonkey.Patches { + rows := sqlmock.NewRows([]string{"id", "email", "password"}). + AddRow(testutls.MockID, testutls.MockEmail, OldPasswordHash) + mock.ExpectQuery(regexp.QuoteMeta(`select * from "users" where "id"=$1`)). + WithArgs(). + WillReturnRows(rows) + return nil }, } } -func setupSQLExpectWxecution(name string, mock sqlmock.Sqlmock) *sqlmock.ExpectedExec { - if name == SuccessCase { - result := driver.Result(driver.RowsAffected(1)) - return mock.ExpectExec(regexp.QuoteMeta(`UPDATE "users" `)).WillReturnResult(result) - } - // Handle the case where there is an error while updating the user's password - if name == ErrorUpdateUser { - return mock.ExpectExec(regexp.QuoteMeta(`UPDATE "users" `)).WillReturnError(fmt.Errorf("errrorr")) + +func changePasswordErrorUpdateUserCase() changePasswordType { + return changePasswordType{ + name: ErrorUpdateUser, + req: changeReq{ + OldPassword: OldPassword, + NewPassword: NewPassword, + }, + wantErr: true, + init: func(mock sqlmock.Sqlmock) *gomonkey.Patches { + rows := sqlmock.NewRows([]string{"id", "email", "password"}). + AddRow(testutls.MockID, testutls.MockEmail, OldPasswordHash) + mock.ExpectQuery(regexp.QuoteMeta(`select * from "users" where "id"=$1`)). + WithArgs(). + WillReturnRows(rows) + mock.ExpectExec(regexp.QuoteMeta(`UPDATE "users" `)).WillReturnError(fmt.Errorf("errrorr")) + return nil + }, } - return nil } -func setupSQLMocks(name string, mock sqlmock.Sqlmock) *sqlmock.ExpectedQuery { - if name == ErrorFindingUser { - return mock.ExpectQuery(regexp.QuoteMeta(`select * from "users" where "id"=$1`)). - WithArgs(). - WillReturnError(fmt.Errorf("")) +func changePasswordErrorFromConfigCase() changePasswordType { + return changePasswordType{ + name: ErrorFromConfig, + req: changeReq{ + OldPassword: OldPassword, + NewPassword: testutls.MockEmail, + }, + wantErr: true, + init: func(mock sqlmock.Sqlmock) *gomonkey.Patches { + rows := sqlmock.NewRows([]string{"id", "email", "password"}). + AddRow(testutls.MockID, testutls.MockEmail, OldPasswordHash) + mock.ExpectQuery(regexp.QuoteMeta(`select * from "users" where "id"=$1`)). + WithArgs(). + WillReturnRows(rows) + tg := jwt.Service{} + return gomonkey.ApplyFunc(service.JWT, func(cfg *config.Configuration) (jwt.Service, error) { + return tg, fmt.Errorf(ErrorMsgFromJwt) + }) + }, } - // Expect a query to get the user by ID to return a row with mock data entered - rows := sqlmock.NewRows([]string{"id", "email", "password"}). - AddRow(testutls.MockID, testutls.MockEmail, OldPasswordHash) - return mock.ExpectQuery(regexp.QuoteMeta(`select * from "users" where "id"=$1`)). - WithArgs(). - WillReturnRows(rows) } +func changePasswordSuccessCase() changePasswordType { + return changePasswordType{ + name: SuccessCase, + req: changeReq{ + OldPassword: OldPassword, + NewPassword: NewPassword, + }, + wantResp: &fm.ChangePasswordResponse{ + Ok: true, + }, + wantErr: false, + init: func(mock sqlmock.Sqlmock) *gomonkey.Patches { + rows := sqlmock.NewRows([]string{"id", "email", "password"}). + AddRow(testutls.MockID, testutls.MockEmail, OldPasswordHash) + mock.ExpectQuery(regexp.QuoteMeta(`select * from "users" where "id"=$1`)). + WithArgs(). + WillReturnRows(rows) + result := driver.Result(driver.RowsAffected(1)) + mock.ExpectExec(regexp.QuoteMeta(`UPDATE "users" `)).WillReturnResult(result) + return nil + }, + } +} +func loadChangePasswordTestCases() []changePasswordType { + return []changePasswordType{ + changePasswordErrorFindingUserCase(), + changePasswordErrorPasswordValidationcase(), + changePasswordErrorInsecurePasswordCase(), + changePasswordErrorUpdateUserCase(), + changePasswordErrorFromConfigCase(), + changePasswordSuccessCase(), + } +} func TestChangePassword( t *testing.T, ) { @@ -409,16 +465,6 @@ func TestChangePassword( tt.name, func(t *testing.T) { // Handle the case where there is an error while loading the configuration - if tt.name == ErrorFromConfig { - patch := applyPatch(tt.name) - defer patch.Reset() - } - // Load environment variables - err := config.LoadEnv() - if err != nil { - fmt.Print("error loading .env file") - } - // Create a mock SQL database connection db, mock, _ := sqlmock.New() // Inject mock instance into boil. oldDB := boil.GetDB() @@ -427,16 +473,12 @@ func TestChangePassword( boil.SetDB(oldDB) }() boil.SetDB(db) - // Handle the case where there is an error while finding the user - setupSQLMocks(tt.name, mock) - - // Handle the case where the password update is successful - if tt.name == SuccessCase || tt.name == ErrorUpdateUser { - setupSQLExpectWxecution(tt.name, mock) + tt.init(mock) + // Load environment variables + err := config.LoadEnv() + if err != nil { + fmt.Print("error loading .env file") } - - // Handle the case where there is an error while updating the user's passwor - // Set up the context with the mock user c := context.Background() ctx := context.WithValue(c, testutls.UserKey, testutls.MockUser()) @@ -444,7 +486,6 @@ func TestChangePassword( // Call the ChangePassword mutation and check the response and error against the expected values response, err := resolver1.Mutation().ChangePassword(ctx, tt.req.OldPassword, tt.req.NewPassword) if tt.wantResp != nil { - // Assert that the expected response matches the actual response assert.Equal(t, tt.wantResp, response) } @@ -456,11 +497,18 @@ func TestChangePassword( } type refereshTokenType struct { - name string - req string - wantResp *fm.RefreshTokenResponse - wantErr bool - err error + name string + req string + wantResp *fm.RefreshTokenResponse + wantErr bool + err error + init refereshTokenPatches + initMocks func(mock sqlmock.Sqlmock) +} +type refereshTokenPatches struct { + configPatch func() *gomonkey.Patches + jwtPatch func() *gomonkey.Patches + tokenPatch func() *gomonkey.Patches } func loadRefereshTokenCases() []refereshTokenType { @@ -470,24 +518,131 @@ func loadRefereshTokenCases() []refereshTokenType { req: TestToken, wantErr: true, err: fmt.Errorf(ErrorMsginvalidToken), + init: refereshTokenPatches{ + configPatch: func() *gomonkey.Patches { + return gomonkey.ApplyFunc(config.Load, func() (*config.Configuration, error) { + return &config.Configuration{}, nil + }) + }, + jwtPatch: func() *gomonkey.Patches { + tg := jwt.Service{} + return gomonkey.ApplyFunc(service.JWT, func(cfg *config.Configuration) (jwt.Service, error) { + return tg, nil + }) + }, + tokenPatch: func() *gomonkey.Patches { + tg := jwt.Service{} + return gomonkey.ApplyMethod(reflect.TypeOf(tg), "GenerateToken", + func(jwt.Service, *models.User) (string, error) { + return "token", nil + }) + }, + }, + initMocks: func(mock sqlmock.Sqlmock) { + mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (token=$1) LIMIT 1;`)). + WithArgs(). + WillReturnError(fmt.Errorf(ErrorMsginvalidToken)) + }, }, { name: ErrorFromConfig, req: ReqToken, wantErr: true, err: fmt.Errorf(ErrorMsgFromConfig), + init: refereshTokenPatches{ + configPatch: func() *gomonkey.Patches { + return gomonkey.ApplyFunc(config.Load, func() (*config.Configuration, error) { + return nil, fmt.Errorf("error in loading config") + }) + }, + jwtPatch: func() *gomonkey.Patches { + tg := jwt.Service{} + return gomonkey.ApplyFunc(service.JWT, func(cfg *config.Configuration) (jwt.Service, error) { + return tg, nil + }) + }, + tokenPatch: func() *gomonkey.Patches { + tg := jwt.Service{} + return gomonkey.ApplyMethod(reflect.TypeOf(tg), "GenerateToken", + func(jwt.Service, *models.User) (string, error) { + return "token", nil + }) + }, + }, + initMocks: func(mock sqlmock.Sqlmock) { + rows := sqlmock.NewRows([]string{"id", "email", "token", "role_id"}). + AddRow(1, testutls.MockEmail, testutls.MockToken, 1) + mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (token=$1) LIMIT 1;`)). + WithArgs(). + WillReturnRows(rows) + }, }, { name: ErrorFromJwt, req: ReqToken, wantErr: true, err: fmt.Errorf(ErrorMsgFromJwt), + init: refereshTokenPatches{ + configPatch: func() *gomonkey.Patches { + return gomonkey.ApplyFunc(config.Load, func() (*config.Configuration, error) { + return &config.Configuration{}, nil + }) + }, + jwtPatch: func() *gomonkey.Patches { + tg := jwt.Service{} + return gomonkey.ApplyFunc(service.JWT, func(cfg *config.Configuration) (jwt.Service, error) { + return tg, fmt.Errorf(ErrorMsgFromJwt) + }) + }, + tokenPatch: func() *gomonkey.Patches { + tg := jwt.Service{} + return gomonkey.ApplyMethod(reflect.TypeOf(tg), "GenerateToken", + func(jwt.Service, *models.User) (string, error) { + return "token", nil + }) + }, + }, + initMocks: func(mock sqlmock.Sqlmock) { + rows := sqlmock.NewRows([]string{"id", "email", "token", "role_id"}). + AddRow(1, testutls.MockEmail, testutls.MockToken, 1) + mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (token=$1) LIMIT 1;`)). + WithArgs(). + WillReturnRows(rows) + }, }, { name: ErrorFromGenerateToken, req: ReqToken, wantErr: true, - err: resultwrapper.ErrUnauthorized}, + err: resultwrapper.ErrUnauthorized, + init: refereshTokenPatches{ + configPatch: func() *gomonkey.Patches { + return gomonkey.ApplyFunc(config.Load, func() (*config.Configuration, error) { + return &config.Configuration{}, nil + }) + }, + jwtPatch: func() *gomonkey.Patches { + tg := jwt.Service{} + return gomonkey.ApplyFunc(service.JWT, func(cfg *config.Configuration) (jwt.Service, error) { + return tg, nil + }) + }, + tokenPatch: func() *gomonkey.Patches { + tg := jwt.Service{} + return gomonkey.ApplyMethod(reflect.TypeOf(tg), "GenerateToken", + func(jwt.Service, *models.User) (string, error) { + return "", resultwrapper.ErrUnauthorized + }) + }, + }, + initMocks: func(mock sqlmock.Sqlmock) { + rows := sqlmock.NewRows([]string{"id", "email", "token", "role_id"}). + AddRow(1, testutls.MockEmail, testutls.MockToken, 1) + mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (token=$1) LIMIT 1;`)). + WithArgs(). + WillReturnRows(rows) + }, + }, { name: SuccessCase, req: ReqToken, @@ -495,63 +650,37 @@ func loadRefereshTokenCases() []refereshTokenType { Token: testutls.MockToken, }, wantErr: false, + init: refereshTokenPatches{ + configPatch: func() *gomonkey.Patches { + return gomonkey.ApplyFunc(config.Load, func() (*config.Configuration, error) { + return &config.Configuration{}, nil + }) + }, + jwtPatch: func() *gomonkey.Patches { + tg := jwt.Service{} + return gomonkey.ApplyFunc(service.JWT, func(cfg *config.Configuration) (jwt.Service, error) { + return tg, nil + }) + }, + tokenPatch: func() *gomonkey.Patches { + tg := jwt.Service{} + return gomonkey.ApplyMethod(reflect.TypeOf(tg), "GenerateToken", + func(jwt.Service, *models.User) (string, error) { + return "token", nil + }) + }, + }, + initMocks: func(mock sqlmock.Sqlmock) { + rows := sqlmock.NewRows([]string{"id", "email", "token", "role_id"}). + AddRow(1, testutls.MockEmail, testutls.MockToken, 1) + mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (token=$1) LIMIT 1;`)). + WithArgs(). + WillReturnRows(rows) + }, }, } } -func setupSQLExpectation(name string, mock sqlmock.Sqlmock) *sqlmock.ExpectedQuery { - if name == ErrorInvalidToken { - return mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (token=$1) LIMIT 1;`)). - WithArgs(). - WillReturnError(fmt.Errorf(ErrorMsginvalidToken)) - } - rows := sqlmock.NewRows([]string{"id", "email", "token", "role_id"}). - AddRow(1, testutls.MockEmail, testutls.MockToken, 1) - mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (token=$1) LIMIT 1;`)). - WithArgs(). - WillReturnRows(rows) - - if name == SuccessCase { - rows := sqlmock.NewRows([]string{"id", "name"}). - AddRow(1, "ADMIN") - return mock.ExpectQuery(regexp.QuoteMeta(`SELECT "roles".* FROM "roles" WHERE ("id" = $1) LIMIT 1`)). - WithArgs([]driver.Value{1}...). - WillReturnRows(rows) - } - return nil -} -func applyPatch(name string) *gomonkey.Patches { - return gomonkey.ApplyFunc(config.Load, func() (*config.Configuration, error) { - if name == ErrorFromConfig { - return nil, fmt.Errorf("error in loading config") - } else { - return &config.Configuration{}, nil - } - }) -} - -func applyJWTPatch(name string) *gomonkey.Patches { - tg := jwt.Service{} - return gomonkey.ApplyFunc(service.JWT, func(cfg *config.Configuration) (jwt.Service, error) { - if name == ErrorFromJwt { - return tg, fmt.Errorf(ErrorMsgFromJwt) - } else { - return tg, nil - } - }) -} - -func applyGenerateTokenPatch(name string) *gomonkey.Patches { - tg := jwt.Service{} - return gomonkey.ApplyMethod(reflect.TypeOf(tg), "GenerateToken", - func(jwt.Service, *models.User) (string, error) { - if name == ErrorFromGenerateToken { - return "", resultwrapper.ErrUnauthorized - } else { - return "token", nil - } - }) -} func TestRefreshToken(t *testing.T) { cases := loadRefereshTokenCases() // Create a new instance of the resolver @@ -570,17 +699,14 @@ func TestRefreshToken(t *testing.T) { }() boil.SetDB(db) // Handle the case where authentication token is invalid - setupSQLExpectation(tt.name, mock) + tt.initMocks(mock) // Handle the case where there is an error loading the config - patch := applyPatch(tt.name) - defer patch.Reset() + configpatch := tt.init.configPatch() //initialize a jwt service // Handle the case where there is an error creating the JWT service - patchJWT := applyJWTPatch(tt.name) - defer patchJWT.Reset() + patchJWT := tt.init.jwtPatch() // Handle the case where there is an error form token generation service - patchGenerateToken := applyGenerateTokenPatch(tt.name) - defer patchGenerateToken.Reset() + patchGenerateToken := tt.init.tokenPatch() // Set up the context with the mock user c := context.Background() ctx := context.WithValue(c, testutls.UserKey, testutls.MockUser()) @@ -596,7 +722,9 @@ func TestRefreshToken(t *testing.T) { // Assert that the expected error value matches the actual error value assert.Equal(t, true, strings.Contains(err.Error(), tt.err.Error())) } - + configpatch.Reset() + patchJWT.Reset() + patchGenerateToken.Reset() }, ) } From 1b9bd2a567e185dd4aa57993e3178b845657494b Mon Sep 17 00:00:00 2001 From: HIMANSHU Date: Mon, 1 Apr 2024 18:35:01 +0530 Subject: [PATCH 20/39] auth mutation comments resolved --- resolver/auth_mutations.resolvers_test.go | 320 ++++++++++++---------- 1 file changed, 169 insertions(+), 151 deletions(-) diff --git a/resolver/auth_mutations.resolvers_test.go b/resolver/auth_mutations.resolvers_test.go index 724b3acf..9743fc6c 100644 --- a/resolver/auth_mutations.resolvers_test.go +++ b/resolver/auth_mutations.resolvers_test.go @@ -511,173 +511,191 @@ type refereshTokenPatches struct { tokenPatch func() *gomonkey.Patches } -func loadRefereshTokenCases() []refereshTokenType { - return []refereshTokenType{ - { - name: ErrorInvalidToken, - req: TestToken, - wantErr: true, - err: fmt.Errorf(ErrorMsginvalidToken), - init: refereshTokenPatches{ - configPatch: func() *gomonkey.Patches { - return gomonkey.ApplyFunc(config.Load, func() (*config.Configuration, error) { - return &config.Configuration{}, nil - }) - }, - jwtPatch: func() *gomonkey.Patches { - tg := jwt.Service{} - return gomonkey.ApplyFunc(service.JWT, func(cfg *config.Configuration) (jwt.Service, error) { - return tg, nil - }) - }, - tokenPatch: func() *gomonkey.Patches { - tg := jwt.Service{} - return gomonkey.ApplyMethod(reflect.TypeOf(tg), "GenerateToken", - func(jwt.Service, *models.User) (string, error) { - return "token", nil - }) - }, +func refreshTokenInvalidCase() refereshTokenType { + return refereshTokenType{ + name: ErrorInvalidToken, + req: TestToken, + wantErr: true, + err: fmt.Errorf(ErrorMsginvalidToken), + init: refereshTokenPatches{ + configPatch: func() *gomonkey.Patches { + return gomonkey.ApplyFunc(config.Load, func() (*config.Configuration, error) { + return &config.Configuration{}, nil + }) }, - initMocks: func(mock sqlmock.Sqlmock) { - mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (token=$1) LIMIT 1;`)). - WithArgs(). - WillReturnError(fmt.Errorf(ErrorMsginvalidToken)) + jwtPatch: func() *gomonkey.Patches { + tg := jwt.Service{} + return gomonkey.ApplyFunc(service.JWT, func(cfg *config.Configuration) (jwt.Service, error) { + return tg, nil + }) }, - }, - { - name: ErrorFromConfig, - req: ReqToken, - wantErr: true, - err: fmt.Errorf(ErrorMsgFromConfig), - init: refereshTokenPatches{ - configPatch: func() *gomonkey.Patches { - return gomonkey.ApplyFunc(config.Load, func() (*config.Configuration, error) { - return nil, fmt.Errorf("error in loading config") + tokenPatch: func() *gomonkey.Patches { + tg := jwt.Service{} + return gomonkey.ApplyMethod(reflect.TypeOf(tg), "GenerateToken", + func(jwt.Service, *models.User) (string, error) { + return "token", nil }) - }, - jwtPatch: func() *gomonkey.Patches { - tg := jwt.Service{} - return gomonkey.ApplyFunc(service.JWT, func(cfg *config.Configuration) (jwt.Service, error) { - return tg, nil - }) - }, - tokenPatch: func() *gomonkey.Patches { - tg := jwt.Service{} - return gomonkey.ApplyMethod(reflect.TypeOf(tg), "GenerateToken", - func(jwt.Service, *models.User) (string, error) { - return "token", nil - }) - }, - }, - initMocks: func(mock sqlmock.Sqlmock) { - rows := sqlmock.NewRows([]string{"id", "email", "token", "role_id"}). - AddRow(1, testutls.MockEmail, testutls.MockToken, 1) - mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (token=$1) LIMIT 1;`)). - WithArgs(). - WillReturnRows(rows) }, }, - { - name: ErrorFromJwt, - req: ReqToken, - wantErr: true, - err: fmt.Errorf(ErrorMsgFromJwt), - init: refereshTokenPatches{ - configPatch: func() *gomonkey.Patches { - return gomonkey.ApplyFunc(config.Load, func() (*config.Configuration, error) { - return &config.Configuration{}, nil - }) - }, - jwtPatch: func() *gomonkey.Patches { - tg := jwt.Service{} - return gomonkey.ApplyFunc(service.JWT, func(cfg *config.Configuration) (jwt.Service, error) { - return tg, fmt.Errorf(ErrorMsgFromJwt) - }) - }, - tokenPatch: func() *gomonkey.Patches { - tg := jwt.Service{} - return gomonkey.ApplyMethod(reflect.TypeOf(tg), "GenerateToken", - func(jwt.Service, *models.User) (string, error) { - return "token", nil - }) - }, + initMocks: func(mock sqlmock.Sqlmock) { + mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (token=$1) LIMIT 1;`)). + WithArgs(). + WillReturnError(fmt.Errorf(ErrorMsginvalidToken)) + }, + } +} +func refreshTokenErrorFromConfigCase() refereshTokenType { + return refereshTokenType{ + name: ErrorFromConfig, + req: ReqToken, + wantErr: true, + err: fmt.Errorf(ErrorMsgFromConfig), + init: refereshTokenPatches{ + configPatch: func() *gomonkey.Patches { + return gomonkey.ApplyFunc(config.Load, func() (*config.Configuration, error) { + return nil, fmt.Errorf("error in loading config") + }) }, - initMocks: func(mock sqlmock.Sqlmock) { - rows := sqlmock.NewRows([]string{"id", "email", "token", "role_id"}). - AddRow(1, testutls.MockEmail, testutls.MockToken, 1) - mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (token=$1) LIMIT 1;`)). - WithArgs(). - WillReturnRows(rows) + jwtPatch: func() *gomonkey.Patches { + tg := jwt.Service{} + return gomonkey.ApplyFunc(service.JWT, func(cfg *config.Configuration) (jwt.Service, error) { + return tg, nil + }) }, - }, - { - name: ErrorFromGenerateToken, - req: ReqToken, - wantErr: true, - err: resultwrapper.ErrUnauthorized, - init: refereshTokenPatches{ - configPatch: func() *gomonkey.Patches { - return gomonkey.ApplyFunc(config.Load, func() (*config.Configuration, error) { - return &config.Configuration{}, nil + tokenPatch: func() *gomonkey.Patches { + tg := jwt.Service{} + return gomonkey.ApplyMethod(reflect.TypeOf(tg), "GenerateToken", + func(jwt.Service, *models.User) (string, error) { + return "token", nil }) - }, - jwtPatch: func() *gomonkey.Patches { - tg := jwt.Service{} - return gomonkey.ApplyFunc(service.JWT, func(cfg *config.Configuration) (jwt.Service, error) { - return tg, nil - }) - }, - tokenPatch: func() *gomonkey.Patches { - tg := jwt.Service{} - return gomonkey.ApplyMethod(reflect.TypeOf(tg), "GenerateToken", - func(jwt.Service, *models.User) (string, error) { - return "", resultwrapper.ErrUnauthorized - }) - }, - }, - initMocks: func(mock sqlmock.Sqlmock) { - rows := sqlmock.NewRows([]string{"id", "email", "token", "role_id"}). - AddRow(1, testutls.MockEmail, testutls.MockToken, 1) - mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (token=$1) LIMIT 1;`)). - WithArgs(). - WillReturnRows(rows) }, }, - { - name: SuccessCase, - req: ReqToken, - wantResp: &fm.RefreshTokenResponse{ - Token: testutls.MockToken, + initMocks: func(mock sqlmock.Sqlmock) { + rows := sqlmock.NewRows([]string{"id", "email", "token", "role_id"}). + AddRow(1, testutls.MockEmail, testutls.MockToken, 1) + mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (token=$1) LIMIT 1;`)). + WithArgs(). + WillReturnRows(rows) + }, + } +} + +func refereshTokenErrorFromJWTCase() refereshTokenType { + return refereshTokenType{ + name: ErrorFromJwt, + req: ReqToken, + wantErr: true, + err: fmt.Errorf(ErrorMsgFromJwt), + init: refereshTokenPatches{ + configPatch: func() *gomonkey.Patches { + return gomonkey.ApplyFunc(config.Load, func() (*config.Configuration, error) { + return &config.Configuration{}, nil + }) }, - wantErr: false, - init: refereshTokenPatches{ - configPatch: func() *gomonkey.Patches { - return gomonkey.ApplyFunc(config.Load, func() (*config.Configuration, error) { - return &config.Configuration{}, nil + jwtPatch: func() *gomonkey.Patches { + tg := jwt.Service{} + return gomonkey.ApplyFunc(service.JWT, func(cfg *config.Configuration) (jwt.Service, error) { + return tg, fmt.Errorf(ErrorMsgFromJwt) + }) + }, + tokenPatch: func() *gomonkey.Patches { + tg := jwt.Service{} + return gomonkey.ApplyMethod(reflect.TypeOf(tg), "GenerateToken", + func(jwt.Service, *models.User) (string, error) { + return "token", nil }) - }, - jwtPatch: func() *gomonkey.Patches { - tg := jwt.Service{} - return gomonkey.ApplyFunc(service.JWT, func(cfg *config.Configuration) (jwt.Service, error) { - return tg, nil + }, + }, + initMocks: func(mock sqlmock.Sqlmock) { + rows := sqlmock.NewRows([]string{"id", "email", "token", "role_id"}). + AddRow(1, testutls.MockEmail, testutls.MockToken, 1) + mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (token=$1) LIMIT 1;`)). + WithArgs(). + WillReturnRows(rows) + }, + } +} + +func refereshTokenErrorFromGenerateTokenCase() refereshTokenType { + return refereshTokenType{ + name: ErrorFromGenerateToken, + req: ReqToken, + wantErr: true, + err: resultwrapper.ErrUnauthorized, + init: refereshTokenPatches{ + configPatch: func() *gomonkey.Patches { + return gomonkey.ApplyFunc(config.Load, func() (*config.Configuration, error) { + return &config.Configuration{}, nil + }) + }, + jwtPatch: func() *gomonkey.Patches { + tg := jwt.Service{} + return gomonkey.ApplyFunc(service.JWT, func(cfg *config.Configuration) (jwt.Service, error) { + return tg, nil + }) + }, + tokenPatch: func() *gomonkey.Patches { + tg := jwt.Service{} + return gomonkey.ApplyMethod(reflect.TypeOf(tg), "GenerateToken", + func(jwt.Service, *models.User) (string, error) { + return "", resultwrapper.ErrUnauthorized }) - }, - tokenPatch: func() *gomonkey.Patches { - tg := jwt.Service{} - return gomonkey.ApplyMethod(reflect.TypeOf(tg), "GenerateToken", - func(jwt.Service, *models.User) (string, error) { - return "token", nil - }) - }, }, - initMocks: func(mock sqlmock.Sqlmock) { - rows := sqlmock.NewRows([]string{"id", "email", "token", "role_id"}). - AddRow(1, testutls.MockEmail, testutls.MockToken, 1) - mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (token=$1) LIMIT 1;`)). - WithArgs(). - WillReturnRows(rows) + }, + initMocks: func(mock sqlmock.Sqlmock) { + rows := sqlmock.NewRows([]string{"id", "email", "token", "role_id"}). + AddRow(1, testutls.MockEmail, testutls.MockToken, 1) + mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (token=$1) LIMIT 1;`)). + WithArgs(). + WillReturnRows(rows) + }, + } +} + +func refreshTokenSuccessCase() refereshTokenType { + return refereshTokenType{ + name: SuccessCase, + req: ReqToken, + wantResp: &fm.RefreshTokenResponse{ + Token: testutls.MockToken, + }, + wantErr: false, + init: refereshTokenPatches{ + configPatch: func() *gomonkey.Patches { + return gomonkey.ApplyFunc(config.Load, func() (*config.Configuration, error) { + return &config.Configuration{}, nil + }) + }, + jwtPatch: func() *gomonkey.Patches { + tg := jwt.Service{} + return gomonkey.ApplyFunc(service.JWT, func(cfg *config.Configuration) (jwt.Service, error) { + return tg, nil + }) + }, + tokenPatch: func() *gomonkey.Patches { + tg := jwt.Service{} + return gomonkey.ApplyMethod(reflect.TypeOf(tg), "GenerateToken", + func(jwt.Service, *models.User) (string, error) { + return "token", nil + }) }, }, + initMocks: func(mock sqlmock.Sqlmock) { + rows := sqlmock.NewRows([]string{"id", "email", "token", "role_id"}). + AddRow(1, testutls.MockEmail, testutls.MockToken, 1) + mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (token=$1) LIMIT 1;`)). + WithArgs(). + WillReturnRows(rows) + }, + } +} +func loadRefereshTokenCases() []refereshTokenType { + return []refereshTokenType{ + refreshTokenInvalidCase(), + refreshTokenErrorFromConfigCase(), + refereshTokenErrorFromJWTCase(), + refereshTokenErrorFromGenerateTokenCase(), + refreshTokenSuccessCase(), } } From 08ed0838da1239ae82d3d689e2f337ca6273f0f1 Mon Sep 17 00:00:00 2001 From: HIMANSHU Date: Mon, 1 Apr 2024 19:54:10 +0530 Subject: [PATCH 21/39] auth mutation comments resolved --- resolver/auth_mutations.resolvers_test.go | 41 ++++------------------- 1 file changed, 6 insertions(+), 35 deletions(-) diff --git a/resolver/auth_mutations.resolvers_test.go b/resolver/auth_mutations.resolvers_test.go index 9743fc6c..117b8b53 100644 --- a/resolver/auth_mutations.resolvers_test.go +++ b/resolver/auth_mutations.resolvers_test.go @@ -21,7 +21,6 @@ import ( "github.com/DATA-DOG/go-sqlmock" "github.com/agiledragon/gomonkey/v2" "github.com/stretchr/testify/assert" - "github.com/volatiletech/sqlboiler/v4/boil" ) const ( @@ -277,20 +276,9 @@ func TestLogin( t.Run( tt.name, func(t *testing.T) { - db, mock, _ := sqlmock.New() - // Inject mock instance into boil. - oldDB := boil.GetDB() - defer func() { - db.Close() - boil.SetDB(oldDB) - }() - boil.SetDB(db) + mock, cleanup, _ := testutls.SetupMockDB(t) + defer cleanup() patch := tt.init(mock) - // Load the environment variables from a .env file - err := config.LoadEnv() - if err != nil { - fmt.Print("error loading .env file") - } c := context.Background() // Call the login mutation with the given arguments and check the response and error against the expected values response, err := resolver1.Mutation().Login(c, tt.req.UserName, tt.req.Password) @@ -465,20 +453,9 @@ func TestChangePassword( tt.name, func(t *testing.T) { // Handle the case where there is an error while loading the configuration - db, mock, _ := sqlmock.New() - // Inject mock instance into boil. - oldDB := boil.GetDB() - defer func() { - db.Close() - boil.SetDB(oldDB) - }() - boil.SetDB(db) + mock, cleanup, _ := testutls.SetupMockDB(t) + defer cleanup() tt.init(mock) - // Load environment variables - err := config.LoadEnv() - if err != nil { - fmt.Print("error loading .env file") - } // Set up the context with the mock user c := context.Background() ctx := context.WithValue(c, testutls.UserKey, testutls.MockUser()) @@ -708,14 +685,8 @@ func TestRefreshToken(t *testing.T) { tt.name, func(t *testing.T) { // Create a mock SQL database connection - db, mock, _ := sqlmock.New() - // Inject mock instance into boil. - oldDB := boil.GetDB() - defer func() { - db.Close() - boil.SetDB(oldDB) - }() - boil.SetDB(db) + mock, cleanup, _ := testutls.SetupMockDB(t) + defer cleanup() // Handle the case where authentication token is invalid tt.initMocks(mock) // Handle the case where there is an error loading the config From 40302643e2c999113ccfbc88900bfd4835499e95 Mon Sep 17 00:00:00 2001 From: HIMANSHU Date: Mon, 1 Apr 2024 13:18:53 +0530 Subject: [PATCH 22/39] user mutaion tests refactor --- resolver/user_mutations.resolvers_test.go | 313 +++++++++++++--------- 1 file changed, 187 insertions(+), 126 deletions(-) diff --git a/resolver/user_mutations.resolvers_test.go b/resolver/user_mutations.resolvers_test.go index a594ad7c..166101ec 100644 --- a/resolver/user_mutations.resolvers_test.go +++ b/resolver/user_mutations.resolvers_test.go @@ -20,6 +20,7 @@ import ( "github.com/DATA-DOG/go-sqlmock" "github.com/agiledragon/gomonkey/v2" "github.com/stretchr/testify/assert" + "github.com/volatiletech/sqlboiler/v4/boil" ) type AnyTime struct{} @@ -55,58 +56,92 @@ func expectInsertUser(mock sqlmock.Sqlmock, mockUser models.User) { ). WillReturnRows(rows) } -func getCreateUserTestCase() []struct { - name string - req fm.UserCreateInput - wantResp *fm.User - wantErr bool -} { - cases := []struct { - name string - req fm.UserCreateInput - wantResp *fm.User - wantErr bool - }{ - { - name: ErrorFromCreateUser, - req: fm.UserCreateInput{}, - wantErr: true, + +type createUserType struct { + name string + req fm.UserCreateInput + wantResp *fm.User + wantErr bool + init func() *gomonkey.Patches + initmocks func(mock sqlmock.Sqlmock, mockUser models.User) +} + +func errorFromCreateUserCase() createUserType { + return createUserType{ + name: ErrorFromCreateUser, + req: fm.UserCreateInput{}, + wantErr: true, + init: func() *gomonkey.Patches { return nil }, + initmocks: func(mock sqlmock.Sqlmock, mockUser models.User) { + mock.ExpectQuery(regexp.QuoteMeta(`INSERT INTO "users"`)). + WithArgs(). + WillReturnError(fmt.Errorf("")) }, - { - name: ErrorFromThrottleCheck, - req: fm.UserCreateInput{}, - wantErr: true, + } +} + +func errorFromThrottleCheck() createUserType { + return createUserType{ + name: ErrorFromThrottleCheck, + req: fm.UserCreateInput{}, + wantErr: true, + init: func() *gomonkey.Patches { + return gomonkey.ApplyFunc(throttle.Check, func(ctx context.Context, limit int, dur time.Duration) error { + return fmt.Errorf("Internal error") + }) }, - { - name: ErrorFromConfig, - req: fm.UserCreateInput{}, - wantErr: true, + initmocks: expectInsertUser, + } +} +func errorFromCreateUserConfigCase() createUserType { + return createUserType{ + name: ErrorFromConfig, + req: fm.UserCreateInput{}, + wantErr: true, + init: func() *gomonkey.Patches { + return gomonkey.ApplyFunc(config.Load, func() (*config.Configuration, error) { + return nil, fmt.Errorf("error in loading config") + }) }, - { - name: SuccessCase, - req: fm.UserCreateInput{ - FirstName: testutls.MockUser().FirstName.String, - LastName: testutls.MockUser().LastName.String, - Username: testutls.MockUser().Username.String, - Email: testutls.MockUser().Email.String, - RoleID: fmt.Sprint(testutls.MockUser().RoleID.Int), - }, - wantResp: &fm.User{ - ID: fmt.Sprint(testutls.MockUser().ID), - Email: convert.NullDotStringToPointerString(testutls.MockUser().Email), - FirstName: convert.NullDotStringToPointerString(testutls.MockUser().FirstName), - LastName: convert.NullDotStringToPointerString(testutls.MockUser().LastName), - Username: convert.NullDotStringToPointerString(testutls.MockUser().Username), - Mobile: convert.NullDotStringToPointerString(testutls.MockUser().Mobile), - Address: convert.NullDotStringToPointerString(testutls.MockUser().Address), - Active: convert.NullDotBoolToPointerBool(testutls.MockUser().Active), - LastLogin: convert.NullDotTimeToPointerInt(testutls.MockUser().LastLogin), - LastPasswordChange: convert.NullDotTimeToPointerInt(testutls.MockUser().LastPasswordChange), - DeletedAt: convert.NullDotTimeToPointerInt(testutls.MockUser().DeletedAt), - UpdatedAt: convert.NullDotTimeToPointerInt(testutls.MockUser().UpdatedAt), - }, - wantErr: false, + initmocks: expectInsertUser, + } +} + +func createUserSuccessCase() createUserType { + return createUserType{ + name: SuccessCase, + req: fm.UserCreateInput{ + FirstName: testutls.MockUser().FirstName.String, + LastName: testutls.MockUser().LastName.String, + Username: testutls.MockUser().Username.String, + Email: testutls.MockUser().Email.String, + RoleID: fmt.Sprint(testutls.MockUser().RoleID.Int), + }, + wantResp: &fm.User{ + ID: fmt.Sprint(testutls.MockUser().ID), + Email: convert.NullDotStringToPointerString(testutls.MockUser().Email), + FirstName: convert.NullDotStringToPointerString(testutls.MockUser().FirstName), + LastName: convert.NullDotStringToPointerString(testutls.MockUser().LastName), + Username: convert.NullDotStringToPointerString(testutls.MockUser().Username), + Mobile: convert.NullDotStringToPointerString(testutls.MockUser().Mobile), + Address: convert.NullDotStringToPointerString(testutls.MockUser().Address), + Active: convert.NullDotBoolToPointerBool(testutls.MockUser().Active), + LastLogin: convert.NullDotTimeToPointerInt(testutls.MockUser().LastLogin), + LastPasswordChange: convert.NullDotTimeToPointerInt(testutls.MockUser().LastPasswordChange), + DeletedAt: convert.NullDotTimeToPointerInt(testutls.MockUser().DeletedAt), + UpdatedAt: convert.NullDotTimeToPointerInt(testutls.MockUser().UpdatedAt), }, + wantErr: false, + init: func() *gomonkey.Patches { return nil }, + initmocks: expectInsertUser, + } +} +func getCreateUserTestCase() []createUserType { + cases := []createUserType{ + errorFromCreateUserCase(), + errorFromThrottleCheck(), + errorFromCreateUserConfigCase(), + createUserSuccessCase(), } return cases } @@ -116,26 +151,9 @@ func TestCreateUser(t *testing.T) { for _, tt := range cases { t.Run(tt.name, func(t *testing.T) { mock, cleanup, _ := testutls.SetupMockDB(t) - - if tt.name == ErrorFromCreateUser { - mock.ExpectQuery(regexp.QuoteMeta(`INSERT INTO "users"`)). - WithArgs(). - WillReturnError(fmt.Errorf("")) - } else { - expectInsertUser(mock, *testutls.MockUser()) - } - - if tt.name == ErrorFromThrottleCheck { - patch := gomonkey.ApplyFunc(throttle.Check, func(ctx context.Context, limit int, dur time.Duration) error { - return fmt.Errorf("Internal error") - }) - defer patch.Reset() - } - - if tt.name == ErrorFromConfig { - patch := gomonkey.ApplyFunc(config.Load, func() (*config.Configuration, error) { - return nil, fmt.Errorf("error in loading config") - }) + tt.initmocks(mock, *testutls.MockUser()) + patch := tt.init() + if patch != nil { defer patch.Reset() } response, err := resolver.Mutation().CreateUser(context.Background(), tt.req) @@ -148,22 +166,25 @@ func TestCreateUser(t *testing.T) { } } -func GetUpdateUserTestCase() []struct { - name string - req *fm.UserUpdateInput - wantResp *fm.User - wantErr bool -} { - cases := []struct { - name string - req *fm.UserUpdateInput - wantResp *fm.User - wantErr bool - }{ +type updateUserType struct { + name string + req *fm.UserUpdateInput + wantResp *fm.User + wantErr bool + init func() + initMocks func(mock sqlmock.Sqlmock) +} + +func loadUpdateUserTestCases() []updateUserType { + return []updateUserType{ { name: ErrorFindingUser, req: &fm.UserUpdateInput{}, wantErr: true, + init: func() {}, + initMocks: func(mock sqlmock.Sqlmock) { + mock.ExpectQuery(regexp.QuoteMeta(`UPDATE "users"`)).WithArgs().WillReturnError(fmt.Errorf("")) + }, }, { name: ErrorUpdateUser, @@ -174,6 +195,19 @@ func GetUpdateUserTestCase() []struct { Address: &testutls.MockUser().Address.String, }, wantErr: true, + init: func() { + gomonkey.ApplyFunc(daos.UpdateUser, + func(user models.User, ctx context.Context) (models.User, error) { + return user, fmt.Errorf("error for update user") + }) + }, + initMocks: func(mock sqlmock.Sqlmock) { + rows := sqlmock.NewRows([]string{"first_name"}).AddRow(testutls.MockUser().FirstName) + mock.ExpectQuery(regexp.QuoteMeta(`select * from "users"`)).WithArgs(0).WillReturnRows(rows) + // update users with new information + result := driver.Result(driver.RowsAffected(1)) + mock.ExpectExec(regexp.QuoteMeta(`UPDATE "users"`)).WillReturnResult(result) + }, }, { name: SuccessCase, @@ -191,40 +225,37 @@ func GetUpdateUserTestCase() []struct { Address: &testutls.MockUser().Address.String, }, wantErr: false, + init: func() {}, + initMocks: func(mock sqlmock.Sqlmock) { + rows := sqlmock.NewRows([]string{"first_name"}).AddRow(testutls.MockUser().FirstName) + mock.ExpectQuery(regexp.QuoteMeta(`select * from "users"`)).WithArgs(0).WillReturnRows(rows) + // update users with new information + result := driver.Result(driver.RowsAffected(1)) + mock.ExpectExec(regexp.QuoteMeta(`UPDATE "users"`)).WillReturnResult(result) + }, }, } - return cases } + func TestUpdateUser( t *testing.T, ) { - cases := GetUpdateUserTestCase() + cases := loadUpdateUserTestCases() resolver1 := resolver.Resolver{} for _, tt := range cases { t.Run( tt.name, func(t *testing.T) { - if tt.name == ErrorUpdateUser { - patch := gomonkey.ApplyFunc(daos.UpdateUser, - func(user models.User, ctx context.Context) (models.User, error) { - return user, fmt.Errorf("error for update user") - }) - defer patch.Reset() - } + tt.init() err := config.LoadEnv() if err != nil { log.Fatal(err) } mock, cleanup, _ := testutls.SetupMockDB(t) - - if tt.name == ErrorFindingUser { - mock.ExpectQuery(regexp.QuoteMeta(`UPDATE "users"`)).WithArgs().WillReturnError(fmt.Errorf("")) - } - rows := sqlmock.NewRows([]string{"first_name"}).AddRow(testutls.MockUser().FirstName) - mock.ExpectQuery(regexp.QuoteMeta(`select * from "users"`)).WithArgs(0).WillReturnRows(rows) - // update users with new information - result := driver.Result(driver.RowsAffected(1)) - mock.ExpectExec(regexp.QuoteMeta(`UPDATE "users"`)).WillReturnResult(result) + oldDB := boil.GetDB() + defer cleanup() + boil.SetDB(oldDB) + tt.initMocks(mock) c := context.Background() ctx := context.WithValue(c, testutls.UserKey, testutls.MockUser()) response, err := resolver1.Mutation().UpdateUser(ctx, tt.req) @@ -233,29 +264,64 @@ func TestUpdateUser( assert.Equal(t, tt.wantResp, response) } assert.Equal(t, tt.wantErr, err != nil) - cleanup() }, ) } } func GetDeleteTestCases() []struct { - name string - wantResp *fm.UserDeletePayload - wantErr bool + name string + wantResp *fm.UserDeletePayload + wantErr bool + init func() *gomonkey.Patches + initMocks func(mock sqlmock.Sqlmock) } { cases := []struct { - name string - wantResp *fm.UserDeletePayload - wantErr bool + name string + wantResp *fm.UserDeletePayload + wantErr bool + init func() *gomonkey.Patches + initMocks func(mock sqlmock.Sqlmock) }{ { name: ErrorFindingUser, wantErr: true, + init: func() *gomonkey.Patches { return nil }, + initMocks: func(mock sqlmock.Sqlmock) { + mock.ExpectQuery(regexp.QuoteMeta(`select * from "users" where "id"=$1`)). + WithArgs(). + WillReturnError(fmt.Errorf("")) + rows := sqlmock.NewRows([]string{"id"}). + AddRow(1) + mock.ExpectQuery(regexp.QuoteMeta(`select * from "users" where "id"=$1`)). + WithArgs(). + WillReturnRows(rows) + // delete user + result := driver.Result(driver.RowsAffected(1)) + mock.ExpectExec(regexp.QuoteMeta(`DELETE FROM "users" WHERE "id"=$1`)). + WillReturnResult(result) + }, }, { name: ErrorDeleteUser, wantErr: true, + init: func() *gomonkey.Patches { + return gomonkey.ApplyFunc(daos.DeleteUser, + func(user models.User, ctx context.Context) (int64, error) { + return 0, fmt.Errorf("error for delete user") + }) + }, + initMocks: func(mock sqlmock.Sqlmock) { + rows := sqlmock.NewRows([]string{"id"}). + AddRow(1) + mock.ExpectQuery(regexp.QuoteMeta(`select * from "users" where "id"=$1`)). + WithArgs(). + WillReturnRows(rows) + // delete user + result := driver.Result(driver.RowsAffected(1)) + mock.ExpectExec(regexp.QuoteMeta(`DELETE FROM "users" WHERE "id"=$1`)). + WillReturnResult(result) + }, }, { name: SuccessCase, @@ -263,6 +329,18 @@ func GetDeleteTestCases() []struct { ID: "0", }, wantErr: false, + init: func() *gomonkey.Patches { return nil }, + initMocks: func(mock sqlmock.Sqlmock) { + rows := sqlmock.NewRows([]string{"id"}). + AddRow(1) + mock.ExpectQuery(regexp.QuoteMeta(`select * from "users" where "id"=$1`)). + WithArgs(). + WillReturnRows(rows) + // delete user + result := driver.Result(driver.RowsAffected(1)) + mock.ExpectExec(regexp.QuoteMeta(`DELETE FROM "users" WHERE "id"=$1`)). + WillReturnResult(result) + }, }, } return cases @@ -277,33 +355,16 @@ func TestDeleteUser( t.Run( tt.name, func(t *testing.T) { - if tt.name == ErrorDeleteUser { - patch := gomonkey.ApplyFunc(daos.DeleteUser, - func(user models.User, ctx context.Context) (int64, error) { - return 0, fmt.Errorf("error for delete user") - }) + patch := tt.init() + if patch != nil { defer patch.Reset() } mock, cleanup, _ := testutls.SetupMockDB(t) - if tt.name == ErrorFindingUser { - mock.ExpectQuery(regexp.QuoteMeta(`select * from "users" where "id"=$1`)). - WithArgs(). - WillReturnError(fmt.Errorf("")) - } // get user by id - rows := sqlmock.NewRows([]string{"id"}). - AddRow(1) - mock.ExpectQuery(regexp.QuoteMeta(`select * from "users" where "id"=$1`)). - WithArgs(). - WillReturnRows(rows) - // delete user - result := driver.Result(driver.RowsAffected(1)) - mock.ExpectExec(regexp.QuoteMeta(`DELETE FROM "users" WHERE "id"=$1`)). - WillReturnResult(result) + tt.initMocks(mock) c := context.Background() ctx := context.WithValue(c, testutls.UserKey, testutls.MockUser()) - response, err := resolver1.Mutation(). - DeleteUser(ctx) + response, err := resolver1.Mutation().DeleteUser(ctx) if tt.wantResp != nil { assert.Equal(t, tt.wantResp, response) } From 93f04b768893ad9c2737b05faf0f631401323f52 Mon Sep 17 00:00:00 2001 From: HIMANSHU Date: Mon, 1 Apr 2024 14:56:12 +0530 Subject: [PATCH 23/39] Update Refactor user mutaion resolvers --- resolver/user_mutations.resolvers_test.go | 138 +++++++++++----------- 1 file changed, 72 insertions(+), 66 deletions(-) diff --git a/resolver/user_mutations.resolvers_test.go b/resolver/user_mutations.resolvers_test.go index 166101ec..8bcecd35 100644 --- a/resolver/user_mutations.resolvers_test.go +++ b/resolver/user_mutations.resolvers_test.go @@ -269,81 +269,87 @@ func TestUpdateUser( } } -func GetDeleteTestCases() []struct { +type deleteUserType struct { name string wantResp *fm.UserDeletePayload wantErr bool init func() *gomonkey.Patches initMocks func(mock sqlmock.Sqlmock) -} { - cases := []struct { - name string - wantResp *fm.UserDeletePayload - wantErr bool - init func() *gomonkey.Patches - initMocks func(mock sqlmock.Sqlmock) - }{ - { - name: ErrorFindingUser, - wantErr: true, - init: func() *gomonkey.Patches { return nil }, - initMocks: func(mock sqlmock.Sqlmock) { - mock.ExpectQuery(regexp.QuoteMeta(`select * from "users" where "id"=$1`)). - WithArgs(). - WillReturnError(fmt.Errorf("")) - rows := sqlmock.NewRows([]string{"id"}). - AddRow(1) - mock.ExpectQuery(regexp.QuoteMeta(`select * from "users" where "id"=$1`)). - WithArgs(). - WillReturnRows(rows) - // delete user - result := driver.Result(driver.RowsAffected(1)) - mock.ExpectExec(regexp.QuoteMeta(`DELETE FROM "users" WHERE "id"=$1`)). - WillReturnResult(result) - }, +} + +func errorFindinguserCaseDelete() deleteUserType { + return deleteUserType{ + name: ErrorFindingUser, + wantErr: true, + init: func() *gomonkey.Patches { return nil }, + initMocks: func(mock sqlmock.Sqlmock) { + mock.ExpectQuery(regexp.QuoteMeta(`select * from "users" where "id"=$1`)). + WithArgs(). + WillReturnError(fmt.Errorf("")) + rows := sqlmock.NewRows([]string{"id"}). + AddRow(1) + mock.ExpectQuery(regexp.QuoteMeta(`select * from "users" where "id"=$1`)). + WithArgs(). + WillReturnRows(rows) + // delete user + result := driver.Result(driver.RowsAffected(1)) + mock.ExpectExec(regexp.QuoteMeta(`DELETE FROM "users" WHERE "id"=$1`)). + WillReturnResult(result) }, - { - name: ErrorDeleteUser, - wantErr: true, - init: func() *gomonkey.Patches { - return gomonkey.ApplyFunc(daos.DeleteUser, - func(user models.User, ctx context.Context) (int64, error) { - return 0, fmt.Errorf("error for delete user") - }) - }, - initMocks: func(mock sqlmock.Sqlmock) { - rows := sqlmock.NewRows([]string{"id"}). - AddRow(1) - mock.ExpectQuery(regexp.QuoteMeta(`select * from "users" where "id"=$1`)). - WithArgs(). - WillReturnRows(rows) - // delete user - result := driver.Result(driver.RowsAffected(1)) - mock.ExpectExec(regexp.QuoteMeta(`DELETE FROM "users" WHERE "id"=$1`)). - WillReturnResult(result) - }, + } +} + +func errorDeleteUserCase() deleteUserType { + return deleteUserType{ + name: ErrorDeleteUser, + wantErr: true, + init: func() *gomonkey.Patches { + return gomonkey.ApplyFunc(daos.DeleteUser, + func(user models.User, ctx context.Context) (int64, error) { + return 0, fmt.Errorf("error for delete user") + }) }, - { - name: SuccessCase, - wantResp: &fm.UserDeletePayload{ - ID: "0", - }, - wantErr: false, - init: func() *gomonkey.Patches { return nil }, - initMocks: func(mock sqlmock.Sqlmock) { - rows := sqlmock.NewRows([]string{"id"}). - AddRow(1) - mock.ExpectQuery(regexp.QuoteMeta(`select * from "users" where "id"=$1`)). - WithArgs(). - WillReturnRows(rows) - // delete user - result := driver.Result(driver.RowsAffected(1)) - mock.ExpectExec(regexp.QuoteMeta(`DELETE FROM "users" WHERE "id"=$1`)). - WillReturnResult(result) - }, + initMocks: func(mock sqlmock.Sqlmock) { + rows := sqlmock.NewRows([]string{"id"}). + AddRow(1) + mock.ExpectQuery(regexp.QuoteMeta(`select * from "users" where "id"=$1`)). + WithArgs(). + WillReturnRows(rows) + // delete user + result := driver.Result(driver.RowsAffected(1)) + mock.ExpectExec(regexp.QuoteMeta(`DELETE FROM "users" WHERE "id"=$1`)). + WillReturnResult(result) }, } - return cases +} + +func deleteUserSuccessCase() deleteUserType { + return deleteUserType{ + name: SuccessCase, + wantResp: &fm.UserDeletePayload{ + ID: "0", + }, + wantErr: false, + init: func() *gomonkey.Patches { return nil }, + initMocks: func(mock sqlmock.Sqlmock) { + rows := sqlmock.NewRows([]string{"id"}). + AddRow(1) + mock.ExpectQuery(regexp.QuoteMeta(`select * from "users" where "id"=$1`)). + WithArgs(). + WillReturnRows(rows) + // delete user + result := driver.Result(driver.RowsAffected(1)) + mock.ExpectExec(regexp.QuoteMeta(`DELETE FROM "users" WHERE "id"=$1`)). + WillReturnResult(result) + }, + } +} +func GetDeleteTestCases() []deleteUserType { + return []deleteUserType{ + errorFindinguserCaseDelete(), + errorDeleteUserCase(), + deleteUserSuccessCase(), + } } func TestDeleteUser( From d016a18ebd2cb652e383fe4efd77aa66bb6d4e66 Mon Sep 17 00:00:00 2001 From: HIMANSHU Date: Mon, 1 Apr 2024 23:25:55 +0530 Subject: [PATCH 24/39] user mutation comments resolved --- resolver/user_mutations.resolvers_test.go | 175 +++++++++++----------- 1 file changed, 88 insertions(+), 87 deletions(-) diff --git a/resolver/user_mutations.resolvers_test.go b/resolver/user_mutations.resolvers_test.go index 8bcecd35..cebb58a4 100644 --- a/resolver/user_mutations.resolvers_test.go +++ b/resolver/user_mutations.resolvers_test.go @@ -12,7 +12,6 @@ import ( "go-template/pkg/utl/throttle" "go-template/resolver" "go-template/testutls" - "log" "regexp" "testing" "time" @@ -20,7 +19,6 @@ import ( "github.com/DATA-DOG/go-sqlmock" "github.com/agiledragon/gomonkey/v2" "github.com/stretchr/testify/assert" - "github.com/volatiletech/sqlboiler/v4/boil" ) type AnyTime struct{} @@ -42,28 +40,12 @@ func (a AnyString) Match( return ok } -func expectInsertUser(mock sqlmock.Sqlmock, mockUser models.User) { - rows := sqlmock.NewRows([]string{ - "id", "mobile", "address", "active", "last_login", "last_password_change", "token", "deleted_at", - }).AddRow( - mockUser.ID, mockUser.Mobile, mockUser.Address, mockUser.Active, - mockUser.LastLogin, mockUser.LastPasswordChange, mockUser.Token, mockUser.DeletedAt, - ) - mock.ExpectQuery(regexp.QuoteMeta(`INSERT INTO "users"`)). - WithArgs( - mockUser.FirstName, mockUser.LastName, mockUser.Username, AnyString{}, mockUser.Email, - mockUser.RoleID, AnyTime{}, AnyTime{}, - ). - WillReturnRows(rows) -} - type createUserType struct { - name string - req fm.UserCreateInput - wantResp *fm.User - wantErr bool - init func() *gomonkey.Patches - initmocks func(mock sqlmock.Sqlmock, mockUser models.User) + name string + req fm.UserCreateInput + wantResp *fm.User + wantErr bool + init func(mock sqlmock.Sqlmock, mockUser models.User) *gomonkey.Patches } func errorFromCreateUserCase() createUserType { @@ -71,11 +53,11 @@ func errorFromCreateUserCase() createUserType { name: ErrorFromCreateUser, req: fm.UserCreateInput{}, wantErr: true, - init: func() *gomonkey.Patches { return nil }, - initmocks: func(mock sqlmock.Sqlmock, mockUser models.User) { + init: func(mock sqlmock.Sqlmock, mockUser models.User) *gomonkey.Patches { mock.ExpectQuery(regexp.QuoteMeta(`INSERT INTO "users"`)). WithArgs(). WillReturnError(fmt.Errorf("")) + return nil }, } } @@ -85,12 +67,23 @@ func errorFromThrottleCheck() createUserType { name: ErrorFromThrottleCheck, req: fm.UserCreateInput{}, wantErr: true, - init: func() *gomonkey.Patches { + init: func(mock sqlmock.Sqlmock, mockUser models.User) *gomonkey.Patches { + rows := sqlmock.NewRows([]string{ + "id", "mobile", "address", "active", "last_login", "last_password_change", "token", "deleted_at", + }).AddRow( + mockUser.ID, mockUser.Mobile, mockUser.Address, mockUser.Active, + mockUser.LastLogin, mockUser.LastPasswordChange, mockUser.Token, mockUser.DeletedAt, + ) + mock.ExpectQuery(regexp.QuoteMeta(`INSERT INTO "users"`)). + WithArgs( + mockUser.FirstName, mockUser.LastName, mockUser.Username, AnyString{}, mockUser.Email, + mockUser.RoleID, AnyTime{}, AnyTime{}, + ). + WillReturnRows(rows) return gomonkey.ApplyFunc(throttle.Check, func(ctx context.Context, limit int, dur time.Duration) error { return fmt.Errorf("Internal error") }) }, - initmocks: expectInsertUser, } } func errorFromCreateUserConfigCase() createUserType { @@ -98,12 +91,23 @@ func errorFromCreateUserConfigCase() createUserType { name: ErrorFromConfig, req: fm.UserCreateInput{}, wantErr: true, - init: func() *gomonkey.Patches { + init: func(mock sqlmock.Sqlmock, mockUser models.User) *gomonkey.Patches { + rows := sqlmock.NewRows([]string{ + "id", "mobile", "address", "active", "last_login", "last_password_change", "token", "deleted_at", + }).AddRow( + mockUser.ID, mockUser.Mobile, mockUser.Address, mockUser.Active, + mockUser.LastLogin, mockUser.LastPasswordChange, mockUser.Token, mockUser.DeletedAt, + ) + mock.ExpectQuery(regexp.QuoteMeta(`INSERT INTO "users"`)). + WithArgs( + mockUser.FirstName, mockUser.LastName, mockUser.Username, AnyString{}, mockUser.Email, + mockUser.RoleID, AnyTime{}, AnyTime{}, + ). + WillReturnRows(rows) return gomonkey.ApplyFunc(config.Load, func() (*config.Configuration, error) { return nil, fmt.Errorf("error in loading config") }) }, - initmocks: expectInsertUser, } } @@ -131,9 +135,22 @@ func createUserSuccessCase() createUserType { DeletedAt: convert.NullDotTimeToPointerInt(testutls.MockUser().DeletedAt), UpdatedAt: convert.NullDotTimeToPointerInt(testutls.MockUser().UpdatedAt), }, - wantErr: false, - init: func() *gomonkey.Patches { return nil }, - initmocks: expectInsertUser, + wantErr: false, + init: func(mock sqlmock.Sqlmock, mockUser models.User) *gomonkey.Patches { + rows := sqlmock.NewRows([]string{ + "id", "mobile", "address", "active", "last_login", "last_password_change", "token", "deleted_at", + }).AddRow( + mockUser.ID, mockUser.Mobile, mockUser.Address, mockUser.Active, + mockUser.LastLogin, mockUser.LastPasswordChange, mockUser.Token, mockUser.DeletedAt, + ) + mock.ExpectQuery(regexp.QuoteMeta(`INSERT INTO "users"`)). + WithArgs( + mockUser.FirstName, mockUser.LastName, mockUser.Username, AnyString{}, mockUser.Email, + mockUser.RoleID, AnyTime{}, AnyTime{}, + ). + WillReturnRows(rows) + return nil + }, } } func getCreateUserTestCase() []createUserType { @@ -151,28 +168,26 @@ func TestCreateUser(t *testing.T) { for _, tt := range cases { t.Run(tt.name, func(t *testing.T) { mock, cleanup, _ := testutls.SetupMockDB(t) - tt.initmocks(mock, *testutls.MockUser()) - patch := tt.init() - if patch != nil { - defer patch.Reset() - } + patch := tt.init(mock, *testutls.MockUser()) response, err := resolver.Mutation().CreateUser(context.Background(), tt.req) if tt.wantResp != nil { assert.Equal(t, tt.wantResp, response) } assert.Equal(t, tt.wantErr, err != nil) + if patch != nil { + patch.Reset() + } cleanup() }) } } type updateUserType struct { - name string - req *fm.UserUpdateInput - wantResp *fm.User - wantErr bool - init func() - initMocks func(mock sqlmock.Sqlmock) + name string + req *fm.UserUpdateInput + wantResp *fm.User + wantErr bool + init func(mock sqlmock.Sqlmock) *gomonkey.Patches } func loadUpdateUserTestCases() []updateUserType { @@ -181,9 +196,9 @@ func loadUpdateUserTestCases() []updateUserType { name: ErrorFindingUser, req: &fm.UserUpdateInput{}, wantErr: true, - init: func() {}, - initMocks: func(mock sqlmock.Sqlmock) { + init: func(mock sqlmock.Sqlmock) *gomonkey.Patches { mock.ExpectQuery(regexp.QuoteMeta(`UPDATE "users"`)).WithArgs().WillReturnError(fmt.Errorf("")) + return nil }, }, { @@ -195,19 +210,12 @@ func loadUpdateUserTestCases() []updateUserType { Address: &testutls.MockUser().Address.String, }, wantErr: true, - init: func() { - gomonkey.ApplyFunc(daos.UpdateUser, + init: func(mock sqlmock.Sqlmock) *gomonkey.Patches { + return gomonkey.ApplyFunc(daos.UpdateUser, func(user models.User, ctx context.Context) (models.User, error) { return user, fmt.Errorf("error for update user") }) }, - initMocks: func(mock sqlmock.Sqlmock) { - rows := sqlmock.NewRows([]string{"first_name"}).AddRow(testutls.MockUser().FirstName) - mock.ExpectQuery(regexp.QuoteMeta(`select * from "users"`)).WithArgs(0).WillReturnRows(rows) - // update users with new information - result := driver.Result(driver.RowsAffected(1)) - mock.ExpectExec(regexp.QuoteMeta(`UPDATE "users"`)).WillReturnResult(result) - }, }, { name: SuccessCase, @@ -225,13 +233,13 @@ func loadUpdateUserTestCases() []updateUserType { Address: &testutls.MockUser().Address.String, }, wantErr: false, - init: func() {}, - initMocks: func(mock sqlmock.Sqlmock) { + init: func(mock sqlmock.Sqlmock) *gomonkey.Patches { rows := sqlmock.NewRows([]string{"first_name"}).AddRow(testutls.MockUser().FirstName) mock.ExpectQuery(regexp.QuoteMeta(`select * from "users"`)).WithArgs(0).WillReturnRows(rows) // update users with new information result := driver.Result(driver.RowsAffected(1)) mock.ExpectExec(regexp.QuoteMeta(`UPDATE "users"`)).WillReturnResult(result) + return nil }, }, } @@ -246,43 +254,38 @@ func TestUpdateUser( t.Run( tt.name, func(t *testing.T) { - tt.init() - err := config.LoadEnv() - if err != nil { - log.Fatal(err) - } mock, cleanup, _ := testutls.SetupMockDB(t) - oldDB := boil.GetDB() - defer cleanup() - boil.SetDB(oldDB) - tt.initMocks(mock) + patches := tt.init(mock) c := context.Background() ctx := context.WithValue(c, testutls.UserKey, testutls.MockUser()) response, err := resolver1.Mutation().UpdateUser(ctx, tt.req) if tt.wantResp != nil && response != nil { assert.Equal(t, tt.wantResp, response) + } else { + assert.Equal(t, tt.wantErr, err != nil) + } + cleanup() + if patches != nil { + patches.Reset() } - assert.Equal(t, tt.wantErr, err != nil) }, ) } } type deleteUserType struct { - name string - wantResp *fm.UserDeletePayload - wantErr bool - init func() *gomonkey.Patches - initMocks func(mock sqlmock.Sqlmock) + name string + wantResp *fm.UserDeletePayload + wantErr bool + init func(mock sqlmock.Sqlmock) *gomonkey.Patches } func errorFindinguserCaseDelete() deleteUserType { return deleteUserType{ name: ErrorFindingUser, wantErr: true, - init: func() *gomonkey.Patches { return nil }, - initMocks: func(mock sqlmock.Sqlmock) { + init: func(mock sqlmock.Sqlmock) *gomonkey.Patches { mock.ExpectQuery(regexp.QuoteMeta(`select * from "users" where "id"=$1`)). WithArgs(). WillReturnError(fmt.Errorf("")) @@ -295,6 +298,7 @@ func errorFindinguserCaseDelete() deleteUserType { result := driver.Result(driver.RowsAffected(1)) mock.ExpectExec(regexp.QuoteMeta(`DELETE FROM "users" WHERE "id"=$1`)). WillReturnResult(result) + return nil }, } } @@ -303,13 +307,7 @@ func errorDeleteUserCase() deleteUserType { return deleteUserType{ name: ErrorDeleteUser, wantErr: true, - init: func() *gomonkey.Patches { - return gomonkey.ApplyFunc(daos.DeleteUser, - func(user models.User, ctx context.Context) (int64, error) { - return 0, fmt.Errorf("error for delete user") - }) - }, - initMocks: func(mock sqlmock.Sqlmock) { + init: func(mock sqlmock.Sqlmock) *gomonkey.Patches { rows := sqlmock.NewRows([]string{"id"}). AddRow(1) mock.ExpectQuery(regexp.QuoteMeta(`select * from "users" where "id"=$1`)). @@ -319,6 +317,10 @@ func errorDeleteUserCase() deleteUserType { result := driver.Result(driver.RowsAffected(1)) mock.ExpectExec(regexp.QuoteMeta(`DELETE FROM "users" WHERE "id"=$1`)). WillReturnResult(result) + return gomonkey.ApplyFunc(daos.DeleteUser, + func(user models.User, ctx context.Context) (int64, error) { + return 0, fmt.Errorf("error for delete user") + }) }, } } @@ -330,8 +332,7 @@ func deleteUserSuccessCase() deleteUserType { ID: "0", }, wantErr: false, - init: func() *gomonkey.Patches { return nil }, - initMocks: func(mock sqlmock.Sqlmock) { + init: func(mock sqlmock.Sqlmock) *gomonkey.Patches { rows := sqlmock.NewRows([]string{"id"}). AddRow(1) mock.ExpectQuery(regexp.QuoteMeta(`select * from "users" where "id"=$1`)). @@ -341,6 +342,7 @@ func deleteUserSuccessCase() deleteUserType { result := driver.Result(driver.RowsAffected(1)) mock.ExpectExec(regexp.QuoteMeta(`DELETE FROM "users" WHERE "id"=$1`)). WillReturnResult(result) + return nil }, } } @@ -361,13 +363,9 @@ func TestDeleteUser( t.Run( tt.name, func(t *testing.T) { - patch := tt.init() - if patch != nil { - defer patch.Reset() - } mock, cleanup, _ := testutls.SetupMockDB(t) + patch := tt.init(mock) // get user by id - tt.initMocks(mock) c := context.Background() ctx := context.WithValue(c, testutls.UserKey, testutls.MockUser()) response, err := resolver1.Mutation().DeleteUser(ctx) @@ -375,6 +373,9 @@ func TestDeleteUser( assert.Equal(t, tt.wantResp, response) } assert.Equal(t, tt.wantErr, err != nil) + if patch != nil { + patch.Reset() + } cleanup() }, ) From e225aa2c15391702d65675a7e268ea93b4467d80 Mon Sep 17 00:00:00 2001 From: Mac Date: Tue, 2 Apr 2024 14:34:48 +0530 Subject: [PATCH 25/39] feat: neater login test --- go.sum | 22 --- internal/server/server_test.go | 2 + internal/service/auth.go | 2 +- pkg/utl/secure/secure.go | 12 +- resolver/auth_mutations.resolvers.go | 2 +- resolver/auth_mutations.resolvers_test.go | 213 +++++++++++++--------- 6 files changed, 138 insertions(+), 115 deletions(-) diff --git a/go.sum b/go.sum index 22b31ee3..4be4f3f9 100644 --- a/go.sum +++ b/go.sum @@ -23,7 +23,6 @@ cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSU cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= -cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= @@ -34,7 +33,6 @@ cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7 cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= cloud.google.com/go/firestore v1.6.0/go.mod h1:afJwI0vaXwAG54kI7A//lP/lSPDkQORQuMkv56TxEPU= -cloud.google.com/go/firestore v1.6.1/go.mod h1:asNXNOzBdyVQmEU+ggO8UPodTkEVFW5Qx+rwHnAz+EY= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= @@ -80,7 +78,6 @@ github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdK github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= -github.com/armon/go-metrics v0.3.10/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= @@ -93,10 +90,8 @@ github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqO github.com/cenkalti/backoff/v4 v4.1.3 h1:cFAlzYUlVYDysBEH2T5hyJZMh3+5+WCBvSnK6Q8UtC4= github.com/cenkalti/backoff/v4 v4.1.3/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= @@ -110,7 +105,6 @@ github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWH github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20211130200136-a8f946100490/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= @@ -145,7 +139,6 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.m github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/envoyproxy/protoc-gen-validate v0.6.2/go.mod h1:2t7qjJNvHPx8IjnBOzl9E9/baC+qXE/TeeyBRzgJDws= github.com/ericlagergren/decimal v0.0.0-20181231230500-73749d4874d5/go.mod h1:1yj25TwtUlJ+pfOu9apAVaM1RWfZGg+aFpd4hPQZekQ= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= @@ -206,7 +199,6 @@ github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4er github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= @@ -282,7 +274,6 @@ github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= -github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= @@ -295,17 +286,13 @@ github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0 h1:BZHcxBETFHIdVyhyEfOvn/RdU/QG github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= github.com/hashicorp/consul/api v1.10.1/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M= -github.com/hashicorp/consul/api v1.11.0/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= -github.com/hashicorp/go-hclog v1.0.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= -github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= @@ -330,7 +317,6 @@ github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2p github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk= -github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= @@ -347,7 +333,6 @@ github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc= github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= @@ -443,10 +428,8 @@ github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/nbutton23/zxcvbn-go v0.0.0-20180912185939-ae427f1e4c1d h1:AREM5mwr4u1ORQBMvzfzBgpsctsbQikCVpvC+tX285E= github.com/nbutton23/zxcvbn-go v0.0.0-20180912185939-ae427f1e4c1d/go.mod h1:o96djdrsSGy3AWPyBgZMAGfxZNfgntdJG+11KU4QvbU= @@ -501,7 +484,6 @@ github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/sagikazarmark/crypt v0.1.0/go.mod h1:B/mN0msZuINBtQ1zZLEQcegFJJf9vnYIR88KRMEuODE= -github.com/sagikazarmark/crypt v0.3.0/go.mod h1:uD/D+6UF4SrIR1uGEv7bBNkNqLGqUr43MRiaGWX1Nig= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= @@ -594,11 +576,8 @@ github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5t github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= -go.etcd.io/etcd/api/v3 v3.5.1/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= -go.etcd.io/etcd/client/pkg/v3 v3.5.1/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= -go.etcd.io/etcd/client/v2 v2.305.1/go.mod h1:pMEacxZW7o8pg4CrFE7pquyCJJzZvkvdD2RibOCCCGs= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -978,7 +957,6 @@ google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNe google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= -google.golang.org/api v0.62.0/go.mod h1:dKmwPCydfsad4qCH08MSdgWjfHOyfpd4VtDGgRFdavw= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= diff --git a/internal/server/server_test.go b/internal/server/server_test.go index 288bb60a..de18c0c4 100644 --- a/internal/server/server_test.go +++ b/internal/server/server_test.go @@ -77,9 +77,11 @@ func TestStart(t *testing.T) { }) } } + type testCase struct { args args } + func getTestCases() map[string]testCase { return map[string]testCase{ "Success": { diff --git a/internal/service/auth.go b/internal/service/auth.go index d0d30aa0..07ee5926 100644 --- a/internal/service/auth.go +++ b/internal/service/auth.go @@ -10,7 +10,7 @@ import ( ) // Secure returns new secure service -func Secure(cfg *config.Configuration) *secure.Service { +func Secure(cfg *config.Configuration) secure.Service { return secure.New(cfg.App.MinPasswordStr, sha1.New()) } diff --git a/pkg/utl/secure/secure.go b/pkg/utl/secure/secure.go index ee2d266d..766b6b7a 100644 --- a/pkg/utl/secure/secure.go +++ b/pkg/utl/secure/secure.go @@ -11,8 +11,8 @@ import ( ) // New initializes security service -func New(minPWStr int, h hash.Hash) *Service { - return &Service{minPWStr: minPWStr, h: h} +func New(minPWStr int, h hash.Hash) Service { + return Service{minPWStr: minPWStr, h: h} } // Service holds security related methods @@ -22,24 +22,24 @@ type Service struct { } // Password checks whether password is secure enough using zxcvbn library -func (s *Service) Password(pass string, inputs ...string) bool { +func (s Service) Password(pass string, inputs ...string) bool { pwStrength := zxcvbn.PasswordStrength(pass, inputs) return pwStrength.Score >= s.minPWStr } // Hash hashes the password using bcrypt -func (*Service) Hash(password string) string { +func (Service) Hash(password string) string { hashedPW, _ := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) return string(hashedPW) } // HashMatchesPassword matches hash with password. Returns true if hash and password match. -func (*Service) HashMatchesPassword(hash, password string) bool { +func (Service) HashMatchesPassword(hash, password string) bool { return bcrypt.CompareHashAndPassword([]byte(hash), []byte(password)) == nil } // Token generates new unique token -func (s *Service) Token(str string) string { +func (s Service) Token(str string) string { s.h.Reset() fmt.Fprintf(s.h, "%s%s", str, strconv.Itoa(time.Now().Nanosecond())) return fmt.Sprintf("%x", s.h.Sum(nil)) diff --git a/resolver/auth_mutations.resolvers.go b/resolver/auth_mutations.resolvers.go index bc24a9bc..bf347c93 100644 --- a/resolver/auth_mutations.resolvers.go +++ b/resolver/auth_mutations.resolvers.go @@ -32,7 +32,7 @@ func (r *mutationResolver) Login(ctx context.Context, username string, password sec := service.Secure(cfg) tg, err := service.JWT(cfg) if err != nil { - return nil, fmt.Errorf("error in creating auth service ") + return nil, fmt.Errorf("error in creating auth service") } if !u.Password.Valid || (!sec.HashMatchesPassword(u.Password.String, password)) { diff --git a/resolver/auth_mutations.resolvers_test.go b/resolver/auth_mutations.resolvers_test.go index 117b8b53..41979754 100644 --- a/resolver/auth_mutations.resolvers_test.go +++ b/resolver/auth_mutations.resolvers_test.go @@ -4,17 +4,21 @@ import ( "context" "database/sql/driver" "fmt" + "go-template/daos" "reflect" "regexp" "strings" "testing" + "github.com/volatiletech/null/v8" + fm "go-template/gqlmodels" "go-template/internal/config" "go-template/internal/jwt" "go-template/internal/service" "go-template/models" "go-template/pkg/utl/resultwrapper" + "go-template/pkg/utl/secure" "go-template/resolver" "go-template/testutls" @@ -84,13 +88,10 @@ func errorFindingUserCase() loginType { wantErr: true, err: fmt.Errorf(ErrorMsgFindingUser), init: func(mock sqlmock.Sqlmock) *gomonkey.Patches { - mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (username=$1) LIMIT 1;`)). - WithArgs(). - WillReturnError(fmt.Errorf(ErrorMsgFindingUser)) - tg := jwt.Service{} - return gomonkey.ApplyFunc(tg.GenerateToken, func(u *models.User) (string, error) { - return "", nil - }) + return gomonkey.ApplyFunc(daos.FindUserByUserName, + func(username string, ctx context.Context) (*models.User, error) { + return nil, fmt.Errorf(ErrorMsgFindingUser) + }) }, } } @@ -127,15 +128,14 @@ func errorActiveStatusCase() loginType { wantErr: true, err: resultwrapper.ErrUnauthorized, init: func(mock sqlmock.Sqlmock) *gomonkey.Patches { - rows := sqlmock.NewRows([]string{"id", "password", "active", "role_id"}). - AddRow(testutls.MockID, OldPasswordHash, true, 1) - mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (username=$1) LIMIT 1;`)). - WithArgs(). - WillReturnRows(rows) - tg := jwt.Service{} - return gomonkey.ApplyFunc(tg.GenerateToken, func(u *models.User) (string, error) { - return "", nil - }) + // mock FindUserByUserName with the proper password, and active state + return gomonkey.ApplyFunc(daos.FindUserByUserName, + func(username string, ctx context.Context) (*models.User, error) { + user := testutls.MockUser() + user.Password = null.StringFrom(OldPasswordHash) + user.Active = null.BoolFrom(false) + return user, nil + }) }, } } @@ -149,19 +149,21 @@ func errorFromConfigCase() loginType { wantErr: true, err: fmt.Errorf(ErrorMsgFromConfig), init: func(mock sqlmock.Sqlmock) *gomonkey.Patches { - rows := sqlmock.NewRows([]string{"id", "password", "active", "role_id"}). - AddRow(testutls.MockID, OldPasswordHash, true, 1) - mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (username=$1) LIMIT 1;`)). - WithArgs(). - WillReturnRows(rows) - return gomonkey.ApplyFunc(config.Load, func() (*config.Configuration, error) { - return nil, fmt.Errorf("error in loading config") - }) + return gomonkey.ApplyFunc(daos.FindUserByUserName, + func(username string, ctx context.Context) (*models.User, error) { + user := testutls.MockUser() + user.Password = null.StringFrom(OldPasswordHash) + user.Active = null.BoolFrom(false) + return user, nil + }). + ApplyFunc(config.Load, func() (*config.Configuration, error) { + return nil, fmt.Errorf("error in loading config") + }) }, } } -func errorFromJwtCase() loginType { +func errorWhileGeneratingToken() loginType { return loginType{ name: ErrorFromJwt, req: loginArgs{ @@ -169,87 +171,130 @@ func errorFromJwtCase() loginType { Password: OldPassword, }, wantErr: true, - err: fmt.Errorf(ErrorMsgFromJwt), + err: resultwrapper.ErrUnauthorized, init: func(mock sqlmock.Sqlmock) *gomonkey.Patches { - rows := sqlmock.NewRows([]string{"id", "password", "active", "role_id"}). - AddRow(testutls.MockID, OldPasswordHash, true, 1) - mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (username=$1) LIMIT 1;`)). - WithArgs(). - WillReturnRows(rows) tg := jwt.Service{} - return gomonkey.ApplyFunc(service.JWT, func(cfg *config.Configuration) (jwt.Service, error) { - return tg, fmt.Errorf(ErrorMsgFromJwt) - }) + return gomonkey.ApplyFunc(daos.FindUserByUserName, + func(username string, ctx context.Context) (*models.User, error) { + user := testutls.MockUser() + user.Password = null.StringFrom(OldPasswordHash) + user.Active = null.BoolFrom(true) + return user, nil + }). + ApplyFunc(service.JWT, func(cfg *config.Configuration) (jwt.Service, error) { + return tg, nil + }). + ApplyMethod(reflect.TypeOf(tg), "GenerateToken", + func(jwt.Service, *models.User) (string, error) { + return "", fmt.Errorf(ErrorMsgFromJwt) + }) }, } } -func errorFromGenerateTokenCase() loginType { +func errorUpdateUserCase() loginType { + err := fmt.Errorf(ErrorMsgfromUpdateUser) return loginType{ - name: ErrorFromGenerateToken, + name: ErrorUpdateUser, req: loginArgs{ UserName: testutls.MockEmail, Password: OldPassword, }, wantErr: true, - err: resultwrapper.ErrUnauthorized, + err: err, init: func(mock sqlmock.Sqlmock) *gomonkey.Patches { - rows := sqlmock.NewRows([]string{"id", "password", "active", "role_id"}). - AddRow(testutls.MockID, OldPasswordHash, true, 1) - mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (username=$1) LIMIT 1;`)). - WithArgs(). - WillReturnRows(rows) tg := jwt.Service{} - return gomonkey.ApplyFunc(tg.GenerateToken, func(u *models.User) (string, error) { - return "", resultwrapper.ErrUnauthorized - }) + sec := secure.Service{} + return gomonkey.ApplyFunc(daos.FindUserByUserName, + func(username string, ctx context.Context) (*models.User, error) { + user := testutls.MockUser() + user.Password = null.StringFrom(OldPasswordHash) + user.Active = null.BoolFrom(true) + return user, nil + }). + ApplyFunc(service.JWT, func(cfg *config.Configuration) (jwt.Service, error) { + return tg, nil + }). + ApplyFunc(service.Secure, func(cfg *config.Configuration) secure.Service { + return sec + }). + ApplyMethod(reflect.TypeOf(tg), "GenerateToken", + func(jwt.Service, *models.User) (string, error) { + return "", nil + }). + ApplyMethod(reflect.TypeOf(sec), "Token", + func(secure.Service, string) string { + return "refreshToken" + }). + ApplyFunc(daos.UpdateUser, + func(u models.User, ctx context.Context) (models.User, error) { + return models.User{}, err + }) }, } } -func errorUpdateUserCase() loginType { +func loginSuccessCase() loginType { + jwtToken := "jwttokenstring" return loginType{ - name: ErrorUpdateUser, + name: SuccessCase, req: loginArgs{ UserName: testutls.MockEmail, Password: OldPassword, }, - wantErr: true, - err: fmt.Errorf(ErrorMsgfromUpdateUser), + wantResp: &fm.LoginResponse{ + Token: jwtToken, + RefreshToken: TestToken, + }, init: func(mock sqlmock.Sqlmock) *gomonkey.Patches { - rows := sqlmock.NewRows([]string{"id", "name"}). - AddRow(1, "ADMIN") - mock.ExpectQuery(regexp.QuoteMeta(`SELECT "roles".* FROM "roles" WHERE ("id" = $1) LIMIT 1`)). - WithArgs([]driver.Value{1}...). - WillReturnRows(rows) - mock.ExpectExec(regexp.QuoteMeta(`UPDATE "users" `)).WillReturnError(fmt.Errorf(ErrorMsgfromUpdateUser)) tg := jwt.Service{} - return gomonkey.ApplyFunc(tg.GenerateToken, func(u *models.User) (string, error) { - return "", nil - }) + sec := secure.Service{} + return gomonkey.ApplyFunc(daos.FindUserByUserName, + func(username string, ctx context.Context) (*models.User, error) { + user := testutls.MockUser() + user.Password = null.StringFrom(OldPasswordHash) + user.Active = null.BoolFrom(true) + return user, nil + }). + ApplyFunc(service.JWT, func(cfg *config.Configuration) (jwt.Service, error) { + return tg, nil + }). + ApplyFunc(service.Secure, func(cfg *config.Configuration) secure.Service { + return sec + }). + ApplyMethod(reflect.TypeOf(tg), "GenerateToken", + func(jwt.Service, *models.User) (string, error) { + return jwtToken, nil + }). + ApplyMethod(reflect.TypeOf(sec), "Token", + func(secure.Service, string) string { + return TestToken + }). + ApplyFunc(daos.UpdateUser, + func(u models.User, ctx context.Context) (models.User, error) { + return *testutls.MockUser(), nil + }) }, } } -func loginSuccessCase() loginType { +func errorWhileCreatingJWTService() loginType { + err := fmt.Errorf("error in creating auth service") return loginType{ - name: SuccessCase, + name: "Error while creating a JWT Service", req: loginArgs{ UserName: testutls.MockEmail, Password: OldPassword, }, - wantResp: &fm.LoginResponse{ - Token: "jwttokenstring", - RefreshToken: TestToken, - }, + wantErr: true, + err: err, init: func(mock sqlmock.Sqlmock) *gomonkey.Patches { - rows := sqlmock.NewRows([]string{"id", "name"}). - AddRow(1, "ADMIN") - mock.ExpectQuery(regexp.QuoteMeta(`SELECT "roles".* FROM "roles" WHERE ("id" = $1) LIMIT 1`)). - WithArgs([]driver.Value{1}...). - WillReturnRows(rows) - result := driver.Result(driver.RowsAffected(1)) - mock.ExpectExec(regexp.QuoteMeta(`UPDATE "users" `)).WillReturnResult(result) - tg := jwt.Service{} - return gomonkey.ApplyFunc(tg.GenerateToken, func(u *models.User) (string, error) { - return "", nil + return gomonkey.ApplyFunc(daos.FindUserByUserName, + func(username string, ctx context.Context) (*models.User, error) { + user := testutls.MockUser() + user.Password = null.StringFrom(OldPasswordHash) + user.Active = null.BoolFrom(false) + return user, nil + }).ApplyFunc(service.JWT, func(cfg *config.Configuration) (jwt.Service, error) { + // mock service.JWT + return jwt.Service{}, err }) }, } @@ -257,11 +302,11 @@ func loginSuccessCase() loginType { func loadLoginTestCases() []loginType { return []loginType{ errorFindingUserCase(), + errorFromConfigCase(), errorPasswordValidationCase(), errorActiveStatusCase(), - errorFromConfigCase(), - errorFromJwtCase(), - errorFromGenerateTokenCase(), + errorWhileCreatingJWTService(), + errorWhileGeneratingToken(), errorUpdateUserCase(), loginSuccessCase(), } @@ -284,8 +329,6 @@ func TestLogin( response, err := resolver1.Mutation().Login(c, tt.req.UserName, tt.req.Password) if tt.wantResp != nil && response != nil { - tt.wantResp.RefreshToken = response.RefreshToken - tt.wantResp.Token = response.Token // Assert that the expected response matches the actual response assert.Equal(t, tt.wantResp, response) } else { @@ -510,7 +553,7 @@ func refreshTokenInvalidCase() refereshTokenType { tg := jwt.Service{} return gomonkey.ApplyMethod(reflect.TypeOf(tg), "GenerateToken", func(jwt.Service, *models.User) (string, error) { - return "token", nil + return "", nil }) }, }, @@ -543,7 +586,7 @@ func refreshTokenErrorFromConfigCase() refereshTokenType { tg := jwt.Service{} return gomonkey.ApplyMethod(reflect.TypeOf(tg), "GenerateToken", func(jwt.Service, *models.User) (string, error) { - return "token", nil + return "", nil }) }, }, @@ -557,7 +600,7 @@ func refreshTokenErrorFromConfigCase() refereshTokenType { } } -func refereshTokenErrorFromJWTCase() refereshTokenType { +func refereshTokenerrorWhileGeneratingToken() refereshTokenType { return refereshTokenType{ name: ErrorFromJwt, req: ReqToken, @@ -579,7 +622,7 @@ func refereshTokenErrorFromJWTCase() refereshTokenType { tg := jwt.Service{} return gomonkey.ApplyMethod(reflect.TypeOf(tg), "GenerateToken", func(jwt.Service, *models.User) (string, error) { - return "token", nil + return "", nil }) }, }, @@ -653,7 +696,7 @@ func refreshTokenSuccessCase() refereshTokenType { tg := jwt.Service{} return gomonkey.ApplyMethod(reflect.TypeOf(tg), "GenerateToken", func(jwt.Service, *models.User) (string, error) { - return "token", nil + return "", nil }) }, }, @@ -670,7 +713,7 @@ func loadRefereshTokenCases() []refereshTokenType { return []refereshTokenType{ refreshTokenInvalidCase(), refreshTokenErrorFromConfigCase(), - refereshTokenErrorFromJWTCase(), + refereshTokenerrorWhileGeneratingToken(), refereshTokenErrorFromGenerateTokenCase(), refreshTokenSuccessCase(), } From 3085e93ddd0c599c4fcf2274a097caab0ecf5bd8 Mon Sep 17 00:00:00 2001 From: Mac Date: Tue, 2 Apr 2024 14:58:53 +0530 Subject: [PATCH 26/39] feat: neater createrole test --- resolver/role_mutations.resolvers_test.go | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/resolver/role_mutations.resolvers_test.go b/resolver/role_mutations.resolvers_test.go index 9b05d9c0..c4b43d57 100644 --- a/resolver/role_mutations.resolvers_test.go +++ b/resolver/role_mutations.resolvers_test.go @@ -8,6 +8,7 @@ import ( "go-template/models" "go-template/pkg/utl/rediscache" "go-template/resolver" + "go-template/testutls" "testing" "github.com/agiledragon/gomonkey/v2" @@ -74,6 +75,10 @@ func errorUnauthorizedUserCase() createRoleType { } } func successCase() createRoleType { + role := models.Role{ + AccessLevel: int(constants.SuperAdminRole), + Name: SuperAdminRoleName, + } return createRoleType{ name: SuccessCase, req: fm.RoleCreateInput{ @@ -88,11 +93,16 @@ func successCase() createRoleType { init: func() *gomonkey.Patches { return gomonkey.ApplyFunc(daos.CreateRole, func(role models.Role, ctx context.Context) (models.Role, error) { - return models.Role{ - AccessLevel: int(constants.SuperAdminRole), - Name: SuperAdminRoleName, - }, nil - }) + return role, nil + }). + ApplyFunc(rediscache.GetUser, + func(userID int, ctx context.Context) (*models.User, error) { + return testutls.MockUser(), nil + }). + ApplyFunc(rediscache.GetRole, + func(userID int, ctx context.Context) (*models.Role, error) { + return &role, nil + }) }, } } @@ -118,8 +128,8 @@ func loadTestCases() []createRoleType { errorFromRedisCase(), errorFromGetRoleCase(), errorUnauthorizedUserCase(), - successCase(), errorFromCreateRoleCase(), + successCase(), } } From d0451a08fc03c780a90244048959b6c332c5e99d Mon Sep 17 00:00:00 2001 From: HIMANSHU Date: Tue, 2 Apr 2024 18:50:34 +0530 Subject: [PATCH 27/39] change password neater tests --- resolver/auth_mutations.resolvers_test.go | 85 ++++++++++++----------- 1 file changed, 45 insertions(+), 40 deletions(-) diff --git a/resolver/auth_mutations.resolvers_test.go b/resolver/auth_mutations.resolvers_test.go index 41979754..10f06ccc 100644 --- a/resolver/auth_mutations.resolvers_test.go +++ b/resolver/auth_mutations.resolvers_test.go @@ -2,7 +2,6 @@ package resolver_test import ( "context" - "database/sql/driver" "fmt" "go-template/daos" "reflect" @@ -364,10 +363,10 @@ func changePasswordErrorFindingUserCase() changePasswordType { }, wantErr: true, init: func(mock sqlmock.Sqlmock) *gomonkey.Patches { - mock.ExpectQuery(regexp.QuoteMeta(`select * from "users" where "id"=$1`)). - WithArgs(). - WillReturnError(fmt.Errorf("")) - return nil + return gomonkey.ApplyFunc(daos.FindUserByUserName, + func(username string, ctx context.Context) (*models.User, error) { + return nil, fmt.Errorf(ErrorMsgFindingUser) + }) }, } } @@ -380,12 +379,10 @@ func changePasswordErrorPasswordValidationcase() changePasswordType { }, wantErr: true, init: func(mock sqlmock.Sqlmock) *gomonkey.Patches { - rows := sqlmock.NewRows([]string{"id", "email", "password"}). - AddRow(testutls.MockID, testutls.MockEmail, OldPasswordHash) - mock.ExpectQuery(regexp.QuoteMeta(`select * from "users" where "id"=$1`)). - WithArgs(). - WillReturnRows(rows) - return nil + tg := jwt.Service{} + return gomonkey.ApplyFunc(tg.GenerateToken, func(u *models.User) (string, error) { + return "", nil + }) }, } } @@ -399,12 +396,14 @@ func changePasswordErrorInsecurePasswordCase() changePasswordType { }, wantErr: true, init: func(mock sqlmock.Sqlmock) *gomonkey.Patches { - rows := sqlmock.NewRows([]string{"id", "email", "password"}). - AddRow(testutls.MockID, testutls.MockEmail, OldPasswordHash) - mock.ExpectQuery(regexp.QuoteMeta(`select * from "users" where "id"=$1`)). - WithArgs(). - WillReturnRows(rows) - return nil + // mock FindUserByUserName with the proper password, and active state + return gomonkey.ApplyFunc(daos.FindUserByID, + func(userID int, ctx context.Context) (*models.User, error) { + user := testutls.MockUser() + user.Password = null.StringFrom(OldPasswordHash) + user.Active = null.BoolFrom(false) + return user, fmt.Errorf(ErrorInsecurePassword) + }) }, } } @@ -418,13 +417,16 @@ func changePasswordErrorUpdateUserCase() changePasswordType { }, wantErr: true, init: func(mock sqlmock.Sqlmock) *gomonkey.Patches { - rows := sqlmock.NewRows([]string{"id", "email", "password"}). - AddRow(testutls.MockID, testutls.MockEmail, OldPasswordHash) - mock.ExpectQuery(regexp.QuoteMeta(`select * from "users" where "id"=$1`)). - WithArgs(). - WillReturnRows(rows) - mock.ExpectExec(regexp.QuoteMeta(`UPDATE "users" `)).WillReturnError(fmt.Errorf("errrorr")) - return nil + return gomonkey.ApplyFunc(daos.FindUserByID, + func(userID int, ctx context.Context) (*models.User, error) { + user := testutls.MockUser() + user.Password = null.StringFrom(OldPasswordHash) + user.Active = null.BoolFrom(false) + return user, fmt.Errorf(ErrorInsecurePassword) + }).ApplyFunc(daos.UpdateUser, + func(user models.User, ctx context.Context) (*models.User, error) { + return nil, fmt.Errorf(ErrorUpdateUser) + }) }, } } @@ -438,14 +440,8 @@ func changePasswordErrorFromConfigCase() changePasswordType { }, wantErr: true, init: func(mock sqlmock.Sqlmock) *gomonkey.Patches { - rows := sqlmock.NewRows([]string{"id", "email", "password"}). - AddRow(testutls.MockID, testutls.MockEmail, OldPasswordHash) - mock.ExpectQuery(regexp.QuoteMeta(`select * from "users" where "id"=$1`)). - WithArgs(). - WillReturnRows(rows) - tg := jwt.Service{} - return gomonkey.ApplyFunc(service.JWT, func(cfg *config.Configuration) (jwt.Service, error) { - return tg, fmt.Errorf(ErrorMsgFromJwt) + return gomonkey.ApplyFunc(config.Load, func() (*config.Configuration, error) { + return nil, fmt.Errorf("error in loading config") }) }, } @@ -463,14 +459,23 @@ func changePasswordSuccessCase() changePasswordType { }, wantErr: false, init: func(mock sqlmock.Sqlmock) *gomonkey.Patches { - rows := sqlmock.NewRows([]string{"id", "email", "password"}). - AddRow(testutls.MockID, testutls.MockEmail, OldPasswordHash) - mock.ExpectQuery(regexp.QuoteMeta(`select * from "users" where "id"=$1`)). - WithArgs(). - WillReturnRows(rows) - result := driver.Result(driver.RowsAffected(1)) - mock.ExpectExec(regexp.QuoteMeta(`UPDATE "users" `)).WillReturnResult(result) - return nil + sec := secure.Service{} + return gomonkey.ApplyFunc(config.Load, func() (*config.Configuration, error) { + return nil, nil + }).ApplyFunc(service.Secure, func(cfg *config.Configuration) secure.Service { + return sec + }).ApplyMethod(reflect.TypeOf(sec), "Password", func(secure.Service, string, ...string) bool { + return true + }).ApplyFunc(daos.FindUserByID, + func(userID int, ctx context.Context) (*models.User, error) { + user := testutls.MockUser() + user.Password = null.StringFrom(OldPasswordHash) + user.Active = null.BoolFrom(false) + return user, nil + }).ApplyFunc(daos.UpdateUser, + func(user models.User, ctx context.Context) (models.User, error) { + return *testutls.MockUser(), nil + }) }, } } From 65f8ce37f8a5c53b2783287c412dbf1405b297a3 Mon Sep 17 00:00:00 2001 From: HIMANSHU Date: Tue, 2 Apr 2024 21:21:41 +0530 Subject: [PATCH 28/39] referesh token neater tests --- resolver/auth_mutations.resolvers_test.go | 215 ++++++---------------- 1 file changed, 61 insertions(+), 154 deletions(-) diff --git a/resolver/auth_mutations.resolvers_test.go b/resolver/auth_mutations.resolvers_test.go index 10f06ccc..0e4e1023 100644 --- a/resolver/auth_mutations.resolvers_test.go +++ b/resolver/auth_mutations.resolvers_test.go @@ -522,18 +522,12 @@ func TestChangePassword( } type refereshTokenType struct { - name string - req string - wantResp *fm.RefreshTokenResponse - wantErr bool - err error - init refereshTokenPatches - initMocks func(mock sqlmock.Sqlmock) -} -type refereshTokenPatches struct { - configPatch func() *gomonkey.Patches - jwtPatch func() *gomonkey.Patches - tokenPatch func() *gomonkey.Patches + name string + req string + wantResp *fm.RefreshTokenResponse + wantErr bool + err error + init func() *gomonkey.Patches } func refreshTokenInvalidCase() refereshTokenType { @@ -542,30 +536,18 @@ func refreshTokenInvalidCase() refereshTokenType { req: TestToken, wantErr: true, err: fmt.Errorf(ErrorMsginvalidToken), - init: refereshTokenPatches{ - configPatch: func() *gomonkey.Patches { - return gomonkey.ApplyFunc(config.Load, func() (*config.Configuration, error) { - return &config.Configuration{}, nil - }) - }, - jwtPatch: func() *gomonkey.Patches { - tg := jwt.Service{} - return gomonkey.ApplyFunc(service.JWT, func(cfg *config.Configuration) (jwt.Service, error) { - return tg, nil - }) - }, - tokenPatch: func() *gomonkey.Patches { - tg := jwt.Service{} - return gomonkey.ApplyMethod(reflect.TypeOf(tg), "GenerateToken", - func(jwt.Service, *models.User) (string, error) { - return "", nil - }) - }, - }, - initMocks: func(mock sqlmock.Sqlmock) { - mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (token=$1) LIMIT 1;`)). - WithArgs(). - WillReturnError(fmt.Errorf(ErrorMsginvalidToken)) + init: func() *gomonkey.Patches { + tg := jwt.Service{} + return gomonkey.ApplyFunc(config.Load, func() (*config.Configuration, error) { + return &config.Configuration{}, nil + }).ApplyFunc(service.JWT, func(cfg *config.Configuration) (jwt.Service, error) { + return tg, nil + }).ApplyMethod(reflect.TypeOf(tg), "GenerateToken", + func(jwt.Service, *models.User) (string, error) { + return "", fmt.Errorf(ErrorMsginvalidToken) + }).ApplyFunc(daos.FindUserByToken, func(token string, ctx context.Context) (*models.User, error) { + return testutls.MockUser(), nil + }) }, } } @@ -575,32 +557,13 @@ func refreshTokenErrorFromConfigCase() refereshTokenType { req: ReqToken, wantErr: true, err: fmt.Errorf(ErrorMsgFromConfig), - init: refereshTokenPatches{ - configPatch: func() *gomonkey.Patches { - return gomonkey.ApplyFunc(config.Load, func() (*config.Configuration, error) { - return nil, fmt.Errorf("error in loading config") - }) - }, - jwtPatch: func() *gomonkey.Patches { - tg := jwt.Service{} - return gomonkey.ApplyFunc(service.JWT, func(cfg *config.Configuration) (jwt.Service, error) { - return tg, nil - }) - }, - tokenPatch: func() *gomonkey.Patches { - tg := jwt.Service{} - return gomonkey.ApplyMethod(reflect.TypeOf(tg), "GenerateToken", - func(jwt.Service, *models.User) (string, error) { - return "", nil - }) - }, - }, - initMocks: func(mock sqlmock.Sqlmock) { - rows := sqlmock.NewRows([]string{"id", "email", "token", "role_id"}). - AddRow(1, testutls.MockEmail, testutls.MockToken, 1) - mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (token=$1) LIMIT 1;`)). - WithArgs(). - WillReturnRows(rows) + init: func() *gomonkey.Patches { + // tg := jwt.Service{} + return gomonkey.ApplyFunc(config.Load, func() (*config.Configuration, error) { + return nil, fmt.Errorf(ErrorFromConfig) + }).ApplyFunc(daos.FindUserByToken, func(token string, ctx context.Context) (*models.User, error) { + return testutls.MockUser(), nil + }) }, } } @@ -611,32 +574,15 @@ func refereshTokenerrorWhileGeneratingToken() refereshTokenType { req: ReqToken, wantErr: true, err: fmt.Errorf(ErrorMsgFromJwt), - init: refereshTokenPatches{ - configPatch: func() *gomonkey.Patches { - return gomonkey.ApplyFunc(config.Load, func() (*config.Configuration, error) { - return &config.Configuration{}, nil - }) - }, - jwtPatch: func() *gomonkey.Patches { - tg := jwt.Service{} - return gomonkey.ApplyFunc(service.JWT, func(cfg *config.Configuration) (jwt.Service, error) { - return tg, fmt.Errorf(ErrorMsgFromJwt) - }) - }, - tokenPatch: func() *gomonkey.Patches { - tg := jwt.Service{} - return gomonkey.ApplyMethod(reflect.TypeOf(tg), "GenerateToken", - func(jwt.Service, *models.User) (string, error) { - return "", nil - }) - }, - }, - initMocks: func(mock sqlmock.Sqlmock) { - rows := sqlmock.NewRows([]string{"id", "email", "token", "role_id"}). - AddRow(1, testutls.MockEmail, testutls.MockToken, 1) - mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (token=$1) LIMIT 1;`)). - WithArgs(). - WillReturnRows(rows) + init: func() *gomonkey.Patches { + tg := jwt.Service{} + return gomonkey.ApplyFunc(config.Load, func() (*config.Configuration, error) { + return &config.Configuration{}, nil + }).ApplyFunc(service.JWT, func(cfg *config.Configuration) (jwt.Service, error) { + return tg, fmt.Errorf(ErrorMsgFromJwt) + }).ApplyFunc(daos.FindUserByToken, func(token string, ctx context.Context) (*models.User, error) { + return testutls.MockUser(), nil + }) }, } } @@ -647,32 +593,18 @@ func refereshTokenErrorFromGenerateTokenCase() refereshTokenType { req: ReqToken, wantErr: true, err: resultwrapper.ErrUnauthorized, - init: refereshTokenPatches{ - configPatch: func() *gomonkey.Patches { - return gomonkey.ApplyFunc(config.Load, func() (*config.Configuration, error) { - return &config.Configuration{}, nil - }) - }, - jwtPatch: func() *gomonkey.Patches { - tg := jwt.Service{} - return gomonkey.ApplyFunc(service.JWT, func(cfg *config.Configuration) (jwt.Service, error) { - return tg, nil - }) - }, - tokenPatch: func() *gomonkey.Patches { - tg := jwt.Service{} - return gomonkey.ApplyMethod(reflect.TypeOf(tg), "GenerateToken", - func(jwt.Service, *models.User) (string, error) { - return "", resultwrapper.ErrUnauthorized - }) - }, - }, - initMocks: func(mock sqlmock.Sqlmock) { - rows := sqlmock.NewRows([]string{"id", "email", "token", "role_id"}). - AddRow(1, testutls.MockEmail, testutls.MockToken, 1) - mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (token=$1) LIMIT 1;`)). - WithArgs(). - WillReturnRows(rows) + init: func() *gomonkey.Patches { + tg := jwt.Service{} + return gomonkey.ApplyFunc(config.Load, func() (*config.Configuration, error) { + return &config.Configuration{}, nil + }).ApplyFunc(service.JWT, func(cfg *config.Configuration) (jwt.Service, error) { + return tg, nil + }).ApplyMethod(reflect.TypeOf(tg), "GenerateToken", + func(jwt.Service, *models.User) (string, error) { + return "", resultwrapper.ErrUnauthorized + }).ApplyFunc(daos.FindUserByToken, func(token string, ctx context.Context) (*models.User, error) { + return testutls.MockUser(), nil + }) }, } } @@ -685,32 +617,18 @@ func refreshTokenSuccessCase() refereshTokenType { Token: testutls.MockToken, }, wantErr: false, - init: refereshTokenPatches{ - configPatch: func() *gomonkey.Patches { - return gomonkey.ApplyFunc(config.Load, func() (*config.Configuration, error) { - return &config.Configuration{}, nil - }) - }, - jwtPatch: func() *gomonkey.Patches { - tg := jwt.Service{} - return gomonkey.ApplyFunc(service.JWT, func(cfg *config.Configuration) (jwt.Service, error) { - return tg, nil - }) - }, - tokenPatch: func() *gomonkey.Patches { - tg := jwt.Service{} - return gomonkey.ApplyMethod(reflect.TypeOf(tg), "GenerateToken", - func(jwt.Service, *models.User) (string, error) { - return "", nil - }) - }, - }, - initMocks: func(mock sqlmock.Sqlmock) { - rows := sqlmock.NewRows([]string{"id", "email", "token", "role_id"}). - AddRow(1, testutls.MockEmail, testutls.MockToken, 1) - mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (token=$1) LIMIT 1;`)). - WithArgs(). - WillReturnRows(rows) + init: func() *gomonkey.Patches { + tg := jwt.Service{} + return gomonkey.ApplyFunc(config.Load, func() (*config.Configuration, error) { + return &config.Configuration{}, nil + }).ApplyFunc(service.JWT, func(cfg *config.Configuration) (jwt.Service, error) { + return tg, nil + }).ApplyMethod(reflect.TypeOf(tg), "GenerateToken", + func(jwt.Service, *models.User) (string, error) { + return "", nil + }).ApplyFunc(daos.FindUserByToken, func(token string, ctx context.Context) (*models.User, error) { + return testutls.MockUser(), nil + }) }, } } @@ -732,18 +650,9 @@ func TestRefreshToken(t *testing.T) { t.Run( tt.name, func(t *testing.T) { - // Create a mock SQL database connection - mock, cleanup, _ := testutls.SetupMockDB(t) - defer cleanup() // Handle the case where authentication token is invalid - tt.initMocks(mock) - // Handle the case where there is an error loading the config - configpatch := tt.init.configPatch() - //initialize a jwt service - // Handle the case where there is an error creating the JWT service - patchJWT := tt.init.jwtPatch() - // Handle the case where there is an error form token generation service - patchGenerateToken := tt.init.tokenPatch() + patches := tt.init() + defer patches.Reset() // Set up the context with the mock user c := context.Background() ctx := context.WithValue(c, testutls.UserKey, testutls.MockUser()) @@ -756,12 +665,10 @@ func TestRefreshToken(t *testing.T) { // Assert that the expected response matches the actual response assert.Equal(t, tt.wantResp, response) } else { + fmt.Println(err.Error(), tt.err.Error(), strings.Contains(err.Error(), tt.err.Error())) // Assert that the expected error value matches the actual error value assert.Equal(t, true, strings.Contains(err.Error(), tt.err.Error())) } - configpatch.Reset() - patchJWT.Reset() - patchGenerateToken.Reset() }, ) } From 5d048d8f7681bfdb142eb43632d92ff8ee300e17 Mon Sep 17 00:00:00 2001 From: HIMANSHU Date: Tue, 2 Apr 2024 22:03:23 +0530 Subject: [PATCH 29/39] cmments resloved --- .vscode/settings.json | 3 +- resolver/auth_mutations.resolvers_test.go | 10 ++--- resolver/user_mutations.resolvers_test.go | 47 +++-------------------- 3 files changed, 13 insertions(+), 47 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 0e19fe39..a4cca5b1 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -18,5 +18,6 @@ "editor.insertSpaces": true, "editor.formatOnSave": true, "editor.defaultFormatter": "golang.go" - } + }, + "go.testFlags": ["-gcflags=all=-l"] } diff --git a/resolver/auth_mutations.resolvers_test.go b/resolver/auth_mutations.resolvers_test.go index 0e4e1023..a32f1a47 100644 --- a/resolver/auth_mutations.resolvers_test.go +++ b/resolver/auth_mutations.resolvers_test.go @@ -380,9 +380,10 @@ func changePasswordErrorPasswordValidationcase() changePasswordType { wantErr: true, init: func(mock sqlmock.Sqlmock) *gomonkey.Patches { tg := jwt.Service{} - return gomonkey.ApplyFunc(tg.GenerateToken, func(u *models.User) (string, error) { - return "", nil - }) + return gomonkey.ApplyMethod(reflect.TypeOf(tg), "GenerateToken", + func(jwt.Service, *models.User) (string, error) { + return "", nil + }) }, } } @@ -558,7 +559,6 @@ func refreshTokenErrorFromConfigCase() refereshTokenType { wantErr: true, err: fmt.Errorf(ErrorMsgFromConfig), init: func() *gomonkey.Patches { - // tg := jwt.Service{} return gomonkey.ApplyFunc(config.Load, func() (*config.Configuration, error) { return nil, fmt.Errorf(ErrorFromConfig) }).ApplyFunc(daos.FindUserByToken, func(token string, ctx context.Context) (*models.User, error) { @@ -652,7 +652,6 @@ func TestRefreshToken(t *testing.T) { func(t *testing.T) { // Handle the case where authentication token is invalid patches := tt.init() - defer patches.Reset() // Set up the context with the mock user c := context.Background() ctx := context.WithValue(c, testutls.UserKey, testutls.MockUser()) @@ -669,6 +668,7 @@ func TestRefreshToken(t *testing.T) { // Assert that the expected error value matches the actual error value assert.Equal(t, true, strings.Contains(err.Error(), tt.err.Error())) } + patches.Reset() }, ) } diff --git a/resolver/user_mutations.resolvers_test.go b/resolver/user_mutations.resolvers_test.go index cebb58a4..c48e3494 100644 --- a/resolver/user_mutations.resolvers_test.go +++ b/resolver/user_mutations.resolvers_test.go @@ -54,10 +54,9 @@ func errorFromCreateUserCase() createUserType { req: fm.UserCreateInput{}, wantErr: true, init: func(mock sqlmock.Sqlmock, mockUser models.User) *gomonkey.Patches { - mock.ExpectQuery(regexp.QuoteMeta(`INSERT INTO "users"`)). - WithArgs(). - WillReturnError(fmt.Errorf("")) - return nil + return gomonkey.ApplyFunc(daos.CreateUser, func(user models.User, ctx context.Context) (models.User, error) { + return *testutls.MockUser(), nil + }) }, } } @@ -68,18 +67,6 @@ func errorFromThrottleCheck() createUserType { req: fm.UserCreateInput{}, wantErr: true, init: func(mock sqlmock.Sqlmock, mockUser models.User) *gomonkey.Patches { - rows := sqlmock.NewRows([]string{ - "id", "mobile", "address", "active", "last_login", "last_password_change", "token", "deleted_at", - }).AddRow( - mockUser.ID, mockUser.Mobile, mockUser.Address, mockUser.Active, - mockUser.LastLogin, mockUser.LastPasswordChange, mockUser.Token, mockUser.DeletedAt, - ) - mock.ExpectQuery(regexp.QuoteMeta(`INSERT INTO "users"`)). - WithArgs( - mockUser.FirstName, mockUser.LastName, mockUser.Username, AnyString{}, mockUser.Email, - mockUser.RoleID, AnyTime{}, AnyTime{}, - ). - WillReturnRows(rows) return gomonkey.ApplyFunc(throttle.Check, func(ctx context.Context, limit int, dur time.Duration) error { return fmt.Errorf("Internal error") }) @@ -92,18 +79,6 @@ func errorFromCreateUserConfigCase() createUserType { req: fm.UserCreateInput{}, wantErr: true, init: func(mock sqlmock.Sqlmock, mockUser models.User) *gomonkey.Patches { - rows := sqlmock.NewRows([]string{ - "id", "mobile", "address", "active", "last_login", "last_password_change", "token", "deleted_at", - }).AddRow( - mockUser.ID, mockUser.Mobile, mockUser.Address, mockUser.Active, - mockUser.LastLogin, mockUser.LastPasswordChange, mockUser.Token, mockUser.DeletedAt, - ) - mock.ExpectQuery(regexp.QuoteMeta(`INSERT INTO "users"`)). - WithArgs( - mockUser.FirstName, mockUser.LastName, mockUser.Username, AnyString{}, mockUser.Email, - mockUser.RoleID, AnyTime{}, AnyTime{}, - ). - WillReturnRows(rows) return gomonkey.ApplyFunc(config.Load, func() (*config.Configuration, error) { return nil, fmt.Errorf("error in loading config") }) @@ -137,19 +112,9 @@ func createUserSuccessCase() createUserType { }, wantErr: false, init: func(mock sqlmock.Sqlmock, mockUser models.User) *gomonkey.Patches { - rows := sqlmock.NewRows([]string{ - "id", "mobile", "address", "active", "last_login", "last_password_change", "token", "deleted_at", - }).AddRow( - mockUser.ID, mockUser.Mobile, mockUser.Address, mockUser.Active, - mockUser.LastLogin, mockUser.LastPasswordChange, mockUser.Token, mockUser.DeletedAt, - ) - mock.ExpectQuery(regexp.QuoteMeta(`INSERT INTO "users"`)). - WithArgs( - mockUser.FirstName, mockUser.LastName, mockUser.Username, AnyString{}, mockUser.Email, - mockUser.RoleID, AnyTime{}, AnyTime{}, - ). - WillReturnRows(rows) - return nil + return gomonkey.ApplyFunc(daos.CreateUser, func(user models.User, ctx context.Context) (models.User, error) { + return *testutls.MockUser(), nil + }) }, } } From 5fc56e65f41bf5b4187aeb90a567abb2e18174be Mon Sep 17 00:00:00 2001 From: HIMANSHU Date: Tue, 2 Apr 2024 23:59:43 +0530 Subject: [PATCH 30/39] usermutaion resolved --- resolver/user_mutations.resolvers_test.go | 134 +++++++++------------- 1 file changed, 55 insertions(+), 79 deletions(-) diff --git a/resolver/user_mutations.resolvers_test.go b/resolver/user_mutations.resolvers_test.go index c48e3494..77c39f46 100644 --- a/resolver/user_mutations.resolvers_test.go +++ b/resolver/user_mutations.resolvers_test.go @@ -12,11 +12,9 @@ import ( "go-template/pkg/utl/throttle" "go-template/resolver" "go-template/testutls" - "regexp" "testing" "time" - "github.com/DATA-DOG/go-sqlmock" "github.com/agiledragon/gomonkey/v2" "github.com/stretchr/testify/assert" ) @@ -45,7 +43,7 @@ type createUserType struct { req fm.UserCreateInput wantResp *fm.User wantErr bool - init func(mock sqlmock.Sqlmock, mockUser models.User) *gomonkey.Patches + init func() *gomonkey.Patches } func errorFromCreateUserCase() createUserType { @@ -53,9 +51,9 @@ func errorFromCreateUserCase() createUserType { name: ErrorFromCreateUser, req: fm.UserCreateInput{}, wantErr: true, - init: func(mock sqlmock.Sqlmock, mockUser models.User) *gomonkey.Patches { + init: func() *gomonkey.Patches { return gomonkey.ApplyFunc(daos.CreateUser, func(user models.User, ctx context.Context) (models.User, error) { - return *testutls.MockUser(), nil + return *testutls.MockUser(), fmt.Errorf("") }) }, } @@ -66,7 +64,7 @@ func errorFromThrottleCheck() createUserType { name: ErrorFromThrottleCheck, req: fm.UserCreateInput{}, wantErr: true, - init: func(mock sqlmock.Sqlmock, mockUser models.User) *gomonkey.Patches { + init: func() *gomonkey.Patches { return gomonkey.ApplyFunc(throttle.Check, func(ctx context.Context, limit int, dur time.Duration) error { return fmt.Errorf("Internal error") }) @@ -78,7 +76,7 @@ func errorFromCreateUserConfigCase() createUserType { name: ErrorFromConfig, req: fm.UserCreateInput{}, wantErr: true, - init: func(mock sqlmock.Sqlmock, mockUser models.User) *gomonkey.Patches { + init: func() *gomonkey.Patches { return gomonkey.ApplyFunc(config.Load, func() (*config.Configuration, error) { return nil, fmt.Errorf("error in loading config") }) @@ -111,7 +109,7 @@ func createUserSuccessCase() createUserType { UpdatedAt: convert.NullDotTimeToPointerInt(testutls.MockUser().UpdatedAt), }, wantErr: false, - init: func(mock sqlmock.Sqlmock, mockUser models.User) *gomonkey.Patches { + init: func() *gomonkey.Patches { return gomonkey.ApplyFunc(daos.CreateUser, func(user models.User, ctx context.Context) (models.User, error) { return *testutls.MockUser(), nil }) @@ -132,16 +130,14 @@ func TestCreateUser(t *testing.T) { resolver := resolver.Resolver{} for _, tt := range cases { t.Run(tt.name, func(t *testing.T) { - mock, cleanup, _ := testutls.SetupMockDB(t) - patch := tt.init(mock, *testutls.MockUser()) + _, cleanup, _ := testutls.SetupMockDB(t) + patch := tt.init() response, err := resolver.Mutation().CreateUser(context.Background(), tt.req) if tt.wantResp != nil { assert.Equal(t, tt.wantResp, response) } assert.Equal(t, tt.wantErr, err != nil) - if patch != nil { - patch.Reset() - } + patch.Reset() cleanup() }) } @@ -152,7 +148,7 @@ type updateUserType struct { req *fm.UserUpdateInput wantResp *fm.User wantErr bool - init func(mock sqlmock.Sqlmock) *gomonkey.Patches + init func() *gomonkey.Patches } func loadUpdateUserTestCases() []updateUserType { @@ -161,9 +157,10 @@ func loadUpdateUserTestCases() []updateUserType { name: ErrorFindingUser, req: &fm.UserUpdateInput{}, wantErr: true, - init: func(mock sqlmock.Sqlmock) *gomonkey.Patches { - mock.ExpectQuery(regexp.QuoteMeta(`UPDATE "users"`)).WithArgs().WillReturnError(fmt.Errorf("")) - return nil + init: func() *gomonkey.Patches { + return gomonkey.ApplyFunc(daos.FindUserByID, func(userID int, ctx context.Context) (*models.User, error) { + return nil, fmt.Errorf("") + }) }, }, { @@ -175,10 +172,10 @@ func loadUpdateUserTestCases() []updateUserType { Address: &testutls.MockUser().Address.String, }, wantErr: true, - init: func(mock sqlmock.Sqlmock) *gomonkey.Patches { + init: func() *gomonkey.Patches { return gomonkey.ApplyFunc(daos.UpdateUser, - func(user models.User, ctx context.Context) (models.User, error) { - return user, fmt.Errorf("error for update user") + func(models.User, context.Context) (models.User, error) { + return *testutls.MockUser(), fmt.Errorf("error for update user") }) }, }, @@ -191,20 +188,22 @@ func loadUpdateUserTestCases() []updateUserType { Address: &testutls.MockUser().Address.String, }, wantResp: &fm.User{ - ID: "0", - FirstName: &testutls.MockUser().FirstName.String, - LastName: &testutls.MockUser().LastName.String, - Mobile: &testutls.MockUser().Mobile.String, - Address: &testutls.MockUser().Address.String, + ID: "1", + FirstName: convert.NullDotStringToPointerString(testutls.MockUser().FirstName), + LastName: convert.NullDotStringToPointerString(testutls.MockUser().LastName), + Username: convert.NullDotStringToPointerString(testutls.MockUser().Username), + Mobile: convert.NullDotStringToPointerString(testutls.MockUser().Mobile), + Address: convert.NullDotStringToPointerString(testutls.MockUser().Address), + Email: convert.NullDotStringToPointerString(testutls.MockUser().Email), + Active: &testutls.MockUser().Active.Bool, }, wantErr: false, - init: func(mock sqlmock.Sqlmock) *gomonkey.Patches { - rows := sqlmock.NewRows([]string{"first_name"}).AddRow(testutls.MockUser().FirstName) - mock.ExpectQuery(regexp.QuoteMeta(`select * from "users"`)).WithArgs(0).WillReturnRows(rows) - // update users with new information - result := driver.Result(driver.RowsAffected(1)) - mock.ExpectExec(regexp.QuoteMeta(`UPDATE "users"`)).WillReturnResult(result) - return nil + init: func() *gomonkey.Patches { + return gomonkey.ApplyFunc(daos.FindUserByID, func(userID int, ctx context.Context) (*models.User, error) { + return testutls.MockUser(), nil + }).ApplyFunc(daos.UpdateUser, func(user models.User, ctx context.Context) (models.User, error) { + return *testutls.MockUser(), nil + }) }, }, } @@ -219,8 +218,8 @@ func TestUpdateUser( t.Run( tt.name, func(t *testing.T) { - mock, cleanup, _ := testutls.SetupMockDB(t) - patches := tt.init(mock) + _, cleanup, _ := testutls.SetupMockDB(t) + patches := tt.init() c := context.Background() ctx := context.WithValue(c, testutls.UserKey, testutls.MockUser()) response, err := resolver1.Mutation().UpdateUser(ctx, tt.req) @@ -230,10 +229,9 @@ func TestUpdateUser( } else { assert.Equal(t, tt.wantErr, err != nil) } + + patches.Reset() cleanup() - if patches != nil { - patches.Reset() - } }, ) } @@ -243,27 +241,17 @@ type deleteUserType struct { name string wantResp *fm.UserDeletePayload wantErr bool - init func(mock sqlmock.Sqlmock) *gomonkey.Patches + init func() *gomonkey.Patches } func errorFindinguserCaseDelete() deleteUserType { return deleteUserType{ name: ErrorFindingUser, wantErr: true, - init: func(mock sqlmock.Sqlmock) *gomonkey.Patches { - mock.ExpectQuery(regexp.QuoteMeta(`select * from "users" where "id"=$1`)). - WithArgs(). - WillReturnError(fmt.Errorf("")) - rows := sqlmock.NewRows([]string{"id"}). - AddRow(1) - mock.ExpectQuery(regexp.QuoteMeta(`select * from "users" where "id"=$1`)). - WithArgs(). - WillReturnRows(rows) - // delete user - result := driver.Result(driver.RowsAffected(1)) - mock.ExpectExec(regexp.QuoteMeta(`DELETE FROM "users" WHERE "id"=$1`)). - WillReturnResult(result) - return nil + init: func() *gomonkey.Patches { + return gomonkey.ApplyFunc(daos.FindUserByID, func(userID int, ctx context.Context) (*models.User, error) { + return testutls.MockUser(), fmt.Errorf("") + }) }, } } @@ -272,17 +260,10 @@ func errorDeleteUserCase() deleteUserType { return deleteUserType{ name: ErrorDeleteUser, wantErr: true, - init: func(mock sqlmock.Sqlmock) *gomonkey.Patches { - rows := sqlmock.NewRows([]string{"id"}). - AddRow(1) - mock.ExpectQuery(regexp.QuoteMeta(`select * from "users" where "id"=$1`)). - WithArgs(). - WillReturnRows(rows) - // delete user - result := driver.Result(driver.RowsAffected(1)) - mock.ExpectExec(regexp.QuoteMeta(`DELETE FROM "users" WHERE "id"=$1`)). - WillReturnResult(result) - return gomonkey.ApplyFunc(daos.DeleteUser, + init: func() *gomonkey.Patches { + return gomonkey.ApplyFunc(daos.FindUserByID, func(userID int, ctx context.Context) (*models.User, error) { + return testutls.MockUser(), fmt.Errorf("") + }).ApplyFunc(daos.DeleteUser, func(user models.User, ctx context.Context) (int64, error) { return 0, fmt.Errorf("error for delete user") }) @@ -297,20 +278,17 @@ func deleteUserSuccessCase() deleteUserType { ID: "0", }, wantErr: false, - init: func(mock sqlmock.Sqlmock) *gomonkey.Patches { - rows := sqlmock.NewRows([]string{"id"}). - AddRow(1) - mock.ExpectQuery(regexp.QuoteMeta(`select * from "users" where "id"=$1`)). - WithArgs(). - WillReturnRows(rows) - // delete user - result := driver.Result(driver.RowsAffected(1)) - mock.ExpectExec(regexp.QuoteMeta(`DELETE FROM "users" WHERE "id"=$1`)). - WillReturnResult(result) - return nil + init: func() *gomonkey.Patches { + return gomonkey.ApplyFunc(daos.FindUserByID, func(userID int, ctx context.Context) (*models.User, error) { + return testutls.MockUser(), nil + }).ApplyFunc(daos.DeleteUser, + func(user models.User, ctx context.Context) (int64, error) { + return 0, nil + }) }, } } + func GetDeleteTestCases() []deleteUserType { return []deleteUserType{ errorFindinguserCaseDelete(), @@ -328,8 +306,8 @@ func TestDeleteUser( t.Run( tt.name, func(t *testing.T) { - mock, cleanup, _ := testutls.SetupMockDB(t) - patch := tt.init(mock) + patch := tt.init() + _, cleanup, _ := testutls.SetupMockDB(t) // get user by id c := context.Background() ctx := context.WithValue(c, testutls.UserKey, testutls.MockUser()) @@ -338,9 +316,7 @@ func TestDeleteUser( assert.Equal(t, tt.wantResp, response) } assert.Equal(t, tt.wantErr, err != nil) - if patch != nil { - patch.Reset() - } + patch.Reset() cleanup() }, ) From a89244dff873e5fa9d3c566799250beec80f9c2a Mon Sep 17 00:00:00 2001 From: HIMANSHU Date: Wed, 3 Apr 2024 00:11:29 +0530 Subject: [PATCH 31/39] login neater tests --- resolver/auth_mutations.resolvers_test.go | 62 ++++++++++++----------- 1 file changed, 32 insertions(+), 30 deletions(-) diff --git a/resolver/auth_mutations.resolvers_test.go b/resolver/auth_mutations.resolvers_test.go index a32f1a47..56c20c86 100644 --- a/resolver/auth_mutations.resolvers_test.go +++ b/resolver/auth_mutations.resolvers_test.go @@ -5,7 +5,6 @@ import ( "fmt" "go-template/daos" "reflect" - "regexp" "strings" "testing" @@ -21,7 +20,6 @@ import ( "go-template/resolver" "go-template/testutls" - "github.com/DATA-DOG/go-sqlmock" "github.com/agiledragon/gomonkey/v2" "github.com/stretchr/testify/assert" ) @@ -74,7 +72,7 @@ type loginType struct { wantResp *fm.LoginResponse wantErr bool err error - init func(mock sqlmock.Sqlmock) *gomonkey.Patches + init func() *gomonkey.Patches } func errorFindingUserCase() loginType { @@ -86,7 +84,7 @@ func errorFindingUserCase() loginType { }, wantErr: true, err: fmt.Errorf(ErrorMsgFindingUser), - init: func(mock sqlmock.Sqlmock) *gomonkey.Patches { + init: func() *gomonkey.Patches { return gomonkey.ApplyFunc(daos.FindUserByUserName, func(username string, ctx context.Context) (*models.User, error) { return nil, fmt.Errorf(ErrorMsgFindingUser) @@ -103,14 +101,15 @@ func errorPasswordValidationCase() loginType { }, wantErr: true, err: fmt.Errorf(ErrorMsgPasswordValidation), - init: func(mock sqlmock.Sqlmock) *gomonkey.Patches { - rows := sqlmock.NewRows([]string{"id", "password", "active", "role_id"}). - AddRow(testutls.MockID, TestPasswordHash, true, 1) - mock.ExpectQuery(regexp.QuoteMeta(`SELECT "users".* FROM "users" WHERE (username=$1) LIMIT 1;`)). - WithArgs(). - WillReturnRows(rows) + init: func() *gomonkey.Patches { tg := jwt.Service{} - return gomonkey.ApplyFunc(tg.GenerateToken, func(u *models.User) (string, error) { + return gomonkey.ApplyFunc(daos.FindUserByUserName, + func(username string, ctx context.Context) (*models.User, error) { + user := testutls.MockUser() + user.Password = null.StringFrom(OldPasswordHash) + user.Active = null.BoolFrom(false) + return user, nil + }).ApplyFunc(tg.GenerateToken, func(u *models.User) (string, error) { return "", nil }) }, @@ -126,7 +125,7 @@ func errorActiveStatusCase() loginType { }, wantErr: true, err: resultwrapper.ErrUnauthorized, - init: func(mock sqlmock.Sqlmock) *gomonkey.Patches { + init: func() *gomonkey.Patches { // mock FindUserByUserName with the proper password, and active state return gomonkey.ApplyFunc(daos.FindUserByUserName, func(username string, ctx context.Context) (*models.User, error) { @@ -147,7 +146,7 @@ func errorFromConfigCase() loginType { }, wantErr: true, err: fmt.Errorf(ErrorMsgFromConfig), - init: func(mock sqlmock.Sqlmock) *gomonkey.Patches { + init: func() *gomonkey.Patches { return gomonkey.ApplyFunc(daos.FindUserByUserName, func(username string, ctx context.Context) (*models.User, error) { user := testutls.MockUser() @@ -171,7 +170,7 @@ func errorWhileGeneratingToken() loginType { }, wantErr: true, err: resultwrapper.ErrUnauthorized, - init: func(mock sqlmock.Sqlmock) *gomonkey.Patches { + init: func() *gomonkey.Patches { tg := jwt.Service{} return gomonkey.ApplyFunc(daos.FindUserByUserName, func(username string, ctx context.Context) (*models.User, error) { @@ -200,7 +199,7 @@ func errorUpdateUserCase() loginType { }, wantErr: true, err: err, - init: func(mock sqlmock.Sqlmock) *gomonkey.Patches { + init: func() *gomonkey.Patches { tg := jwt.Service{} sec := secure.Service{} return gomonkey.ApplyFunc(daos.FindUserByUserName, @@ -243,7 +242,7 @@ func loginSuccessCase() loginType { Token: jwtToken, RefreshToken: TestToken, }, - init: func(mock sqlmock.Sqlmock) *gomonkey.Patches { + init: func() *gomonkey.Patches { tg := jwt.Service{} sec := secure.Service{} return gomonkey.ApplyFunc(daos.FindUserByUserName, @@ -284,7 +283,7 @@ func errorWhileCreatingJWTService() loginType { }, wantErr: true, err: err, - init: func(mock sqlmock.Sqlmock) *gomonkey.Patches { + init: func() *gomonkey.Patches { return gomonkey.ApplyFunc(daos.FindUserByUserName, func(username string, ctx context.Context) (*models.User, error) { user := testutls.MockUser() @@ -320,9 +319,8 @@ func TestLogin( t.Run( tt.name, func(t *testing.T) { - mock, cleanup, _ := testutls.SetupMockDB(t) - defer cleanup() - patch := tt.init(mock) + _, cleanup, _ := testutls.SetupMockDB(t) + patch := tt.init() c := context.Background() // Call the login mutation with the given arguments and check the response and error against the expected values response, err := resolver1.Mutation().Login(c, tt.req.UserName, tt.req.Password) @@ -336,6 +334,7 @@ func TestLogin( assert.Equal(t, tt.wantErr, err != nil) } patch.Reset() + cleanup() }, ) } @@ -351,7 +350,7 @@ type changePasswordType struct { req changeReq wantResp *fm.ChangePasswordResponse wantErr bool - init func(mock sqlmock.Sqlmock) *gomonkey.Patches + init func() *gomonkey.Patches } func changePasswordErrorFindingUserCase() changePasswordType { @@ -362,7 +361,7 @@ func changePasswordErrorFindingUserCase() changePasswordType { NewPassword: NewPassword, }, wantErr: true, - init: func(mock sqlmock.Sqlmock) *gomonkey.Patches { + init: func() *gomonkey.Patches { return gomonkey.ApplyFunc(daos.FindUserByUserName, func(username string, ctx context.Context) (*models.User, error) { return nil, fmt.Errorf(ErrorMsgFindingUser) @@ -378,7 +377,7 @@ func changePasswordErrorPasswordValidationcase() changePasswordType { NewPassword: NewPassword, }, wantErr: true, - init: func(mock sqlmock.Sqlmock) *gomonkey.Patches { + init: func() *gomonkey.Patches { tg := jwt.Service{} return gomonkey.ApplyMethod(reflect.TypeOf(tg), "GenerateToken", func(jwt.Service, *models.User) (string, error) { @@ -396,7 +395,7 @@ func changePasswordErrorInsecurePasswordCase() changePasswordType { NewPassword: testutls.MockEmail, }, wantErr: true, - init: func(mock sqlmock.Sqlmock) *gomonkey.Patches { + init: func() *gomonkey.Patches { // mock FindUserByUserName with the proper password, and active state return gomonkey.ApplyFunc(daos.FindUserByID, func(userID int, ctx context.Context) (*models.User, error) { @@ -417,7 +416,7 @@ func changePasswordErrorUpdateUserCase() changePasswordType { NewPassword: NewPassword, }, wantErr: true, - init: func(mock sqlmock.Sqlmock) *gomonkey.Patches { + init: func() *gomonkey.Patches { return gomonkey.ApplyFunc(daos.FindUserByID, func(userID int, ctx context.Context) (*models.User, error) { user := testutls.MockUser() @@ -440,7 +439,7 @@ func changePasswordErrorFromConfigCase() changePasswordType { NewPassword: testutls.MockEmail, }, wantErr: true, - init: func(mock sqlmock.Sqlmock) *gomonkey.Patches { + init: func() *gomonkey.Patches { return gomonkey.ApplyFunc(config.Load, func() (*config.Configuration, error) { return nil, fmt.Errorf("error in loading config") }) @@ -459,7 +458,7 @@ func changePasswordSuccessCase() changePasswordType { Ok: true, }, wantErr: false, - init: func(mock sqlmock.Sqlmock) *gomonkey.Patches { + init: func() *gomonkey.Patches { sec := secure.Service{} return gomonkey.ApplyFunc(config.Load, func() (*config.Configuration, error) { return nil, nil @@ -502,9 +501,8 @@ func TestChangePassword( tt.name, func(t *testing.T) { // Handle the case where there is an error while loading the configuration - mock, cleanup, _ := testutls.SetupMockDB(t) - defer cleanup() - tt.init(mock) + _, cleanup, _ := testutls.SetupMockDB(t) + patches := tt.init() // Set up the context with the mock user c := context.Background() ctx := context.WithValue(c, testutls.UserKey, testutls.MockUser()) @@ -517,6 +515,8 @@ func TestChangePassword( } // Assert that the expected error value matches the actual error value assert.Equal(t, tt.wantErr, err != nil) + cleanup() + patches.Reset() }, ) } @@ -650,6 +650,7 @@ func TestRefreshToken(t *testing.T) { t.Run( tt.name, func(t *testing.T) { + _, cleanup, _ := testutls.SetupMockDB(t) // Handle the case where authentication token is invalid patches := tt.init() // Set up the context with the mock user @@ -669,6 +670,7 @@ func TestRefreshToken(t *testing.T) { assert.Equal(t, true, strings.Contains(err.Error(), tt.err.Error())) } patches.Reset() + cleanup() }, ) } From 72e2ea02703b09823ba73170ce2e74329f0dd417 Mon Sep 17 00:00:00 2001 From: HIMANSHU Date: Wed, 3 Apr 2024 18:25:34 +0530 Subject: [PATCH 32/39] login neater tests comment resolbe --- resolver/auth_mutations.resolvers_test.go | 151 +++++++++++++++------- 1 file changed, 104 insertions(+), 47 deletions(-) diff --git a/resolver/auth_mutations.resolvers_test.go b/resolver/auth_mutations.resolvers_test.go index 56c20c86..5dafa918 100644 --- a/resolver/auth_mutations.resolvers_test.go +++ b/resolver/auth_mutations.resolvers_test.go @@ -7,6 +7,7 @@ import ( "reflect" "strings" "testing" + "time" "github.com/volatiletech/null/v8" @@ -42,7 +43,7 @@ const ( ErrorMsgFromConfig = "error in loading config" ErrorMsginvalidToken = "error from FindByToken" ErrorMsgFindingUser = "error in finding the user" - ErrorMsgFromJwt = "error in creating auth service " + ErrorMsgFromJwt = "error in creating auth service" ErrorMsgfromUpdateUser = "error while updating user" ErrorMsgPasswordValidation = "username or password does not exist " TestPasswordHash = "$2a$10$dS5vK8hHmG5" @@ -103,14 +104,21 @@ func errorPasswordValidationCase() loginType { err: fmt.Errorf(ErrorMsgPasswordValidation), init: func() *gomonkey.Patches { tg := jwt.Service{} - return gomonkey.ApplyFunc(daos.FindUserByUserName, + sec := secure.Service{} + return gomonkey.ApplyFunc(service.Secure, func(cfg *config.Configuration) secure.Service { + return sec + }).ApplyFunc(service.JWT, func(cfg *config.Configuration) (jwt.Service, error) { + return tg, nil + }).ApplyFunc(config.Load, func() (*config.Configuration, error) { + return &config.Configuration{}, nil + }).ApplyFunc(daos.FindUserByUserName, func(username string, ctx context.Context) (*models.User, error) { user := testutls.MockUser() user.Password = null.StringFrom(OldPasswordHash) user.Active = null.BoolFrom(false) return user, nil }).ApplyFunc(tg.GenerateToken, func(u *models.User) (string, error) { - return "", nil + return "", fmt.Errorf(ErrorMsgPasswordValidation) }) }, } @@ -126,14 +134,26 @@ func errorActiveStatusCase() loginType { wantErr: true, err: resultwrapper.ErrUnauthorized, init: func() *gomonkey.Patches { + tg := jwt.Service{} + sec := secure.Service{} + // mock FindUserByUserName with the proper password, and active state - return gomonkey.ApplyFunc(daos.FindUserByUserName, + return gomonkey.ApplyFunc(config.Load, func() (*config.Configuration, error) { + return nil, nil + }). + ApplyFunc(service.Secure, func(cfg *config.Configuration) secure.Service { + return sec + }).ApplyFunc(service.JWT, func(cfg *config.Configuration) (jwt.Service, error) { + return tg, nil + }).ApplyFunc(daos.FindUserByUserName, func(username string, ctx context.Context) (*models.User, error) { user := testutls.MockUser() user.Password = null.StringFrom(OldPasswordHash) user.Active = null.BoolFrom(false) return user, nil - }) + }).ApplyFunc(tg.GenerateToken, func(u *models.User) (string, error) { + return "", nil + }) }, } } @@ -169,23 +189,28 @@ func errorWhileGeneratingToken() loginType { Password: OldPassword, }, wantErr: true, - err: resultwrapper.ErrUnauthorized, + err: fmt.Errorf(ErrorMsgFromJwt), init: func() *gomonkey.Patches { tg := jwt.Service{} - return gomonkey.ApplyFunc(daos.FindUserByUserName, + sec := secure.Service{} + return gomonkey.ApplyFunc(config.Load, func() (*config.Configuration, error) { + return nil, nil + }).ApplyMethod(reflect.TypeOf(tg), "GenerateToken", + func(jwt.Service, *models.User) (string, error) { + return "", nil + }).ApplyFunc(service.Secure, func(cfg *config.Configuration) secure.Service { + return sec + }).ApplyFunc(daos.FindUserByUserName, func(username string, ctx context.Context) (*models.User, error) { user := testutls.MockUser() - user.Password = null.StringFrom(OldPasswordHash) + user.Password = null.StringFrom(OldPassword) user.Active = null.BoolFrom(true) return user, nil - }). - ApplyFunc(service.JWT, func(cfg *config.Configuration) (jwt.Service, error) { - return tg, nil - }). - ApplyMethod(reflect.TypeOf(tg), "GenerateToken", - func(jwt.Service, *models.User) (string, error) { - return "", fmt.Errorf(ErrorMsgFromJwt) - }) + }).ApplyMethod(reflect.TypeOf(sec), "HashMatchesPassword", func(sec secure.Service, hash string, password string) bool { + return true + }).ApplyFunc(service.JWT, func(cfg *config.Configuration) (jwt.Service, error) { + return tg, fmt.Errorf(ErrorMsgFromJwt) + }) }, } } @@ -202,31 +227,39 @@ func errorUpdateUserCase() loginType { init: func() *gomonkey.Patches { tg := jwt.Service{} sec := secure.Service{} - return gomonkey.ApplyFunc(daos.FindUserByUserName, + return gomonkey.ApplyFunc(service.JWT, func(cfg *config.Configuration) (jwt.Service, error) { + return tg, nil + }).ApplyFunc(daos.FindUserByUserName, func(username string, ctx context.Context) (*models.User, error) { user := testutls.MockUser() user.Password = null.StringFrom(OldPasswordHash) user.Active = null.BoolFrom(true) return user, nil }). - ApplyFunc(service.JWT, func(cfg *config.Configuration) (jwt.Service, error) { - return tg, nil - }). ApplyFunc(service.Secure, func(cfg *config.Configuration) secure.Service { return sec }). ApplyMethod(reflect.TypeOf(tg), "GenerateToken", func(jwt.Service, *models.User) (string, error) { return "", nil - }). + }).ApplyMethod(reflect.TypeOf(sec), "HashMatchesPassword", + func(sec secure.Service, hash string, password string) bool { + return true + }). + ApplyFunc(config.Load, func() (*config.Configuration, error) { + return nil, nil + }). ApplyMethod(reflect.TypeOf(sec), "Token", func(secure.Service, string) string { - return "refreshToken" + return "" }). ApplyFunc(daos.UpdateUser, func(u models.User, ctx context.Context) (models.User, error) { return models.User{}, err - }) + }).ApplyMethod(reflect.TypeOf(sec), "Token", + func(secure.Service, string) string { + return TestToken + }) }, } } @@ -269,7 +302,9 @@ func loginSuccessCase() loginType { ApplyFunc(daos.UpdateUser, func(u models.User, ctx context.Context) (models.User, error) { return *testutls.MockUser(), nil - }) + }).ApplyFunc(config.Load, func() (*config.Configuration, error) { + return nil, nil + }) }, } } @@ -284,7 +319,12 @@ func errorWhileCreatingJWTService() loginType { wantErr: true, err: err, init: func() *gomonkey.Patches { - return gomonkey.ApplyFunc(daos.FindUserByUserName, + sec := secure.Service{} + return gomonkey.ApplyFunc(config.Load, func() (*config.Configuration, error) { + return nil, nil + }).ApplyFunc(service.Secure, func(cfg *config.Configuration) secure.Service { + return sec + }).ApplyFunc(daos.FindUserByUserName, func(username string, ctx context.Context) (*models.User, error) { user := testutls.MockUser() user.Password = null.StringFrom(OldPasswordHash) @@ -299,12 +339,12 @@ func errorWhileCreatingJWTService() loginType { } func loadLoginTestCases() []loginType { return []loginType{ + errorWhileGeneratingToken(), errorFindingUserCase(), errorFromConfigCase(), errorPasswordValidationCase(), errorActiveStatusCase(), errorWhileCreatingJWTService(), - errorWhileGeneratingToken(), errorUpdateUserCase(), loginSuccessCase(), } @@ -319,8 +359,8 @@ func TestLogin( t.Run( tt.name, func(t *testing.T) { - _, cleanup, _ := testutls.SetupMockDB(t) patch := tt.init() + time.Sleep(time.Duration(10000000)) c := context.Background() // Call the login mutation with the given arguments and check the response and error against the expected values response, err := resolver1.Mutation().Login(c, tt.req.UserName, tt.req.Password) @@ -333,8 +373,9 @@ func TestLogin( assert.Equal(t, true, strings.Contains(err.Error(), tt.err.Error())) assert.Equal(t, tt.wantErr, err != nil) } - patch.Reset() - cleanup() + if patch != nil { + patch.Reset() + } }, ) } @@ -362,8 +403,8 @@ func changePasswordErrorFindingUserCase() changePasswordType { }, wantErr: true, init: func() *gomonkey.Patches { - return gomonkey.ApplyFunc(daos.FindUserByUserName, - func(username string, ctx context.Context) (*models.User, error) { + return gomonkey.ApplyFunc(daos.FindUserByID, + func(userID int, ctx context.Context) (*models.User, error) { return nil, fmt.Errorf(ErrorMsgFindingUser) }) }, @@ -378,10 +419,14 @@ func changePasswordErrorPasswordValidationcase() changePasswordType { }, wantErr: true, init: func() *gomonkey.Patches { - tg := jwt.Service{} - return gomonkey.ApplyMethod(reflect.TypeOf(tg), "GenerateToken", - func(jwt.Service, *models.User) (string, error) { - return "", nil + // tg := jwt.Service{} + sec := secure.Service{} + return gomonkey.ApplyFunc(daos.FindUserByID, + func(userID int, ctx context.Context) (*models.User, error) { + return nil, fmt.Errorf(ErrorMsgFindingUser) + }).ApplyMethod(reflect.TypeOf(sec), "HashMatchesPassword", + func(sec secure.Service, hash string, password string) bool { + return false }) }, } @@ -396,13 +441,20 @@ func changePasswordErrorInsecurePasswordCase() changePasswordType { }, wantErr: true, init: func() *gomonkey.Patches { + sec := secure.Service{} // mock FindUserByUserName with the proper password, and active state return gomonkey.ApplyFunc(daos.FindUserByID, func(userID int, ctx context.Context) (*models.User, error) { user := testutls.MockUser() user.Password = null.StringFrom(OldPasswordHash) user.Active = null.BoolFrom(false) - return user, fmt.Errorf(ErrorInsecurePassword) + return user, nil + }).ApplyMethod(reflect.TypeOf(sec), "HashMatchesPassword", + func(sec secure.Service, hash string, password string) bool { + return true + }).ApplyMethod(reflect.TypeOf(sec), "Password", + func(sec secure.Service, pass string, inputs ...string) bool { + return false }) }, } @@ -442,7 +494,13 @@ func changePasswordErrorFromConfigCase() changePasswordType { init: func() *gomonkey.Patches { return gomonkey.ApplyFunc(config.Load, func() (*config.Configuration, error) { return nil, fmt.Errorf("error in loading config") - }) + }).ApplyFunc(daos.FindUserByID, + func(userID int, ctx context.Context) (*models.User, error) { + user := testutls.MockUser() + user.Password = null.StringFrom(OldPasswordHash) + user.Active = null.BoolFrom(false) + return user, nil + }) }, } } @@ -501,7 +559,6 @@ func TestChangePassword( tt.name, func(t *testing.T) { // Handle the case where there is an error while loading the configuration - _, cleanup, _ := testutls.SetupMockDB(t) patches := tt.init() // Set up the context with the mock user c := context.Background() @@ -515,8 +572,9 @@ func TestChangePassword( } // Assert that the expected error value matches the actual error value assert.Equal(t, tt.wantErr, err != nil) - cleanup() - patches.Reset() + if patches != nil { + patches.Reset() + } }, ) } @@ -577,7 +635,7 @@ func refereshTokenerrorWhileGeneratingToken() refereshTokenType { init: func() *gomonkey.Patches { tg := jwt.Service{} return gomonkey.ApplyFunc(config.Load, func() (*config.Configuration, error) { - return &config.Configuration{}, nil + return nil, nil }).ApplyFunc(service.JWT, func(cfg *config.Configuration) (jwt.Service, error) { return tg, fmt.Errorf(ErrorMsgFromJwt) }).ApplyFunc(daos.FindUserByToken, func(token string, ctx context.Context) (*models.User, error) { @@ -592,7 +650,7 @@ func refereshTokenErrorFromGenerateTokenCase() refereshTokenType { name: ErrorFromGenerateToken, req: ReqToken, wantErr: true, - err: resultwrapper.ErrUnauthorized, + err: fmt.Errorf(ErrorFromGenerateToken), init: func() *gomonkey.Patches { tg := jwt.Service{} return gomonkey.ApplyFunc(config.Load, func() (*config.Configuration, error) { @@ -601,7 +659,7 @@ func refereshTokenErrorFromGenerateTokenCase() refereshTokenType { return tg, nil }).ApplyMethod(reflect.TypeOf(tg), "GenerateToken", func(jwt.Service, *models.User) (string, error) { - return "", resultwrapper.ErrUnauthorized + return "", fmt.Errorf(ErrorFromGenerateToken) }).ApplyFunc(daos.FindUserByToken, func(token string, ctx context.Context) (*models.User, error) { return testutls.MockUser(), nil }) @@ -650,7 +708,6 @@ func TestRefreshToken(t *testing.T) { t.Run( tt.name, func(t *testing.T) { - _, cleanup, _ := testutls.SetupMockDB(t) // Handle the case where authentication token is invalid patches := tt.init() // Set up the context with the mock user @@ -665,12 +722,12 @@ func TestRefreshToken(t *testing.T) { // Assert that the expected response matches the actual response assert.Equal(t, tt.wantResp, response) } else { - fmt.Println(err.Error(), tt.err.Error(), strings.Contains(err.Error(), tt.err.Error())) // Assert that the expected error value matches the actual error value assert.Equal(t, true, strings.Contains(err.Error(), tt.err.Error())) } - patches.Reset() - cleanup() + if patches != nil { + patches.Reset() + } }, ) } From 63ce81bbf967cb9ba415414476b7b3bcfaed1121 Mon Sep 17 00:00:00 2001 From: HIMANSHU Date: Wed, 3 Apr 2024 19:18:51 +0530 Subject: [PATCH 33/39] create user neater tests --- resolver/user_mutations.resolvers_test.go | 51 +++++++++++++++++------ 1 file changed, 39 insertions(+), 12 deletions(-) diff --git a/resolver/user_mutations.resolvers_test.go b/resolver/user_mutations.resolvers_test.go index 77c39f46..dc889e1b 100644 --- a/resolver/user_mutations.resolvers_test.go +++ b/resolver/user_mutations.resolvers_test.go @@ -7,8 +7,10 @@ import ( "go-template/daos" fm "go-template/gqlmodels" "go-template/internal/config" + "go-template/internal/service" "go-template/models" "go-template/pkg/utl/convert" + "go-template/pkg/utl/secure" "go-template/pkg/utl/throttle" "go-template/resolver" "go-template/testutls" @@ -52,8 +54,13 @@ func errorFromCreateUserCase() createUserType { req: fm.UserCreateInput{}, wantErr: true, init: func() *gomonkey.Patches { + sec := secure.Service{} return gomonkey.ApplyFunc(daos.CreateUser, func(user models.User, ctx context.Context) (models.User, error) { - return *testutls.MockUser(), fmt.Errorf("") + return *testutls.MockUser(), fmt.Errorf("error") + }).ApplyFunc(service.Secure, func(cfg *config.Configuration) secure.Service { + return sec + }).ApplyFunc(throttle.Check, func(ctx context.Context, limit int, dur time.Duration) error { + return nil }) }, } @@ -110,8 +117,28 @@ func createUserSuccessCase() createUserType { }, wantErr: false, init: func() *gomonkey.Patches { + sec := secure.Service{} return gomonkey.ApplyFunc(daos.CreateUser, func(user models.User, ctx context.Context) (models.User, error) { - return *testutls.MockUser(), nil + return models.User{ + ID: testutls.MockUser().ID, + Email: testutls.MockUser().Email, + FirstName: testutls.MockUser().FirstName, + LastName: testutls.MockUser().LastName, + Username: testutls.MockUser().Username, + Mobile: testutls.MockUser().Mobile, + Address: testutls.MockUser().Address, + Active: testutls.MockUser().Active, + LastLogin: testutls.MockUser().LastLogin, + LastPasswordChange: testutls.MockUser().LastPasswordChange, + DeletedAt: testutls.MockUser().DeletedAt, + UpdatedAt: testutls.MockUser().UpdatedAt, + }, nil + }).ApplyFunc(throttle.Check, func(ctx context.Context, limit int, dur time.Duration) error { + return nil + }).ApplyFunc(config.Load, func() (*config.Configuration, error) { + return nil, nil + }).ApplyFunc(service.Secure, func(cfg *config.Configuration) secure.Service { + return sec }) }, } @@ -130,15 +157,16 @@ func TestCreateUser(t *testing.T) { resolver := resolver.Resolver{} for _, tt := range cases { t.Run(tt.name, func(t *testing.T) { - _, cleanup, _ := testutls.SetupMockDB(t) patch := tt.init() + time.Sleep(time.Duration(100000)) response, err := resolver.Mutation().CreateUser(context.Background(), tt.req) if tt.wantResp != nil { assert.Equal(t, tt.wantResp, response) } assert.Equal(t, tt.wantErr, err != nil) - patch.Reset() - cleanup() + if patch != nil { + patch.Reset() + } }) } } @@ -218,7 +246,6 @@ func TestUpdateUser( t.Run( tt.name, func(t *testing.T) { - _, cleanup, _ := testutls.SetupMockDB(t) patches := tt.init() c := context.Background() ctx := context.WithValue(c, testutls.UserKey, testutls.MockUser()) @@ -229,9 +256,9 @@ func TestUpdateUser( } else { assert.Equal(t, tt.wantErr, err != nil) } - - patches.Reset() - cleanup() + if patches != nil { + patches.Reset() + } }, ) } @@ -307,7 +334,6 @@ func TestDeleteUser( tt.name, func(t *testing.T) { patch := tt.init() - _, cleanup, _ := testutls.SetupMockDB(t) // get user by id c := context.Background() ctx := context.WithValue(c, testutls.UserKey, testutls.MockUser()) @@ -316,8 +342,9 @@ func TestDeleteUser( assert.Equal(t, tt.wantResp, response) } assert.Equal(t, tt.wantErr, err != nil) - patch.Reset() - cleanup() + if patch != nil { + patch.Reset() + } }, ) } From ed1a160439c5619872ab798f9fe2f2dd3300b6bf Mon Sep 17 00:00:00 2001 From: HIMANSHU Date: Wed, 3 Apr 2024 19:19:34 +0530 Subject: [PATCH 34/39] removed time --- resolver/auth_mutations.resolvers_test.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/resolver/auth_mutations.resolvers_test.go b/resolver/auth_mutations.resolvers_test.go index 5dafa918..158db45d 100644 --- a/resolver/auth_mutations.resolvers_test.go +++ b/resolver/auth_mutations.resolvers_test.go @@ -7,7 +7,6 @@ import ( "reflect" "strings" "testing" - "time" "github.com/volatiletech/null/v8" @@ -360,7 +359,6 @@ func TestLogin( tt.name, func(t *testing.T) { patch := tt.init() - time.Sleep(time.Duration(10000000)) c := context.Background() // Call the login mutation with the given arguments and check the response and error against the expected values response, err := resolver1.Mutation().Login(c, tt.req.UserName, tt.req.Password) From abdb617fa63312765c0e750c6758c29eb14deb94 Mon Sep 17 00:00:00 2001 From: HIMANSHU Date: Wed, 3 Apr 2024 20:26:44 +0530 Subject: [PATCH 35/39] usermutaion resolved --- resolver/user_mutations.resolvers_test.go | 141 +++++++++++++--------- 1 file changed, 87 insertions(+), 54 deletions(-) diff --git a/resolver/user_mutations.resolvers_test.go b/resolver/user_mutations.resolvers_test.go index dc889e1b..e984b32a 100644 --- a/resolver/user_mutations.resolvers_test.go +++ b/resolver/user_mutations.resolvers_test.go @@ -7,6 +7,7 @@ import ( "go-template/daos" fm "go-template/gqlmodels" "go-template/internal/config" + "go-template/internal/middleware/auth" "go-template/internal/service" "go-template/models" "go-template/pkg/utl/convert" @@ -179,63 +180,89 @@ type updateUserType struct { init func() *gomonkey.Patches } -func loadUpdateUserTestCases() []updateUserType { - return []updateUserType{ - { - name: ErrorFindingUser, - req: &fm.UserUpdateInput{}, - wantErr: true, - init: func() *gomonkey.Patches { - return gomonkey.ApplyFunc(daos.FindUserByID, func(userID int, ctx context.Context) (*models.User, error) { - return nil, fmt.Errorf("") - }) - }, +func updateUserErrorFindingUser() updateUserType { + return updateUserType{ + name: ErrorFindingUser, + req: &fm.UserUpdateInput{}, + wantErr: true, + init: func() *gomonkey.Patches { + return gomonkey.ApplyFunc(daos.FindUserByID, func(userID int, ctx context.Context) (*models.User, error) { + return nil, fmt.Errorf("") + }) }, - { - name: ErrorUpdateUser, - req: &fm.UserUpdateInput{ - FirstName: &testutls.MockUser().FirstName.String, - LastName: &testutls.MockUser().LastName.String, - Mobile: &testutls.MockUser().Mobile.String, - Address: &testutls.MockUser().Address.String, - }, - wantErr: true, - init: func() *gomonkey.Patches { - return gomonkey.ApplyFunc(daos.UpdateUser, - func(models.User, context.Context) (models.User, error) { - return *testutls.MockUser(), fmt.Errorf("error for update user") - }) - }, + } +} +func updateUserErrorUpdateUser() updateUserType { + return updateUserType{ + name: ErrorUpdateUser, + req: &fm.UserUpdateInput{ + FirstName: &testutls.MockUser().FirstName.String, + LastName: &testutls.MockUser().LastName.String, + Mobile: &testutls.MockUser().Mobile.String, + Address: &testutls.MockUser().Address.String, }, - { - name: SuccessCase, - req: &fm.UserUpdateInput{ - FirstName: &testutls.MockUser().FirstName.String, - LastName: &testutls.MockUser().LastName.String, - Mobile: &testutls.MockUser().Mobile.String, - Address: &testutls.MockUser().Address.String, - }, - wantResp: &fm.User{ - ID: "1", - FirstName: convert.NullDotStringToPointerString(testutls.MockUser().FirstName), - LastName: convert.NullDotStringToPointerString(testutls.MockUser().LastName), - Username: convert.NullDotStringToPointerString(testutls.MockUser().Username), - Mobile: convert.NullDotStringToPointerString(testutls.MockUser().Mobile), - Address: convert.NullDotStringToPointerString(testutls.MockUser().Address), - Email: convert.NullDotStringToPointerString(testutls.MockUser().Email), - Active: &testutls.MockUser().Active.Bool, - }, - wantErr: false, - init: func() *gomonkey.Patches { - return gomonkey.ApplyFunc(daos.FindUserByID, func(userID int, ctx context.Context) (*models.User, error) { - return testutls.MockUser(), nil - }).ApplyFunc(daos.UpdateUser, func(user models.User, ctx context.Context) (models.User, error) { - return *testutls.MockUser(), nil - }) - }, + wantErr: true, + init: func() *gomonkey.Patches { + return gomonkey.ApplyFunc(daos.UpdateUser, + func(models.User, context.Context) (models.User, error) { + return *testutls.MockUser(), fmt.Errorf("error for update user") + }).ApplyFunc(auth.UserIDFromContext, func(ctx context.Context) int { + return 0 + }).ApplyFunc(daos.FindUserByID, func(userID int, ctx context.Context) (*models.User, error) { + return &models.User{}, nil + }) }, } } +func updateUserSuccessCase() updateUserType { + return updateUserType{ + name: SuccessCase, + req: &fm.UserUpdateInput{ + FirstName: &testutls.MockUser().FirstName.String, + LastName: &testutls.MockUser().LastName.String, + Mobile: &testutls.MockUser().Mobile.String, + Address: &testutls.MockUser().Address.String, + }, + wantResp: &fm.User{ + ID: "1", + FirstName: convert.NullDotStringToPointerString(testutls.MockUser().FirstName), + LastName: convert.NullDotStringToPointerString(testutls.MockUser().LastName), + Username: convert.NullDotStringToPointerString(testutls.MockUser().Username), + Mobile: convert.NullDotStringToPointerString(testutls.MockUser().Mobile), + Address: convert.NullDotStringToPointerString(testutls.MockUser().Address), + Email: convert.NullDotStringToPointerString(testutls.MockUser().Email), + Active: &testutls.MockUser().Active.Bool, + }, + wantErr: false, + init: func() *gomonkey.Patches { + return gomonkey.ApplyFunc(daos.FindUserByID, func(userID int, ctx context.Context) (*models.User, error) { + return testutls.MockUser(), nil + }).ApplyFunc(daos.UpdateUser, func(user models.User, ctx context.Context) (models.User, error) { + return *testutls.MockUser(), nil + }).ApplyFunc(auth.UserIDFromContext, func(ctx context.Context) int { + return 0 + }).ApplyFunc(daos.FindUserByID, func(userID int, ctx context.Context) (*models.User, error) { + return &models.User{ + ID: 1, + FirstName: testutls.MockUser().FirstName, + LastName: testutls.MockUser().LastName, + Username: testutls.MockUser().Username, + Mobile: testutls.MockUser().Mobile, + Address: testutls.MockUser().Address, + Email: testutls.MockUser().Email, + Active: testutls.MockUser().Active, + }, nil + }) + }, + } +} +func loadUpdateUserTestCases() []updateUserType { + return []updateUserType{ + updateUserErrorFindingUser(), + updateUserErrorUpdateUser(), + updateUserSuccessCase(), + } +} func TestUpdateUser( t *testing.T, @@ -293,7 +320,9 @@ func errorDeleteUserCase() deleteUserType { }).ApplyFunc(daos.DeleteUser, func(user models.User, ctx context.Context) (int64, error) { return 0, fmt.Errorf("error for delete user") - }) + }).ApplyFunc(daos.FindUserByID, func(userID int, ctx context.Context) (*models.User, error) { + return testutls.MockUser(), fmt.Errorf("") + }) }, } } @@ -311,7 +340,11 @@ func deleteUserSuccessCase() deleteUserType { }).ApplyFunc(daos.DeleteUser, func(user models.User, ctx context.Context) (int64, error) { return 0, nil - }) + }).ApplyFunc(daos.FindUserByID, func(userID int, ctx context.Context) (*models.User, error) { + return &models.User{ + ID: 0, + }, nil + }) }, } } From 9b1ea9eda18ba983168bbd780867109ecaedc23a Mon Sep 17 00:00:00 2001 From: HIMANSHU Date: Wed, 3 Apr 2024 21:47:09 +0530 Subject: [PATCH 36/39] nater api test --- pkg/api/api_test.go | 312 ++++++++++++++++++++++---------------------- 1 file changed, 154 insertions(+), 158 deletions(-) diff --git a/pkg/api/api_test.go b/pkg/api/api_test.go index 7b4397f4..03d69baf 100644 --- a/pkg/api/api_test.go +++ b/pkg/api/api_test.go @@ -6,6 +6,7 @@ import ( "database/sql" "fmt" "io" + "log" "net/http" "net/http/httptest" "os" @@ -24,7 +25,6 @@ import ( "github.com/99designs/gqlgen/graphql/handler" "github.com/99designs/gqlgen/graphql/handler/transport" "github.com/agiledragon/gomonkey/v2" - . "github.com/agiledragon/gomonkey/v2" "github.com/gorilla/websocket" "github.com/labstack/echo/v4" _ "github.com/lib/pq" @@ -37,7 +37,7 @@ var graphQLPathname = "/graphql" type args struct { cfg *config.Configuration } -type testCases struct { +type testStartServerType struct { name string args args wantErr bool @@ -47,201 +47,197 @@ type testCases struct { optionsTransportCalled bool multipartFormTransportCalled bool websocketTransportCalled bool + init func(e *echo.Echo, tt testStartServerType) *gomonkey.Patches } -func TestStart(t *testing.T) { - tests := initializeTestCases() - - patches := applyPatches() - defer patches.Reset() - - mockEchoServer, _ := prepareMocks() - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - setupMockFunctions() - - if hasTransportCalls(tt) { - checkTransportCalls(tt) - } else { - checkGraphQLServer(t, tt, mockEchoServer) - } - }) +func testStartServerSuccessCase() testStartServerType { + return testStartServerType{ + name: "Success", + args: args{ + cfg: testutls.MockConfig(), + }, + setDbCalled: true, + wantErr: false, + init: func(e *echo.Echo, tt testStartServerType) *gomonkey.Patches { + return gomonkey.ApplyFunc(os.Getenv, func(key string) (value string) { + if key == "JWT_SECRET" { + return testutls.MockJWTSecret + } + return "" + }).ApplyFunc(sql.Open, func(driverName string, dataSourceName string) (*sql.DB, error) { + fmt.Print("sql.Open called\n") + return nil, nil + }).ApplyFunc(server.Start, func(e *echo.Echo, cfg *server.Config) { + fmt.Print("Fake server started\n") + }).ApplyFunc(server.New, func() *echo.Echo { + return e + }).ApplyFunc(boil.SetDB, func(db boil.Executor) { + fmt.Print("boil.SetDB called\n", tt.setDbCalled) + }) + }, } } - -func initializeTestCases() []testCases { - return []testCases{ - { - name: "Success", - args: args{ - cfg: testutls.MockConfig(), - }, - wantErr: false, +func testWithTransportCase() testStartServerType { + return testStartServerType{ + name: "Test_AddTransport", + args: args{ + cfg: testutls.MockConfig(), }, - { - name: "Test_AddTransport", - args: args{ - cfg: testutls.MockConfig(), - }, - wantErr: false, - getTransportCalled: false, - postTransportCalled: false, - optionsTransportCalled: false, - multipartFormTransportCalled: false, - websocketTransportCalled: false, + wantErr: false, + getTransportCalled: true, + postTransportCalled: true, + optionsTransportCalled: true, + multipartFormTransportCalled: true, + websocketTransportCalled: true, + init: func(e *echo.Echo, tt testStartServerType) *gomonkey.Patches { + observers := map[string]chan *graphql.User{} + graphqlHandler := handler.New(graphql.NewExecutableSchema(graphql.Config{ + Resolvers: &resolver.Resolver{Observers: observers}, + })) + return gomonkey.ApplyFunc(os.Getenv, func(key string) (value string) { + if key == "JWT_SECRET" { + return testutls.MockJWTSecret + } + return "" + }).ApplyFunc(sql.Open, func(driverName string, dataSourceName string) (*sql.DB, error) { + fmt.Print("sql.Open called\n") + return nil, nil + }).ApplyFunc(server.Start, func(e *echo.Echo, cfg *server.Config) { + fmt.Print("Fake server started\n") + }).ApplyFunc(server.New, func() *echo.Echo { + return e + }).ApplyFunc(boil.SetDB, func(db boil.Executor) { + //mocking boil.setdb + }).ApplyMethod(reflect.TypeOf(graphqlHandler), "AddTransport", func(s *handler.Server, t graphql2.Transport) { + transportGET := transport.GET{} + transportMultipartForm := transport.MultipartForm{} + transportPOST := transport.POST{} + transportWebsocket := transport.Websocket{ + KeepAlivePingInterval: 10 * time.Second, + InitFunc: func(ctx context.Context, initPayload transport.InitPayload) (context.Context, error) { + return ctx, nil + }, + Upgrader: websocket.Upgrader{ + CheckOrigin: func(r *http.Request) bool { + return true + }, + }, + } + if t == transportGET { + tt.getTransportCalled = true + } + if t == transportMultipartForm { + tt.multipartFormTransportCalled = true + } + if t == transportPOST { + tt.postTransportCalled = true + } + if reflect.TypeOf(t) == reflect.TypeOf(transportWebsocket) { + tt.websocketTransportCalled = true + } + }) }, } } - -func applyPatches() *gomonkey.Patches { - return ApplyFunc(os.Getenv, mockGetenv). - ApplyFunc(sql.Open, mockSqlOpen). - ApplyFunc(server.Start, mockServerStart). - ApplyFunc(server.New, mockServerNew) -} - -func mockGetenv(key string) string { - if key == "JWT_SECRET" { - return testutls.MockJWTSecret +func loadTestStartCases() []testStartServerType { + return []testStartServerType{ + testStartServerSuccessCase(), + testWithTransportCase(), } - return "" } -func mockSqlOpen(driverName string, dataSourceName string) (*sql.DB, error) { - fmt.Print("sql.Open called\n") - return nil, nil -} - -func mockServerStart(e *echo.Echo, cfg *server.Config) { - fmt.Print("Fake server started\n") +func checkGraphQLGetResponse(e *echo.Echo) (*http.Response, error) { + _, res, err := testutls.SimpleMakeRequest(testutls.RequestParameters{ + E: e, + Pathname: "/playground", + HttpMethod: "GET", + IsGraphQL: false, + }) + return res, err } - -func mockServerNew() *echo.Echo { - return echo.New() +func checkGraphQLPostResponse(e *echo.Echo) (map[string]interface{}, error) { + res, err := testutls.MakeRequest(testutls.RequestParameters{ + E: e, + Pathname: graphQLPathname, + HttpMethod: "POST", + RequestBody: testutls.MockWhitelistedQuery, + IsGraphQL: false, + }) + return res, err } - -func prepareMocks() (*echo.Echo, *handler.Server) { +func TestStart(t *testing.T) { + tests := loadTestStartCases() e := echo.New() - graphqlHandler := handler.New(graphql.NewExecutableSchema(graphql.Config{ - Resolvers: &resolver.Resolver{Observers: make(map[string]chan *graphql.User)}, - })) - return e, graphqlHandler + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + runTest(t, tt, e) + }) + } } -func setupMockFunctions() { - ApplyFunc(boil.SetDB, mockSetDB) +func runTest(t *testing.T, tt testStartServerType, e *echo.Echo) { + patches := tt.init(e, tt) + if tt.getTransportCalled || tt.postTransportCalled || + tt.optionsTransportCalled || tt.multipartFormTransportCalled { + testWithTransportCalls(t, tt, e) + } else { + testWithoutTransportCalls(t, tt, e) + } + patches.Reset() } -func mockSetDB(db boil.Executor, tt testCases) { - fmt.Print("boil.SetDB called\n") - tt.setDbCalled = true +func testWithTransportCalls(t *testing.T, tt testStartServerType, e *echo.Echo) { + _, err := Start(tt.args.cfg) + assertError(t, err, tt.wantErr) + assert.Equal(t, tt.getTransportCalled, true) + assert.Equal(t, tt.multipartFormTransportCalled, true) + assert.Equal(t, tt.postTransportCalled, true) + assert.Equal(t, tt.websocketTransportCalled, true) } -func hasTransportCalls(tt testCases) bool { - return tt.getTransportCalled || tt.postTransportCalled || - tt.optionsTransportCalled || tt.multipartFormTransportCalled +func testWithoutTransportCalls(t *testing.T, tt testStartServerType, e *echo.Echo) { + _, err := Start(tt.args.cfg) + assertError(t, err, tt.wantErr) + checkGraphQLResponse(t, e) + checkWebsocketConnection(t, e) } -func checkTransportCalls(tt testCases) { - observers := map[string]chan *graphql.User{} - graphqlHandler := handler.New(graphql.NewExecutableSchema(graphql.Config{ - Resolvers: &resolver.Resolver{Observers: observers}, - })) - if tt.getTransportCalled || tt.postTransportCalled || - tt.optionsTransportCalled || tt.multipartFormTransportCalled { - ApplyMethod(reflect.TypeOf(graphqlHandler), "AddTransport", func(s *handler.Server, t graphql2.Transport) { - transportGET := transport.GET{} - transportMultipartForm := transport.MultipartForm{} - transportPOST := transport.POST{} - transportWebsocket := transport.Websocket{ - KeepAlivePingInterval: 10 * time.Second, - InitFunc: func(ctx context.Context, initPayload transport.InitPayload) (context.Context, error) { - return ctx, nil - }, - Upgrader: websocket.Upgrader{ - CheckOrigin: func(r *http.Request) bool { - return true - }, - }, - } - if t == transportGET { - tt.getTransportCalled = true - } - if t == transportMultipartForm { - tt.multipartFormTransportCalled = true - } - if t == transportPOST { - tt.postTransportCalled = true - } - if reflect.TypeOf(t) == reflect.TypeOf(transportWebsocket) { - tt.websocketTransportCalled = true - } - }) +func assertError(t *testing.T, err error, wantErr bool) { + if err != nil != wantErr { + t.Errorf("Error occurred = %v, wantErr %v", err, wantErr) } } -func checkGraphQLServer(t *testing.T, tt testCases, e *echo.Echo) { - jsonRes, err := testutls.MakeRequest(testutls.RequestParameters{ - E: e, - Pathname: graphQLPathname, - HttpMethod: "POST", - RequestBody: testutls.MockWhitelistedQuery, - IsGraphQL: false, - }) - if err != nil { - t.Fatalf("Failed to make request to GraphQL server: %v", err) - } - - // Assert that database was set - assert.True(t, tt.setDbCalled, "Expected database to be set") - - // Assert GraphQL schema is returned - assert.NotNil(t, jsonRes["data"].(map[string]interface{})["__schema"], - "Expected GraphQL schema to be returned") - // Simulate request to the GraphQL playground - _, res, err := testutls.SimpleMakeRequest(testutls.RequestParameters{ - E: e, - Pathname: "/playground", - HttpMethod: "GET", - IsGraphQL: false, - }) +func checkGraphQLResponse(t *testing.T, e *echo.Echo) { + jsonRes, err := checkGraphQLPostResponse(e) if err != nil { - t.Fatalf("Failed to make request to GraphQL playground: %v", err) + log.Fatal(err) } - - bodyBytes, err := io.ReadAll(res.Body) + assert.Equal(t, true, jsonRes["data"].(map[string]interface{})["__schema"] != nil, "Schema is nil") + res, err := checkGraphQLGetResponse(e) if err != nil { - t.Fatalf("Failed to read response body: %v", err) + log.Fatal(err) } + bodyBytes, _ := io.ReadAll(res.Body) + assert.Contains(t, string(bodyBytes), "GraphiQL.createFetcher", "Playground not found") +} - // Assert that GraphQL playground is returned - assert.Contains(t, string(bodyBytes), "GraphiQL.createFetcher", - "Expected GraphQL playground to be returned") - - // Connect to the WebSocket endpoint +func checkWebsocketConnection(t *testing.T, e *echo.Echo) { ts := httptest.NewServer(e) - defer ts.Close() u := "ws" + strings.TrimPrefix(ts.URL+graphQLPathname, "http") ws, _, err := websocket.DefaultDialer.Dial(u, nil) if err != nil { - t.Fatalf("Failed to connect to WebSocket: %v", err) + t.Fatalf("%v", err) } - defer ws.Close() - - // Send connection initiation message if err := ws.WriteMessage(websocket.TextMessage, []byte(`{"type":"connection_init","payload":`+ `{"authorization":"bearer ABC"}}`)); err != nil { - t.Fatalf("Failed to send connection initiation message: %v", err) + t.Fatalf("%v", err) } - - // Read response from WebSocket _, p, err := ws.ReadMessage() if err != nil { - t.Fatalf("Failed to read WebSocket message: %v", err) + t.Fatalf("%v", err) } - - // Assert that connection acknowledgement is received - assert.Contains(t, string(p), "{\"type\":\"connection_ack\"}\n", - "Expected connection acknowledgement from WebSocket") + assert.Contains(t, string(p), "{\"type\":\"connection_ack\"}\n", "Connection ack not found") + ts.Close() + ws.Close() } From 7549e74ff10b4524a1195649aa4a1c22a11f84cc Mon Sep 17 00:00:00 2001 From: HIMANSHU Date: Wed, 3 Apr 2024 21:58:41 +0530 Subject: [PATCH 37/39] nater api test --- pkg/api/api_test.go | 42 ++++++++++++++---------------------------- 1 file changed, 14 insertions(+), 28 deletions(-) diff --git a/pkg/api/api_test.go b/pkg/api/api_test.go index 03d69baf..eda4ed4e 100644 --- a/pkg/api/api_test.go +++ b/pkg/api/api_test.go @@ -170,25 +170,23 @@ func TestStart(t *testing.T) { e := echo.New() for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - runTest(t, tt, e) + patches := tt.init(e, tt) + if tt.getTransportCalled || tt.postTransportCalled || + tt.optionsTransportCalled || tt.multipartFormTransportCalled { + testWithTransportCalls(t, tt) + } else { + testWithoutTransportCalls(t, tt, e) + } + patches.Reset() }) } } -func runTest(t *testing.T, tt testStartServerType, e *echo.Echo) { - patches := tt.init(e, tt) - if tt.getTransportCalled || tt.postTransportCalled || - tt.optionsTransportCalled || tt.multipartFormTransportCalled { - testWithTransportCalls(t, tt, e) - } else { - testWithoutTransportCalls(t, tt, e) - } - patches.Reset() -} - -func testWithTransportCalls(t *testing.T, tt testStartServerType, e *echo.Echo) { +func testWithTransportCalls(t *testing.T, tt testStartServerType) { _, err := Start(tt.args.cfg) - assertError(t, err, tt.wantErr) + if err != nil != tt.wantErr { + assert.Equal(t, err, tt.wantErr) + } assert.Equal(t, tt.getTransportCalled, true) assert.Equal(t, tt.multipartFormTransportCalled, true) assert.Equal(t, tt.postTransportCalled, true) @@ -197,18 +195,9 @@ func testWithTransportCalls(t *testing.T, tt testStartServerType, e *echo.Echo) func testWithoutTransportCalls(t *testing.T, tt testStartServerType, e *echo.Echo) { _, err := Start(tt.args.cfg) - assertError(t, err, tt.wantErr) - checkGraphQLResponse(t, e) - checkWebsocketConnection(t, e) -} - -func assertError(t *testing.T, err error, wantErr bool) { - if err != nil != wantErr { - t.Errorf("Error occurred = %v, wantErr %v", err, wantErr) + if err != nil != tt.wantErr { + assert.Equal(t, err, tt.wantErr) } -} - -func checkGraphQLResponse(t *testing.T, e *echo.Echo) { jsonRes, err := checkGraphQLPostResponse(e) if err != nil { log.Fatal(err) @@ -220,9 +209,6 @@ func checkGraphQLResponse(t *testing.T, e *echo.Echo) { } bodyBytes, _ := io.ReadAll(res.Body) assert.Contains(t, string(bodyBytes), "GraphiQL.createFetcher", "Playground not found") -} - -func checkWebsocketConnection(t *testing.T, e *echo.Echo) { ts := httptest.NewServer(e) u := "ws" + strings.TrimPrefix(ts.URL+graphQLPathname, "http") ws, _, err := websocket.DefaultDialer.Dial(u, nil) From fbb1a8b1388e8476bcd2efc933e5854987f3c2cc Mon Sep 17 00:00:00 2001 From: HIMANSHU Date: Thu, 4 Apr 2024 20:41:41 +0530 Subject: [PATCH 38/39] Added linters v10 --- pkg/api/api_test.go | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/pkg/api/api_test.go b/pkg/api/api_test.go index eda4ed4e..89b551f3 100644 --- a/pkg/api/api_test.go +++ b/pkg/api/api_test.go @@ -40,6 +40,7 @@ type args struct { type testStartServerType struct { name string args args + want bool wantErr bool setDbCalled bool getTransportCalled bool @@ -84,6 +85,7 @@ func testWithTransportCase() testStartServerType { cfg: testutls.MockConfig(), }, wantErr: false, + want: true, getTransportCalled: true, postTransportCalled: true, optionsTransportCalled: true, @@ -177,7 +179,9 @@ func TestStart(t *testing.T) { } else { testWithoutTransportCalls(t, tt, e) } - patches.Reset() + if patches != nil { + patches.Reset() + } }) } } @@ -187,10 +191,10 @@ func testWithTransportCalls(t *testing.T, tt testStartServerType) { if err != nil != tt.wantErr { assert.Equal(t, err, tt.wantErr) } - assert.Equal(t, tt.getTransportCalled, true) - assert.Equal(t, tt.multipartFormTransportCalled, true) - assert.Equal(t, tt.postTransportCalled, true) - assert.Equal(t, tt.websocketTransportCalled, true) + assert.Equal(t, tt.getTransportCalled, tt.want) + assert.Equal(t, tt.multipartFormTransportCalled, tt.want) + assert.Equal(t, tt.postTransportCalled, tt.want) + assert.Equal(t, tt.websocketTransportCalled, tt.want) } func testWithoutTransportCalls(t *testing.T, tt testStartServerType, e *echo.Echo) { From 6f3eb371b6b4f90d67da7ff307d29a2f66fedef9 Mon Sep 17 00:00:00 2001 From: HIMANSHU Date: Fri, 5 Apr 2024 13:24:41 +0530 Subject: [PATCH 39/39] code rabbit comments resolved --- internal/config/env_test.go | 11 +- internal/middleware/auth/auth_test.go | 302 +++++++--------------- pkg/utl/resultwrapper/error_test.go | 5 +- pkg/utl/throttle/throttler_test.go | 2 + resolver/role_mutations.resolvers_test.go | 2 + 5 files changed, 114 insertions(+), 208 deletions(-) diff --git a/internal/config/env_test.go b/internal/config/env_test.go index 0134a0e3..601023f1 100644 --- a/internal/config/env_test.go +++ b/internal/config/env_test.go @@ -156,10 +156,13 @@ func TestFileName(t *testing.T) { } } +// keyValueArgs represents a key-value pair for environment variable setup type keyValueArgs struct { key string value string } + +// args holds the setup for environment variables and expected key-value pairs for assertions. type args struct { setEnv []keyValueArgs expectedKeyValues []keyValueArgs @@ -174,7 +177,7 @@ func TestLoadEnv(t *testing.T) { tests := getTestCases(username, host, dbname, password, port) for _, tt := range tests { setEnvironmentVariables(tt.args) - + defer clearEnvironmentVariables(tt.args) t.Run(tt.name, func(t *testing.T) { testLoadEnv(t, tt) }) @@ -348,3 +351,9 @@ func testLoadEnv(t *testing.T, tt struct { } } } + +func clearEnvironmentVariables(args args) { + for _, env := range args.setEnv { + os.Unsetenv(env.key) + } +} diff --git a/internal/middleware/auth/auth_test.go b/internal/middleware/auth/auth_test.go index 0319c25b..b1d9432d 100644 --- a/internal/middleware/auth/auth_test.go +++ b/internal/middleware/auth/auth_test.go @@ -41,16 +41,7 @@ func (s tokenParserMock) ParseToken(token string) (*jwt.Token, error) { var operationHandlerMock func(ctx context.Context) graphql2.ResponseHandler -func TestGraphQLMiddleware(t *testing.T) { - // Define test cases - cases := defineTestCases(t) - _, cleanup, _ := testutls.SetupMockDB(t) - defer cleanup() - // Run test cases - runTestCases(t, cases) -} - -func defineTestCases(t *testing.T) map[string]struct { +type testGraphQLMiddlewareType struct { wantStatus int header string signMethod string @@ -59,17 +50,36 @@ func defineTestCases(t *testing.T) map[string]struct { operationHandler func(ctx context.Context) graphql2.ResponseHandler tokenParser func(token string) (*jwt.Token, error) whiteListedQuery bool -} { - return map[string]struct { - wantStatus int - header string - signMethod string - err string - dbQueries []testutls.QueryData - operationHandler func(ctx context.Context) graphql2.ResponseHandler - tokenParser func(token string) (*jwt.Token, error) - whiteListedQuery bool - }{ + init func(t *testing.T, dbQueries []testutls.QueryData) sqlmock.Sqlmock +} + +func TestGraphQLMiddleware(t *testing.T) { + // Define test cases + cases := defineTestCases(t) + _, cleanup, _ := testutls.SetupMockDB(t) + defer cleanup() + for name, tt := range cases { + t.Run(name, func(t *testing.T) { + mock := tt.init(t, tt.dbQueries) + // Determine request query + requestQuery := testutls.MockQuery + if tt.whiteListedQuery { + requestQuery = testutls.MockWhitelistedQuery + } + + // Make request + makeRequest(t, requestQuery, tt) + + // Ensure mock expectations are met + if err := mock.ExpectationsWereMet(); err != nil { + t.Errorf("mock expectations were not met: %v", err) + } + }) + } +} + +func defineTestCases(t *testing.T) map[string]testGraphQLMiddlewareType { + return map[string]testGraphQLMiddlewareType{ "SuccessCase": defineSuccessCase(t), "Success__WhitelistedQuery": defineSuccessWhitelistedQuery(), "Failure__NoAuthorizationToken": defineFailureNoAuthorizationToken(), @@ -79,26 +89,8 @@ func defineTestCases(t *testing.T) map[string]struct { } } -func defineSuccessCase(t *testing.T) struct { - wantStatus int - header string - signMethod string - err string - dbQueries []testutls.QueryData - operationHandler func(ctx context.Context) graphql2.ResponseHandler - tokenParser func(token string) (*jwt.Token, error) - whiteListedQuery bool -} { - return struct { - wantStatus int - header string - signMethod string - err string - dbQueries []testutls.QueryData - operationHandler func(ctx context.Context) graphql2.ResponseHandler - tokenParser func(token string) (*jwt.Token, error) - whiteListedQuery bool - }{ +func defineSuccessCase(t *testing.T) testGraphQLMiddlewareType { + return testGraphQLMiddlewareType{ whiteListedQuery: false, header: "Bearer 123", wantStatus: http.StatusOK, @@ -120,29 +112,20 @@ func defineSuccessCase(t *testing.T) struct { ), }, }, + init: func(t *testing.T, dbQueries []testutls.QueryData) sqlmock.Sqlmock { + mock, _, _ := testutls.SetupMockDB(t) + for _, dbQuery := range dbQueries { + mock.ExpectQuery(regexp.QuoteMeta(dbQuery.Query)). + WithArgs(*dbQuery.Actions...). + WillReturnRows(dbQuery.DbResponse) + } + return mock + }, } } -func defineSuccessWhitelistedQuery() struct { - wantStatus int - header string - signMethod string - err string - dbQueries []testutls.QueryData - operationHandler func(ctx context.Context) graphql2.ResponseHandler - tokenParser func(token string) (*jwt.Token, error) - whiteListedQuery bool -} { - return struct { - wantStatus int - header string - signMethod string - err string - dbQueries []testutls.QueryData - operationHandler func(ctx context.Context) graphql2.ResponseHandler - tokenParser func(token string) (*jwt.Token, error) - whiteListedQuery bool - }{ +func defineSuccessWhitelistedQuery() testGraphQLMiddlewareType { + return testGraphQLMiddlewareType{ whiteListedQuery: true, header: "bearer 123", wantStatus: http.StatusOK, @@ -161,29 +144,20 @@ func defineSuccessWhitelistedQuery() struct { return handler }, dbQueries: []testutls.QueryData{}, + init: func(t *testing.T, dbQueries []testutls.QueryData) sqlmock.Sqlmock { + mock, _, _ := testutls.SetupMockDB(t) + for _, dbQuery := range dbQueries { + mock.ExpectQuery(regexp.QuoteMeta(dbQuery.Query)). + WithArgs(*dbQuery.Actions...). + WillReturnRows(dbQuery.DbResponse) + } + return mock + }, } } -func defineFailureNoAuthorizationToken() struct { - wantStatus int - header string - signMethod string - err string - dbQueries []testutls.QueryData - operationHandler func(ctx context.Context) graphql2.ResponseHandler - tokenParser func(token string) (*jwt.Token, error) - whiteListedQuery bool -} { - return struct { - wantStatus int - header string - signMethod string - err string - dbQueries []testutls.QueryData - operationHandler func(ctx context.Context) graphql2.ResponseHandler - tokenParser func(token string) (*jwt.Token, error) - whiteListedQuery bool - }{ +func defineFailureNoAuthorizationToken() testGraphQLMiddlewareType { + return testGraphQLMiddlewareType{ whiteListedQuery: false, header: "", wantStatus: http.StatusOK, @@ -195,29 +169,20 @@ func defineFailureNoAuthorizationToken() struct { return nil }, dbQueries: []testutls.QueryData{}, + init: func(t *testing.T, dbQueries []testutls.QueryData) sqlmock.Sqlmock { + mock, _, _ := testutls.SetupMockDB(t) + for _, dbQuery := range dbQueries { + mock.ExpectQuery(regexp.QuoteMeta(dbQuery.Query)). + WithArgs(*dbQuery.Actions...). + WillReturnRows(dbQuery.DbResponse) + } + return mock + }, } } -func defineFailureNotAnAdmin() struct { - wantStatus int - header string - signMethod string - err string - dbQueries []testutls.QueryData - operationHandler func(ctx context.Context) graphql2.ResponseHandler - tokenParser func(token string) (*jwt.Token, error) - whiteListedQuery bool -} { - return struct { - wantStatus int - header string - signMethod string - err string - dbQueries []testutls.QueryData - operationHandler func(ctx context.Context) graphql2.ResponseHandler - tokenParser func(token string) (*jwt.Token, error) - whiteListedQuery bool - }{ +func defineFailureNotAnAdmin() testGraphQLMiddlewareType { + return testGraphQLMiddlewareType{ whiteListedQuery: false, header: "bearer 123", wantStatus: http.StatusOK, @@ -229,29 +194,20 @@ func defineFailureNotAnAdmin() struct { return nil }, dbQueries: []testutls.QueryData{}, + init: func(t *testing.T, dbQueries []testutls.QueryData) sqlmock.Sqlmock { + mock, _, _ := testutls.SetupMockDB(t) + for _, dbQuery := range dbQueries { + mock.ExpectQuery(regexp.QuoteMeta(dbQuery.Query)). + WithArgs(*dbQuery.Actions...). + WillReturnRows(dbQuery.DbResponse) + } + return mock + }, } } -func defineFailureNoUserWithThatEmail() struct { - wantStatus int - header string - signMethod string - err string - dbQueries []testutls.QueryData - operationHandler func(ctx context.Context) graphql2.ResponseHandler - tokenParser func(token string) (*jwt.Token, error) - whiteListedQuery bool -} { - return struct { - wantStatus int - header string - signMethod string - err string - dbQueries []testutls.QueryData - operationHandler func(ctx context.Context) graphql2.ResponseHandler - tokenParser func(token string) (*jwt.Token, error) - whiteListedQuery bool - }{ +func defineFailureNoUserWithThatEmail() testGraphQLMiddlewareType { + return testGraphQLMiddlewareType{ whiteListedQuery: false, header: "bearer 123", wantStatus: http.StatusOK, @@ -263,29 +219,20 @@ func defineFailureNoUserWithThatEmail() struct { return nil }, dbQueries: []testutls.QueryData{}, + init: func(t *testing.T, dbQueries []testutls.QueryData) sqlmock.Sqlmock { + mock, _, _ := testutls.SetupMockDB(t) + for _, dbQuery := range dbQueries { + mock.ExpectQuery(regexp.QuoteMeta(dbQuery.Query)). + WithArgs(*dbQuery.Actions...). + WillReturnRows(dbQuery.DbResponse) + } + return mock + }, } } -func defineFailureInvalidAuthorizationToken() struct { - wantStatus int - header string - signMethod string - err string - dbQueries []testutls.QueryData - operationHandler func(ctx context.Context) graphql2.ResponseHandler - tokenParser func(token string) (*jwt.Token, error) - whiteListedQuery bool -} { - return struct { - wantStatus int - header string - signMethod string - err string - dbQueries []testutls.QueryData - operationHandler func(ctx context.Context) graphql2.ResponseHandler - tokenParser func(token string) (*jwt.Token, error) - whiteListedQuery bool - }{ +func defineFailureInvalidAuthorizationToken() testGraphQLMiddlewareType { + return testGraphQLMiddlewareType{ whiteListedQuery: false, header: "bearer 123", wantStatus: http.StatusOK, @@ -297,6 +244,15 @@ func defineFailureInvalidAuthorizationToken() struct { return nil }, dbQueries: []testutls.QueryData{}, + init: func(t *testing.T, dbQueries []testutls.QueryData) sqlmock.Sqlmock { + mock, _, _ := testutls.SetupMockDB(t) + for _, dbQuery := range dbQueries { + mock.ExpectQuery(regexp.QuoteMeta(dbQuery.Query)). + WithArgs(*dbQuery.Actions...). + WillReturnRows(dbQuery.DbResponse) + } + return mock + }, } } func defineOperationHandlerSuccessCase(t *testing.T) func(ctx context.Context) graphql2.ResponseHandler { @@ -318,69 +274,7 @@ func defineOperationHandlerSuccessCase(t *testing.T) func(ctx context.Context) g } } -func runTestCases(t *testing.T, cases map[string]struct { - wantStatus int - header string - signMethod string - err string - dbQueries []testutls.QueryData - operationHandler func(ctx context.Context) graphql2.ResponseHandler - tokenParser func(token string) (*jwt.Token, error) - whiteListedQuery bool -}) { - for name, tt := range cases { - t.Run(name, func(t *testing.T) { - runSingleTestCase(t, tt) - }) - } -} - -func runSingleTestCase(t *testing.T, tt struct { - wantStatus int - header string - signMethod string - err string - dbQueries []testutls.QueryData - operationHandler func(ctx context.Context) graphql2.ResponseHandler - tokenParser func(token string) (*jwt.Token, error) - whiteListedQuery bool -}) { - // Set up mock queries - mock := setupMockQueries(t, tt.dbQueries) - - // Determine request query - requestQuery := testutls.MockQuery - if tt.whiteListedQuery { - requestQuery = testutls.MockWhitelistedQuery - } - - // Make request - makeRequest(t, requestQuery, tt) - - // Ensure mock expectations are met - _ = mock.ExpectationsWereMet() -} - -func setupMockQueries(t *testing.T, dbQueries []testutls.QueryData) sqlmock.Sqlmock { - mock, _, _ := testutls.SetupMockDB(t) - for _, dbQuery := range dbQueries { - mock.ExpectQuery(regexp.QuoteMeta(dbQuery.Query)). - WithArgs(*dbQuery.Actions...). - WillReturnRows(dbQuery.DbResponse) - } - return mock -} - -func makeRequest(t *testing.T, requestQuery string, tt struct { - wantStatus int - header string - signMethod string - err string - dbQueries []testutls.QueryData - operationHandler func(ctx context.Context) graphql2.ResponseHandler - tokenParser func(token string) (*jwt.Token, error) - whiteListedQuery bool -}) { +func makeRequest(t *testing.T, requestQuery string, tt testGraphQLMiddlewareType) { // mock token parser to handle the different cases for when the token us valid, invalid, empty parseTokenMock = tt.tokenParser // mock operation handler, and assert different conditions diff --git a/pkg/utl/resultwrapper/error_test.go b/pkg/utl/resultwrapper/error_test.go index ba7e3332..f707b3cd 100644 --- a/pkg/utl/resultwrapper/error_test.go +++ b/pkg/utl/resultwrapper/error_test.go @@ -152,7 +152,6 @@ func TestInternalServerError(t *testing.T) { c echo.Context err error } - errorStr := ErrMsg tests := []struct { name string args args @@ -161,9 +160,9 @@ func TestInternalServerError(t *testing.T) { }{ { name: SuccessCase, - err: errorStr, + err: ErrMsg, args: args{ - err: fmt.Errorf(errorStr), + err: fmt.Errorf(ErrMsg), c: getContext()}, wantErr: true, }, diff --git a/pkg/utl/throttle/throttler_test.go b/pkg/utl/throttle/throttler_test.go index eca31cf2..10267ccf 100644 --- a/pkg/utl/throttle/throttler_test.go +++ b/pkg/utl/throttle/throttler_test.go @@ -129,6 +129,8 @@ func createFailureNotLocalRateLimitExceededTestCase(ctx context.Context) testCas wantErr: true, } } + +// Suggested refactoring to use table-driven tests func TestCheck(t *testing.T) { var ctx context.Context = testutls.MockCtx{} tests := CreateTestCases(ctx) diff --git a/resolver/role_mutations.resolvers_test.go b/resolver/role_mutations.resolvers_test.go index c4b43d57..732fc739 100644 --- a/resolver/role_mutations.resolvers_test.go +++ b/resolver/role_mutations.resolvers_test.go @@ -107,6 +107,8 @@ func successCase() createRoleType { } } +// Suggested refactoring to use table-driven tests and helper functions for common setup. + func errorFromCreateRoleCase() createRoleType { return createRoleType{ name: ErrorFromCreateRole,