From 42c147b15ae2e41942cdd4ba51f316e9f2c9739d Mon Sep 17 00:00:00 2001 From: HIMANSHU Date: Mon, 18 Mar 2024 12:40:59 +0530 Subject: [PATCH 1/5] tests- feat seprate pr --- resolver/author_mutation.resolvers_test.go | 320 +++++++++++++++++++++ 1 file changed, 320 insertions(+) create mode 100644 resolver/author_mutation.resolvers_test.go diff --git a/resolver/author_mutation.resolvers_test.go b/resolver/author_mutation.resolvers_test.go new file mode 100644 index 00000000..6b8173e1 --- /dev/null +++ b/resolver/author_mutation.resolvers_test.go @@ -0,0 +1,320 @@ +package resolver_test + +import ( + "context" + "database/sql/driver" + "fmt" + "go-template/daos" + fm "go-template/gqlmodels" + "go-template/internal/config" + "go-template/models" + "go-template/pkg/utl/convert" + "go-template/pkg/utl/throttle" + "go-template/resolver" + "go-template/testutls" + "log" + "regexp" + "testing" + "time" + + "github.com/agiledragon/gomonkey/v2" + "github.com/joho/godotenv" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/stretchr/testify/assert" + "github.com/volatiletech/sqlboiler/v4/boil" +) + +const ( + ErrorFromCreateAuthor = "Error Creating Author" + ErrorFindingAuthor = "Error Finding Author" + ErrorDeleteAuthor = "Error Delete Author" + ErrorUpdateAuthor = "Error Update Author" +) + +func TestCreateAuthor( + t *testing.T, +) { + cases := []struct { + name string + req fm.AuthorCreateInput + wantResp *fm.Author + wantErr bool + }{ + { + name: ErrorFromCreateAuthor, + req: fm.AuthorCreateInput{}, + wantErr: true, + }, + { + name: ErrorFromThrottleCheck, + req: fm.AuthorCreateInput{}, + wantErr: true, + }, + { + name: ErrorFromConfig, + req: fm.AuthorCreateInput{}, + wantErr: true, + }, + { + name: SuccessCase, + req: fm.AuthorCreateInput{ + FirstName: testutls.MockAuthor().FirstName.String, + LastName: testutls.MockAuthor().LastName.String, + Email: testutls.MockAuthor().Email.String, + }, + wantResp: &fm.Author{ + ID: fmt.Sprint(testutls.MockAuthor().ID), + Email: convert.NullDotStringToPointerString(testutls.MockAuthor().Email), + FirstName: convert.NullDotStringToPointerString(testutls.MockAuthor().FirstName), + LastName: convert.NullDotStringToPointerString(testutls.MockAuthor().LastName), + DeletedAt: convert.NullDotTimeToPointerInt(testutls.MockAuthor().DeletedAt), + UpdatedAt: convert.NullDotTimeToPointerInt(testutls.MockAuthor().UpdatedAt), + }, + wantErr: false, + }, + } + + resolver1 := 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() + } + + 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) + + if tt.name == ErrorFromCreateAuthor { + // insert new Author + mock.ExpectQuery(regexp.QuoteMeta(`INSERT INTO "authors"`)). + WithArgs(). + WillReturnError(fmt.Errorf("")) + } + // insert new Author + rows := sqlmock.NewRows([]string{ + "id", + }). + AddRow( + testutls.MockAuthor().ID, + ) + mock.ExpectQuery(regexp.QuoteMeta(`INSERT INTO "authors"`)). + WithArgs( + testutls.MockAuthor().FirstName, + testutls.MockAuthor().LastName, + "", + testutls.MockAuthor().Email, + AnyTime{}, + AnyTime{}, + ). + WillReturnRows(rows) + + c := context.Background() + response, err := resolver1.Mutation(). + CreateAuthor(c, tt.req) + if tt.wantResp != nil { + assert.Equal(t, tt.wantResp, response) + } + assert.Equal(t, tt.wantErr, err != nil) + }, + ) + } +} + +func TestUpdateAuthor( + t *testing.T, +) { + cases := []struct { + name string + req *fm.AuthorUpdateInput + wantResp *fm.Author + wantErr bool + }{ + { + name: ErrorFindingAuthor, + req: &fm.AuthorUpdateInput{}, + wantErr: true, + }, + { + name: ErrorUpdateAuthor, + req: &fm.AuthorUpdateInput{ + FirstName: &testutls.MockAuthor().FirstName.String, + LastName: &testutls.MockAuthor().LastName.String, + Email: &testutls.MockAuthor().Email.String, + }, + wantErr: true, + }, + { + name: SuccessCase, + req: &fm.AuthorUpdateInput{ + FirstName: &testutls.MockAuthor().FirstName.String, + LastName: &testutls.MockAuthor().LastName.String, + Email: &testutls.MockAuthor().Email.String, + }, + wantResp: &fm.Author{ + ID: "0", + FirstName: &testutls.MockAuthor().FirstName.String, + LastName: &testutls.MockAuthor().LastName.String, + Email: &testutls.MockAuthor().LastName.String, + }, + wantErr: false, + }, + } + + resolver1 := resolver.Resolver{} + for _, tt := range cases { + t.Run( + tt.name, + func(t *testing.T) { + + if tt.name == ErrorUpdateAuthor { + + patch := gomonkey.ApplyFunc(daos.UpdateAuthor, + func(author models.Author, ctx context.Context) (models.Author, error) { + return author, fmt.Errorf("error for update Author") + }) + 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) + + if tt.name == ErrorFindingAuthor { + mock.ExpectQuery(regexp.QuoteMeta(`UPDATE "authors"`)).WithArgs().WillReturnError(fmt.Errorf("")) + } + + rows := sqlmock.NewRows([]string{"first_name"}).AddRow(testutls.MockAuthor().FirstName) + mock.ExpectQuery(regexp.QuoteMeta(`select * from "authors"`)).WithArgs(0).WillReturnRows(rows) + + // update Authors with new information + result := driver.Result(driver.RowsAffected(1)) + mock.ExpectExec(regexp.QuoteMeta(`UPDATE "authors"`)).WillReturnResult(result) + + c := context.Background() + ctx := context.WithValue(c, testutls.AuthorKey, testutls.MockAuthor()) + response, err := resolver1.Mutation().UpdateAuthor(ctx, *tt.req) + if tt.wantResp != nil && + response != nil { + assert.Equal(t, tt.wantResp, response) + } + assert.Equal(t, tt.wantErr, err != nil) + }, + ) + } +} + +func TestDeleteAuthor( + t *testing.T, +) { + cases := []struct { + name string + wantResp *fm.AuthorDeletePayload + wantErr bool + }{ + { + name: ErrorFindingAuthor, + wantErr: true, + }, + { + name: ErrorDeleteAuthor, + wantErr: true, + }, + { + name: SuccessCase, + wantResp: &fm.AuthorDeletePayload{ + ID: "0", + }, + wantErr: false, + }, + } + + resolver1 := resolver.Resolver{} + for _, tt := range cases { + t.Run( + tt.name, + func(t *testing.T) { + if tt.name == ErrorDeleteAuthor { + + patch := gomonkey.ApplyFunc(daos.DeleteAuthor, + func(author models.Author, ctx context.Context) (int64, error) { + return 0, fmt.Errorf("error for delete author") + }) + 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) + + if tt.name == ErrorFindingAuthor { + mock.ExpectQuery(regexp.QuoteMeta(`select * from "authors" where "id"=$1`)). + WithArgs(). + WillReturnError(fmt.Errorf("")) + } + // get Author by id + rows := sqlmock.NewRows([]string{"id"}). + AddRow(1) + mock.ExpectQuery(regexp.QuoteMeta(`select * from "authors" where "id"=$1`)). + WithArgs(). + WillReturnRows(rows) + // delete Author + result := driver.Result(driver.RowsAffected(1)) + mock.ExpectExec(regexp.QuoteMeta(`DELETE FROM "authors" WHERE "id"=$1`)). + WillReturnResult(result) + + c := context.Background() + ctx := context.WithValue(c, testutls.AuthorKey, testutls.MockAuthor()) + response, err := resolver1.Mutation(). + DeleteAuthor(ctx, fm.AuthorDeleteInput{ID: "1"}) + if tt.wantResp != nil { + assert.Equal(t, tt.wantResp, response) + } + assert.Equal(t, tt.wantErr, err != nil) + }, + ) + } +} From ff223e717d49e5fa7121edfe2fe0f308f4574a08 Mon Sep 17 00:00:00 2001 From: HIMANSHU Date: Mon, 18 Mar 2024 16:11:26 +0530 Subject: [PATCH 2/5] post mutation tests --- models/posts.go | 18 +- resolver/post_mutation_resolvers_test.go | 311 +++++++++++++++++++++++ testutls/main.go | 23 +- 3 files changed, 350 insertions(+), 2 deletions(-) create mode 100644 resolver/post_mutation_resolvers_test.go diff --git a/models/posts.go b/models/posts.go index 001896b2..e6c210e0 100644 --- a/models/posts.go +++ b/models/posts.go @@ -19,6 +19,8 @@ import ( "github.com/volatiletech/sqlboiler/v4/queries/qm" "github.com/volatiletech/sqlboiler/v4/queries/qmhelper" "github.com/volatiletech/strmangle" + "github.com/volatiletech/null/v8" + ) // Post is an object representing the database table. @@ -26,7 +28,9 @@ type Post struct { ID int `boil:"id" json:"id" toml:"id" yaml:"id"` AuthorID int `boil:"author_id" json:"author_id" toml:"author_id" yaml:"author_id"` Post string `boil:"post" json:"post" toml:"post" yaml:"post"` - + CreatedAt null.Time `boil:"created_at" json:"created_at,omitempty" toml:"created_at" yaml:"created_at,omitempty"` + UpdatedAt null.Time `boil:"updated_at" json:"updated_at,omitempty" toml:"updated_at" yaml:"updated_at,omitempty"` + DeletedAt null.Time `boil:"deleted_at" json:"deleted_at,omitempty" toml:"deleted_at" yaml:"deleted_at,omitempty"` R *postR `boil:"-" json:"-" toml:"-" yaml:"-"` L postL `boil:"-" json:"-" toml:"-" yaml:"-"` } @@ -35,20 +39,32 @@ var PostColumns = struct { ID string AuthorID string Post string + CreatedAt string + UpdatedAt string + DeletedAt string }{ ID: "id", AuthorID: "author_id", Post: "post", + CreatedAt: "created_at", + UpdatedAt: "updated_at", + DeletedAt: "deleted_at", } var PostTableColumns = struct { ID string AuthorID string Post string + CreatedAt string + UpdatedAt string + DeletedAt string }{ ID: "posts.id", AuthorID: "posts.author_id", Post: "posts.post", + CreatedAt: "posts.created_at", + UpdatedAt: "posts.updated_at", + DeletedAt: "posts.deleted_at", } // Generated where diff --git a/resolver/post_mutation_resolvers_test.go b/resolver/post_mutation_resolvers_test.go new file mode 100644 index 00000000..57ce1afd --- /dev/null +++ b/resolver/post_mutation_resolvers_test.go @@ -0,0 +1,311 @@ +package resolver_test + +import ( + "context" + "database/sql/driver" + "fmt" + "go-template/daos" + fm "go-template/gqlmodels" + "go-template/internal/config" + "go-template/models" + "go-template/pkg/utl/convert" + "go-template/pkg/utl/throttle" + "go-template/resolver" + "go-template/testutls" + "log" + "regexp" + "strconv" + "testing" + "time" + + "github.com/agiledragon/gomonkey/v2" + "github.com/joho/godotenv" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/stretchr/testify/assert" + "github.com/volatiletech/sqlboiler/v4/boil" +) + +const ( + ErrorFromCreatePost = "Error Creating Post" + ErrorFindingPost = "Error Finding Post" + ErrorDeletePost = "Error Delete Post" + ErrorUpdatePost = "Error Update Post" +) + +func TestCreatePost( + t *testing.T, +) { + cases := []struct { + name string + req fm.PostCreateInput + wantResp *fm.Post + wantErr bool + }{ + { + name: ErrorFromCreatePost, + req: fm.PostCreateInput{}, + wantErr: true, + }, + { + name: ErrorFromThrottleCheck, + req: fm.PostCreateInput{}, + wantErr: true, + }, + { + name: ErrorFromConfig, + req: fm.PostCreateInput{}, + wantErr: true, + }, + { + name: SuccessCase, + req: fm.PostCreateInput{ + Post: testutls.MockPost().Post, + AuthorID: strconv.Itoa(testutls.MockPost().AuthorID), + }, + wantResp: &fm.Post{ + ID: fmt.Sprint(testutls.MockPost().ID), + Post: convert.StringToPointerString(testutls.MockPost().Post), + Author: &fm.Author{ID: strconv.Itoa(testutls.MockPost().AuthorID)}, + DeletedAt: convert.NullDotTimeToPointerInt(testutls.MockAuthor().DeletedAt), + UpdatedAt: convert.NullDotTimeToPointerInt(testutls.MockAuthor().UpdatedAt), + }, + wantErr: false, + }, + } + + resolver1 := 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() + } + + 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) + + if tt.name == ErrorFromCreatePost { + // insert new Author + mock.ExpectQuery(regexp.QuoteMeta(`INSERT INTO "posts"`)). + WithArgs(). + WillReturnError(fmt.Errorf("")) + } + // insert new Author + rows := sqlmock.NewRows([]string{ + "id", + }). + AddRow( + testutls.MockPost().ID, + ) + mock.ExpectQuery(regexp.QuoteMeta(`INSERT INTO "posts"`)). + WithArgs( + testutls.MockPost().Post, + testutls.MockPost().AuthorID, + "", + AnyTime{}, + AnyTime{}, + ). + WillReturnRows(rows) + + c := context.Background() + response, err := resolver1.Mutation(). + CreatePost(c, tt.req) + if tt.wantResp != nil { + assert.Equal(t, tt.wantResp, response) + } + assert.Equal(t, tt.wantErr, err != nil) + }, + ) + } +} + +func TestUpdatePost( + t *testing.T, +) { + cases := []struct { + name string + req *fm.PostUpdateInput + wantResp *fm.Post + wantErr bool + }{ + { + name: ErrorFindingPost, + req: &fm.PostUpdateInput{}, + wantErr: true, + }, + { + name: ErrorUpdatePost, + req: &fm.PostUpdateInput{ + Post: &testutls.MockPost().Post, + }, + wantErr: true, + }, + { + name: SuccessCase, + req: &fm.PostUpdateInput{ + Post: &testutls.MockPost().Post, + }, + wantResp: &fm.Post{ + ID: "0", + Post: &testutls.MockPost().Post, + }, + wantErr: false, + }, + } + + resolver1 := resolver.Resolver{} + for _, tt := range cases { + t.Run( + tt.name, + func(t *testing.T) { + + if tt.name == ErrorUpdatePost { + + patch := gomonkey.ApplyFunc(daos.UpdatePost, + func(post models.Post, ctx context.Context) (models.Post, error) { + return post, fmt.Errorf("error for update Author") + }) + 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) + + if tt.name == ErrorFindingPost { + mock.ExpectQuery(regexp.QuoteMeta(`UPDATE "posts"`)).WithArgs().WillReturnError(fmt.Errorf("")) + } + + rows := sqlmock.NewRows([]string{"post"}).AddRow(testutls.MockPost().Post) + mock.ExpectQuery(regexp.QuoteMeta(`select * from "posts"`)).WithArgs(0).WillReturnRows(rows) + + // update Authors with new information + result := driver.Result(driver.RowsAffected(1)) + mock.ExpectExec(regexp.QuoteMeta(`UPDATE "posts"`)).WillReturnResult(result) + + c := context.Background() + ctx := context.WithValue(c, testutls.PostKey, testutls.MockPost()) + response, err := resolver1.Mutation().UpdatePost(ctx, *tt.req) + if tt.wantResp != nil && + response != nil { + assert.Equal(t, tt.wantResp, response) + } + assert.Equal(t, tt.wantErr, err != nil) + }, + ) + } +} + +func TestDeletePost( + t *testing.T, +) { + cases := []struct { + name string + wantResp *fm.PostDeletePayload + wantErr bool + }{ + { + name: ErrorFindingPost, + wantErr: true, + }, + { + name: ErrorDeletePost, + wantErr: true, + }, + { + name: SuccessCase, + wantResp: &fm.PostDeletePayload{ + ID: "0", + }, + wantErr: false, + }, + } + + resolver1 := resolver.Resolver{} + for _, tt := range cases { + t.Run( + tt.name, + func(t *testing.T) { + if tt.name == ErrorDeletePost { + + patch := gomonkey.ApplyFunc(daos.DeletePost, + func(post models.Post, ctx context.Context) (int64, error) { + return 0, fmt.Errorf("error for delete post") + }) + 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) + + if tt.name == ErrorFindingAuthor { + mock.ExpectQuery(regexp.QuoteMeta(`select * from "posts" where "id"=$1`)). + WithArgs(). + WillReturnError(fmt.Errorf("")) + } + // get Author by id + rows := sqlmock.NewRows([]string{"id"}). + AddRow(1) + mock.ExpectQuery(regexp.QuoteMeta(`select * from "posts" where "id"=$1`)). + WithArgs(). + WillReturnRows(rows) + // delete Author + result := driver.Result(driver.RowsAffected(1)) + mock.ExpectExec(regexp.QuoteMeta(`DELETE FROM "posts" WHERE "id"=$1`)). + WillReturnResult(result) + + c := context.Background() + ctx := context.WithValue(c, testutls.PostKey, testutls.MockPost()) + response, err := resolver1.Mutation(). + DeletePost(ctx, fm.PostDeleteInput{ID: "1"}) + if tt.wantResp != nil { + assert.Equal(t, tt.wantResp, response) + } + assert.Equal(t, tt.wantErr, err != nil) + }, + ) + } +} diff --git a/testutls/main.go b/testutls/main.go index 0ea0d1ec..71abd7ed 100644 --- a/testutls/main.go +++ b/testutls/main.go @@ -22,8 +22,9 @@ import ( type key string var ( - UserKey key = "user" + UserKey key = "user" AuthorKey key = "author" + PostKey key = "posts" ) const ( @@ -41,6 +42,7 @@ var MockCount = int64(1) var MockJWTSecret = "1234567890123456789012345678901234567890123456789012345678901234567890" var MockQuery = `{"query":"query users { users { users { id } } }","variables":{}}"` var MockWhitelistedQuery = `{"query":"query Schema { __schema { queryType { kind } } }","variables":{}}"` +var MockPostContent = "Hello Test Post" func MockUser() *models.User { return &models.User{ @@ -188,3 +190,22 @@ func MockAuthors() []*models.Author { } } + +func MockPost() *models.Post { + return &models.Post{ + ID: MockID, + Post: MockPostContent, + AuthorID: MockID, + DeletedAt: null.NewTime(time.Time{}, false), + UpdatedAt: null.NewTime(time.Time{}, false), + } +} +func MockPosts() []*models.Post { + return []*models.Post{ + { + Post: MockPostContent, + AuthorID: MockID, + }, + } + +} From b2aeeb6d514b902f780951e0584be21748bcb61f Mon Sep 17 00:00:00 2001 From: HIMANSHU Date: Mon, 18 Mar 2024 16:25:42 +0530 Subject: [PATCH 3/5] author queries tests --- resolver/author_queries_resolvers_test.go | 133 ++++++++++++++++++++++ 1 file changed, 133 insertions(+) create mode 100644 resolver/author_queries_resolvers_test.go diff --git a/resolver/author_queries_resolvers_test.go b/resolver/author_queries_resolvers_test.go new file mode 100644 index 00000000..8a0fa551 --- /dev/null +++ b/resolver/author_queries_resolvers_test.go @@ -0,0 +1,133 @@ +package resolver_test + +import ( + "context" + "fmt" + "regexp" + "testing" + + fm "go-template/gqlmodels" + "go-template/models" + "go-template/resolver" + "go-template/testutls" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/joho/godotenv" + "github.com/volatiletech/sqlboiler/v4/boil" + + "github.com/stretchr/testify/assert" +) + +func TestAuthors( + t *testing.T, +) { + cases := []struct { + name string + pagination *fm.AuthorPagination + wantResp []*models.Author + wantErr bool + }{ + { + name: ErrorFindingAuthor, + wantErr: true, + }, + { + name: "pagination", + wantErr: false, + pagination: &fm.AuthorPagination{ + Limit: 1, + Page: 1, + }, + wantResp: testutls.MockAuthors(), + }, + { + name: SuccessCase, + wantErr: false, + wantResp: testutls.MockAuthors(), + }, + } + + // Create a new instance of the resolver. + 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", + ) + 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) + }() + boil.SetDB(db) + + //fail on finding user case + if tt.name == ErrorFindingUser { + mock.ExpectQuery(regexp.QuoteMeta(`select * from "authors" where "id"=$1`)). + WithArgs(). + WillReturnError(fmt.Errorf("")) + } + + if tt.name == "pagination" { + rows := sqlmock. + NewRows([]string{"id", "first_name", "last_name", "email"}). + AddRow(testutls.MockID, "First", "Last", testutls.MockEmail) + mock.ExpectQuery(regexp.QuoteMeta(`SELECT "authors".* FROM "authors" LIMIT 1 OFFSET 1;`)).WithArgs().WillReturnRows(rows) + + rowCount := sqlmock.NewRows([]string{"count"}). + AddRow(1) + mock.ExpectQuery(regexp.QuoteMeta(`SELECT COUNT(*) FROM "authors" LIMIT 1;`)). + WithArgs(). + WillReturnRows(rowCount) + + } else { + rows := sqlmock. + NewRows([]string{"id", "email", "first_name", "last_name"}). + AddRow(testutls.MockID, testutls.MockEmail, "First", "Last") + mock.ExpectQuery(regexp.QuoteMeta(`SELECT "authors".* FROM "authors";`)).WithArgs().WillReturnRows(rows) + + rowCount := sqlmock.NewRows([]string{"count"}). + AddRow(1) + mock.ExpectQuery(regexp.QuoteMeta(`SELECT COUNT(*) FROM "authors";`)). + 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.AuthorKey, testutls.MockAuthor()) + + // Query for users using the resolver and get the response and error. + response, err := resolver1.Query(). + Authors(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.Authors)) + + } + // Check if the error matches the expected error value. + assert.Equal(t, tt.wantErr, err != nil) + }, + ) + } +} From 0ec8a84cbe5d4faec204f2772007a9b9d20d7cd6 Mon Sep 17 00:00:00 2001 From: HIMANSHU Date: Mon, 18 Mar 2024 17:25:09 +0530 Subject: [PATCH 4/5] post queries tests --- resolver/post_queries_resolvers_test.go | 137 ++++++++++++++++++++++++ 1 file changed, 137 insertions(+) create mode 100644 resolver/post_queries_resolvers_test.go diff --git a/resolver/post_queries_resolvers_test.go b/resolver/post_queries_resolvers_test.go new file mode 100644 index 00000000..904b4964 --- /dev/null +++ b/resolver/post_queries_resolvers_test.go @@ -0,0 +1,137 @@ +package resolver_test + +import ( + "context" + "fmt" + "regexp" + "testing" + + fm "go-template/gqlmodels" + "go-template/models" + "go-template/resolver" + "go-template/testutls" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/joho/godotenv" + "github.com/volatiletech/sqlboiler/v4/boil" + + "github.com/stretchr/testify/assert" +) + +func TestPosts( + t *testing.T, +) { + cases := []struct { + name string + pagination *fm.PostsPagination + queryInput *fm.PostQueryInput + wantResp []*models.Post + wantErr bool + }{ + { + name: ErrorFindingPost, + wantErr: true, + }, + { + name: "pagination", + wantErr: false, + pagination: &fm.PostsPagination{ + Limit: 1, + Page: 1, + }, + queryInput: &fm.PostQueryInput{ + AuthorID: testutls.MockPost().AuthorID, + }, + wantResp: testutls.MockPosts(), + }, + { + name: SuccessCase, + wantErr: false, + wantResp: testutls.MockPosts(), + }, + } + + // Create a new instance of the resolver. + 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", + ) + 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) + }() + boil.SetDB(db) + + //fail on finding user case + if tt.name == ErrorFindingUser { + mock.ExpectQuery(regexp.QuoteMeta(`select * from "posts" where "id"=$1`)). + WithArgs(). + WillReturnError(fmt.Errorf("")) + } + + if tt.name == "pagination" { + rows := sqlmock. + NewRows([]string{"author_id", "post"}). + AddRow(testutls.MockID, "Hello post") + mock.ExpectQuery(regexp.QuoteMeta(`SELECT "posts".* FROM "posts" where author_id= 1 LIMIT 1 OFFSET 1;`)).WithArgs().WillReturnRows(rows) + + rowCount := sqlmock.NewRows([]string{"count"}). + AddRow(1) + mock.ExpectQuery(regexp.QuoteMeta(`SELECT COUNT(*) FROM "posts" where author_id=1 LIMIT 1;`)). + WithArgs(). + WillReturnRows(rowCount) + + } else { + rows := sqlmock. + NewRows([]string{"id", "author_id", "post"}). + AddRow(testutls.MockID, testutls.MockAuthor().ID, "Hello Post") + mock.ExpectQuery(regexp.QuoteMeta(`SELECT "posts".* FROM "posts";`)).WithArgs().WillReturnRows(rows) + + rowCount := sqlmock.NewRows([]string{"count"}). + AddRow(1) + mock.ExpectQuery(regexp.QuoteMeta(`SELECT COUNT(*) FROM "posts";`)). + 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.PostKey, testutls.MockPost()) + + // Query for users using the resolver and get the response and error. + response, err := resolver1.Query(). + Posts(ctx, tt.queryInput, 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.Posts)) + + } + // Check if the error matches the expected error value. + assert.Equal(t, tt.wantErr, err != nil) + }, + ) + } +} From 23d810431178d770266d0a3c037fd8a7f46a490d Mon Sep 17 00:00:00 2001 From: HIMANSHU Date: Mon, 18 Mar 2024 18:03:25 +0530 Subject: [PATCH 5/5] author daos tests --- daos/authors_test.go | 286 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 286 insertions(+) create mode 100644 daos/authors_test.go diff --git a/daos/authors_test.go b/daos/authors_test.go new file mode 100644 index 00000000..2dde436d --- /dev/null +++ b/daos/authors_test.go @@ -0,0 +1,286 @@ +package daos_test + +import ( + "context" + "database/sql/driver" + "fmt" + "go-template/daos" + "go-template/internal/config" + "go-template/models" + "go-template/pkg/utl/convert" + "go-template/testutls" + "log" + "regexp" + "strconv" + "testing" + + "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" +) + +const ErrorFindingAuthor = "Fail on finding Author" + +func TestCreateAuthorTx(t *testing.T) { + + cases := []struct { + name string + req models.Author + err error + }{ + { + name: "Passing author type value", + req: models.Author{ + ID: testutls.MockAuthor().ID, + Email: testutls.MockAuthor().Email, + FirstName: testutls.MockAuthor().FirstName, + LastName: testutls.MockAuthor().LastName, + }, + err: nil, + }, + } + + for _, tt := range cases { + // Inject mock instance into boil. + + 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) + + rows := sqlmock.NewRows([]string{ + "first_name", + "last_name", + "email", + "deleted_at", + }).AddRow( + testutls.MockAuthor().FirstName, + testutls.MockAuthor().LastName, + testutls.MockAuthor().Email, + testutls.MockAuthor().DeletedAt, + ) + mock.ExpectQuery(regexp.QuoteMeta(`INSERT INTO "authors"`)). + WithArgs(). + WillReturnRows(rows) + + t.Run(tt.name, func(t *testing.T) { + _, err := daos.CreateAuthor(tt.req, context.Background()) + if err != nil { + assert.Equal(t, true, tt.err != nil) + } else { + assert.Equal(t, err, tt.err) + } + }) + } +} + +func TestFindAuthorByID(t *testing.T) { + + cases := []struct { + name string + req int + err error + }{ + { + name: "Passing a author ID", + req: 1, + 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) + } + // 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 "authors" where "id"=$1`)). + WithArgs(). + WillReturnRows(rows) + + t.Run(tt.name, func(t *testing.T) { + _, err := daos.FindAuthorWithId(strconv.Itoa(tt.req), context.Background()) + assert.Equal(t, err, tt.err) + + }) + } +} + +func TestUpdateAuthorTx(t *testing.T) { + + cases := []struct { + name string + req models.Author + err error + }{ + { + name: "Passing author type value", + req: models.Author{}, + 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) + } + // 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 "authors" `)). + WillReturnResult(result) + + t.Run(tt.name, func(t *testing.T) { + _, err := daos.UpdateAuthor(tt.req, context.Background()) + assert.Equal(t, err, tt.err) + }) + } +} + +func TestDeleteAuthor(t *testing.T) { + + cases := []struct { + name string + req models.Author + err error + }{ + { + name: "Passing author type value", + req: models.Author{}, + 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) + } + // 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 "authors" WHERE "id"=$1`)). + WillReturnResult(result) + + t.Run(tt.name, func(t *testing.T) { + _, err := daos.DeleteAuthor(tt.req, context.Background()) + assert.Equal(t, err, tt.err) + }) + } +} + +func TestFindAllAuthorsWithCount(t *testing.T) { + + oldDB := boil.GetDB() + err := config.LoadEnvWithFilePrefix(convert.StringToPointerString("./../")) + if err != nil { + log.Fatal(err) + } + mock, db, _ := testutls.SetupMockDB(t) + + cases := []struct { + name string + err error + dbQueries []testutls.QueryData + }{ + { + name: "Failed to find all authors with count", + err: fmt.Errorf("sql: no rows in sql"), + }, + { + name: "Successfully find all authors with count", + err: nil, + dbQueries: []testutls.QueryData{ + { + Query: `SELECT "authors".* FROM "authors";`, + DbResponse: sqlmock.NewRows([]string{"id", "email", "first_name", "last_name"}).AddRow( + testutls.MockID, + testutls.MockEmail, + testutls.MockAuthor().FirstName, + testutls.MockAuthor().LastName), + }, + { + Query: `SELECT COUNT(*) FROM "authors";`, + DbResponse: sqlmock.NewRows([]string{"count"}).AddRow(testutls.MockCount), + }, + }, + }, + } + + for _, tt := range cases { + + if tt.err != nil { + mock.ExpectQuery(regexp.QuoteMeta(`SELECT "authors".* FROM "authors";`)). + 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.FindAllAuthorsWithCount([]qm.QueryMod{}, context.Background()) + if err != nil { + assert.Equal(t, true, tt.err != nil) + } else { + assert.Equal(t, err, tt.err) + assert.Equal(t, testutls.MockCount, c) + assert.Equal(t, res[0].Email, null.StringFrom(testutls.MockEmail)) + assert.Equal(t, res[0].ID, int(testutls.MockID)) + } + }) + } + boil.SetDB(oldDB) + db.Close() +}