package handler import ( "context" "database/sql" "net/http/httptest" "testing" "github.com/brianvoe/gofakeit/v6" "github.com/gofiber/fiber/v2" "github.com/gojuno/minimock/v3" "github.com/stretchr/testify/assert" "git.dmitriygnatenko.ru/dima/dmitriygnatenko-v2/internal/helpers/test" "git.dmitriygnatenko.ru/dima/dmitriygnatenko-v2/internal/models" "git.dmitriygnatenko.ru/dima/dmitriygnatenko-v2/internal/services/handler/mocks" ) func TestArticleHandler(t *testing.T) { t.Parallel() type req struct { method string route string } var ( articleID = gofakeit.Uint64() articleURL = gofakeit.Word() publishTime = gofakeit.Date() internalErr = gofakeit.Error() article = models.Article{ ID: articleID, URL: articleURL, Title: gofakeit.Phrase(), Text: gofakeit.Phrase(), PublishTime: publishTime, PreviewText: sql.NullString{Valid: true, String: gofakeit.Phrase()}, Image: sql.NullString{Valid: true, String: gofakeit.URL()}, IsActive: true, Language: models.LangRu, } notActiveArticle = models.Article{ ID: articleID, URL: articleURL, Title: gofakeit.Phrase(), Text: gofakeit.Phrase(), PublishTime: publishTime, PreviewText: sql.NullString{Valid: true, String: gofakeit.Phrase()}, Image: sql.NullString{Valid: true, String: gofakeit.URL()}, Language: models.LangRu, } _ = internalErr _ = article _ = notActiveArticle tags = []models.Tag{ { ID: gofakeit.Uint64(), Tag: gofakeit.Word(), URL: gofakeit.Word(), }, { ID: gofakeit.Uint64(), Tag: gofakeit.Word(), URL: gofakeit.Word(), }, } _ = tags previewArticles = []models.ArticlePreview{ { ID: gofakeit.Uint64(), URL: gofakeit.URL(), Title: gofakeit.Phrase(), PublishTime: publishTime, PreviewText: sql.NullString{Valid: true, String: gofakeit.Phrase()}, Image: sql.NullString{Valid: true, String: gofakeit.URL()}, }, { ID: gofakeit.Uint64(), URL: gofakeit.URL(), Title: gofakeit.Phrase(), PublishTime: publishTime, PreviewText: sql.NullString{Valid: true, String: gofakeit.Phrase()}, Image: sql.NullString{Valid: true, String: gofakeit.URL()}, }, { ID: gofakeit.Uint64(), URL: gofakeit.URL(), Title: gofakeit.Phrase(), PublishTime: publishTime, PreviewText: sql.NullString{Valid: true, String: gofakeit.Phrase()}, Image: sql.NullString{Valid: true, String: gofakeit.URL()}, }, { ID: gofakeit.Uint64(), URL: gofakeit.URL(), Title: gofakeit.Phrase(), PublishTime: publishTime, PreviewText: sql.NullString{Valid: true, String: gofakeit.Phrase()}, Image: sql.NullString{Valid: true, String: gofakeit.URL()}, }, } _ = previewArticles ) tests := []struct { name string req req res int err error cacheMock func(mc *minimock.Controller) CacheService tagMock func(mc *minimock.Controller) TagRepository articleMock func(mc *minimock.Controller) ArticleRepository }{ // { // name: "positive case", // req: req{ // method: fiber.MethodGet, // route: "/article/" + articleURL, // }, // res: fiber.StatusOK, // err: nil, // cacheMock: func(mc *minimock.Controller) CacheService { // mock := mocks.NewCacheServiceMock(mc) // mock.GetMock.Return(nil, false) // mock.SetMock.Return() // return mock // }, // tagMock: func(mc *minimock.Controller) TagRepository { // mock := mocks.NewTagRepositoryMock(mc) // mock.GetAllUsedMock.Return(tags, nil) // return mock // }, // articleMock: func(mc *minimock.Controller) ArticleRepository { // mock := mocks.NewArticleRepositoryMock(mc) // // mock.GetByURLMock.Inspect(func(ctx context.Context, url string, lang models.Language) { // assert.Equal(mc, articleURL, url) // assert.Equal(mc, models.LangRu, lang) // }).Return(&article, nil) // // mock.GetAllPreviewMock.Return(previewArticles, nil) // // return mock // }, // }, { name: "negative case - article not found", req: req{ method: fiber.MethodGet, route: "/article/" + articleURL, }, res: fiber.StatusNotFound, err: nil, cacheMock: func(mc *minimock.Controller) CacheService { mock := mocks.NewCacheServiceMock(mc) mock.GetMock.Return(nil, false) return mock }, tagMock: func(mc *minimock.Controller) TagRepository { mock := mocks.NewTagRepositoryMock(mc) return mock }, articleMock: func(mc *minimock.Controller) ArticleRepository { mock := mocks.NewArticleRepositoryMock(mc) mock.GetByURLMock.Inspect(func(ctx context.Context, url string, lang models.Language) { assert.Equal(mc, articleURL, url) assert.Equal(mc, models.LangRu, lang) }).Return(nil, sql.ErrNoRows) return mock }, }, // { // name: "negative case - article repository error", // req: req{ // method: fiber.MethodGet, // route: "/article/" + articleURL, // }, // res: fiber.StatusInternalServerError, // err: nil, // cacheMock: func(mc *minimock.Controller) CacheService { // mock := mocks.NewCacheServiceMock(mc) // mock.GetMock.Return(nil, false) // return mock // }, // tagMock: func(mc *minimock.Controller) TagRepository { // return mocks.NewTagRepositoryMock(mc) // }, // articleMock: func(mc *minimock.Controller) ArticleRepository { // mock := mocks.NewArticleRepositoryMock(mc) // mock.GetByURLMock.Inspect(func(ctx context.Context, url string, lang models.Language) { // assert.Equal(mc, articleURL, url) // assert.Equal(mc, models.LangRu, lang) // }).Return(nil, internalErr) // // return mock // }, // }, // { // name: "negative case - article not active", // req: req{ // method: fiber.MethodGet, // route: "/article/" + articleURL, // }, // res: fiber.StatusNotFound, // err: nil, // cacheMock: func(mc *minimock.Controller) CacheService { // mock := mocks.NewCacheServiceMock(mc) // mock.GetMock.Return(nil, false) // return mock // }, // tagMock: func(mc *minimock.Controller) TagRepository { // return mocks.NewTagRepositoryMock(mc) // }, // articleMock: func(mc *minimock.Controller) ArticleRepository { // mock := mocks.NewArticleRepositoryMock(mc) // mock.GetByURLMock.Inspect(func(ctx context.Context, url string, lang models.Language) { // assert.Equal(mc, articleURL, url) // assert.Equal(mc, models.LangRu, lang) // }).Return(¬ActiveArticle, nil) // // return mock // }, // }, // { // name: "negative case - tags repository error", // req: req{ // method: fiber.MethodGet, // route: "/article/" + articleURL, // }, // res: fiber.StatusInternalServerError, // err: nil, // cacheMock: func(mc *minimock.Controller) CacheService { // mock := mocks.NewCacheServiceMock(mc) // // mock.GetMock.Return(nil, false) // // return mock // }, // tagMock: func(mc *minimock.Controller) TagRepository { // mock := mocks.NewTagRepositoryMock(mc) // mock.GetAllUsedMock.Return(nil, internalErr) // return mock // }, // articleMock: func(mc *minimock.Controller) ArticleRepository { // mock := mocks.NewArticleRepositoryMock(mc) // // mock.GetByURLMock.Inspect(func(ctx context.Context, url string, lang models.Language) { // assert.Equal(mc, articleURL, url) // assert.Equal(mc, models.LangRu, lang) // }).Return(&article, nil) // // return mock // }, // }, // { // name: "negative case - articles repository error", // req: req{ // method: fiber.MethodGet, // route: "/article/" + articleURL, // }, // res: fiber.StatusInternalServerError, // err: nil, // cacheMock: func(mc *minimock.Controller) CacheService { // mock := mocks.NewCacheServiceMock(mc) // mock.GetMock.Return(nil, false) // // return mock // }, // tagMock: func(mc *minimock.Controller) TagRepository { // mock := mocks.NewTagRepositoryMock(mc) // mock.GetAllUsedMock.Return(tags, nil) // // return mock // }, // articleMock: func(mc *minimock.Controller) ArticleRepository { // mock := mocks.NewArticleRepositoryMock(mc) // // mock.GetByURLMock.Inspect(func(ctx context.Context, url string, lang models.Language) { // assert.Equal(mc, articleURL, url) // assert.Equal(mc, models.LangRu, lang) // }).Return(&article, nil) // // mock.GetAllPreviewMock.Return(nil, internalErr) // // return mock // }, // }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() mc := minimock.NewController(t) fiberApp := fiber.New(test.GetFiberTestConfig()) fiberReq := httptest.NewRequest(tt.req.method, tt.req.route, nil) fiberApp.Get("/article/:article", ArticleHandler( tt.cacheMock(mc), tt.articleMock(mc), tt.tagMock(mc), )) fiberRes, fiberErr := fiberApp.Test(fiberReq) assert.Equal(t, tt.res, fiberRes.StatusCode) assert.Equal(t, tt.err, fiberErr) }) } }