article_test.go 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. package handler
  2. import (
  3. "context"
  4. "database/sql"
  5. "net/http/httptest"
  6. "testing"
  7. "github.com/brianvoe/gofakeit/v6"
  8. "github.com/gofiber/fiber/v2"
  9. "github.com/gojuno/minimock/v3"
  10. "github.com/stretchr/testify/assert"
  11. "git.dmitriygnatenko.ru/dima/dmitriygnatenko-v2/internal/helpers/test"
  12. "git.dmitriygnatenko.ru/dima/dmitriygnatenko-v2/internal/models"
  13. "git.dmitriygnatenko.ru/dima/dmitriygnatenko-v2/internal/services/handler/mocks"
  14. )
  15. func TestArticleHandler(t *testing.T) {
  16. t.Parallel()
  17. type req struct {
  18. method string
  19. route string
  20. }
  21. var (
  22. articleID = gofakeit.Uint64()
  23. articleURL = gofakeit.Word()
  24. publishTime = gofakeit.Date()
  25. internalErr = gofakeit.Error()
  26. language = models.LanguageID(gofakeit.Uint64())
  27. article = models.Article{
  28. ID: articleID,
  29. URL: articleURL,
  30. Title: gofakeit.Phrase(),
  31. Text: gofakeit.Phrase(),
  32. PublishTime: publishTime,
  33. PreviewText: sql.NullString{Valid: true, String: gofakeit.Phrase()},
  34. Image: gofakeit.URL(),
  35. Language: language,
  36. IsActive: true,
  37. }
  38. notActiveArticle = models.Article{
  39. ID: articleID,
  40. URL: articleURL,
  41. Title: gofakeit.Phrase(),
  42. Text: gofakeit.Phrase(),
  43. PublishTime: publishTime,
  44. PreviewText: sql.NullString{Valid: true, String: gofakeit.Phrase()},
  45. Image: gofakeit.URL(),
  46. Language: language,
  47. }
  48. tags = []models.Tag{
  49. {
  50. ID: gofakeit.Uint64(),
  51. Tag: gofakeit.Word(),
  52. URL: gofakeit.Word(),
  53. },
  54. {
  55. ID: gofakeit.Uint64(),
  56. Tag: gofakeit.Word(),
  57. URL: gofakeit.Word(),
  58. },
  59. }
  60. previewArticles = []models.ArticlePreview{
  61. {
  62. ID: gofakeit.Uint64(),
  63. URL: gofakeit.URL(),
  64. Title: gofakeit.Phrase(),
  65. PublishTime: publishTime,
  66. PreviewText: sql.NullString{Valid: true, String: gofakeit.Phrase()},
  67. Image: gofakeit.URL(),
  68. },
  69. {
  70. ID: gofakeit.Uint64(),
  71. URL: gofakeit.URL(),
  72. Title: gofakeit.Phrase(),
  73. PublishTime: publishTime,
  74. PreviewText: sql.NullString{Valid: true, String: gofakeit.Phrase()},
  75. Image: gofakeit.URL(),
  76. },
  77. {
  78. ID: gofakeit.Uint64(),
  79. URL: gofakeit.URL(),
  80. Title: gofakeit.Phrase(),
  81. PublishTime: publishTime,
  82. PreviewText: sql.NullString{Valid: true, String: gofakeit.Phrase()},
  83. Image: gofakeit.URL(),
  84. },
  85. {
  86. ID: gofakeit.Uint64(),
  87. URL: gofakeit.URL(),
  88. Title: gofakeit.Phrase(),
  89. PublishTime: publishTime,
  90. PreviewText: sql.NullString{Valid: true, String: gofakeit.Phrase()},
  91. Image: gofakeit.URL(),
  92. },
  93. }
  94. )
  95. tests := []struct {
  96. name string
  97. req req
  98. res int
  99. err error
  100. cacheMock func(mc *minimock.Controller) CacheService
  101. tagMock func(mc *minimock.Controller) TagRepository
  102. articleMock func(mc *minimock.Controller) ArticleRepository
  103. }{
  104. {
  105. name: "positive case",
  106. req: req{
  107. method: fiber.MethodGet,
  108. route: "/article/" + articleURL,
  109. },
  110. res: fiber.StatusOK,
  111. err: nil,
  112. cacheMock: func(mc *minimock.Controller) CacheService {
  113. mock := mocks.NewCacheServiceMock(mc)
  114. mock.GetMock.When(ArticleCacheKey+articleURL).Then(nil, false)
  115. mock.GetMock.When(RecentArticlesCacheKey).Then(nil, false)
  116. mock.GetMock.When(UsedTagsCacheKey).Then(nil, false)
  117. mock.SetMock.Return()
  118. return mock
  119. },
  120. tagMock: func(mc *minimock.Controller) TagRepository {
  121. mock := mocks.NewTagRepositoryMock(mc)
  122. mock.GetAllUsedMock.Return(tags, nil)
  123. return mock
  124. },
  125. articleMock: func(mc *minimock.Controller) ArticleRepository {
  126. mock := mocks.NewArticleRepositoryMock(mc)
  127. mock.GetByURLMock.Inspect(func(ctx context.Context, url string) {
  128. assert.Equal(mc, articleURL, url)
  129. }).Return(&article, nil)
  130. mock.GetAllPreviewMock.Return(previewArticles, nil)
  131. return mock
  132. },
  133. },
  134. {
  135. name: "negative case - article not found",
  136. req: req{
  137. method: fiber.MethodGet,
  138. route: "/article/" + articleURL,
  139. },
  140. res: fiber.StatusNotFound,
  141. err: nil,
  142. cacheMock: func(mc *minimock.Controller) CacheService {
  143. mock := mocks.NewCacheServiceMock(mc)
  144. mock.GetMock.Expect(ArticleCacheKey+articleURL).Return(nil, false)
  145. return mock
  146. },
  147. tagMock: func(mc *minimock.Controller) TagRepository {
  148. return mocks.NewTagRepositoryMock(mc)
  149. },
  150. articleMock: func(mc *minimock.Controller) ArticleRepository {
  151. mock := mocks.NewArticleRepositoryMock(mc)
  152. mock.GetByURLMock.Inspect(func(ctx context.Context, url string) {
  153. assert.Equal(mc, articleURL, url)
  154. }).Return(nil, sql.ErrNoRows)
  155. return mock
  156. },
  157. },
  158. {
  159. name: "negative case - article repository error",
  160. req: req{
  161. method: fiber.MethodGet,
  162. route: "/article/" + articleURL,
  163. },
  164. res: fiber.StatusInternalServerError,
  165. err: nil,
  166. cacheMock: func(mc *minimock.Controller) CacheService {
  167. mock := mocks.NewCacheServiceMock(mc)
  168. mock.GetMock.Expect(ArticleCacheKey+articleURL).Return(nil, false)
  169. return mock
  170. },
  171. tagMock: func(mc *minimock.Controller) TagRepository {
  172. return mocks.NewTagRepositoryMock(mc)
  173. },
  174. articleMock: func(mc *minimock.Controller) ArticleRepository {
  175. mock := mocks.NewArticleRepositoryMock(mc)
  176. mock.GetByURLMock.Inspect(func(ctx context.Context, url string) {
  177. assert.Equal(mc, articleURL, url)
  178. }).Return(nil, internalErr)
  179. return mock
  180. },
  181. },
  182. {
  183. name: "negative case - article not active",
  184. req: req{
  185. method: fiber.MethodGet,
  186. route: "/article/" + articleURL,
  187. },
  188. res: fiber.StatusNotFound,
  189. err: nil,
  190. cacheMock: func(mc *minimock.Controller) CacheService {
  191. mock := mocks.NewCacheServiceMock(mc)
  192. mock.GetMock.Expect(ArticleCacheKey+articleURL).Return(nil, false)
  193. return mock
  194. },
  195. tagMock: func(mc *minimock.Controller) TagRepository {
  196. return mocks.NewTagRepositoryMock(mc)
  197. },
  198. articleMock: func(mc *minimock.Controller) ArticleRepository {
  199. mock := mocks.NewArticleRepositoryMock(mc)
  200. mock.GetByURLMock.Inspect(func(ctx context.Context, url string) {
  201. assert.Equal(mc, articleURL, url)
  202. }).Return(&notActiveArticle, nil)
  203. return mock
  204. },
  205. },
  206. {
  207. name: "negative case - articles repository error",
  208. req: req{
  209. method: fiber.MethodGet,
  210. route: "/article/" + articleURL,
  211. },
  212. res: fiber.StatusInternalServerError,
  213. err: nil,
  214. cacheMock: func(mc *minimock.Controller) CacheService {
  215. mock := mocks.NewCacheServiceMock(mc)
  216. mock.GetMock.When(ArticleCacheKey+articleURL).Then(nil, false)
  217. mock.GetMock.When(RecentArticlesCacheKey).Then(nil, false)
  218. mock.SetMock.Return()
  219. return mock
  220. },
  221. tagMock: func(mc *minimock.Controller) TagRepository {
  222. return mocks.NewTagRepositoryMock(mc)
  223. },
  224. articleMock: func(mc *minimock.Controller) ArticleRepository {
  225. mock := mocks.NewArticleRepositoryMock(mc)
  226. mock.GetByURLMock.Inspect(func(ctx context.Context, url string) {
  227. assert.Equal(mc, articleURL, url)
  228. }).Return(&article, nil)
  229. mock.GetAllPreviewMock.Return(nil, internalErr)
  230. return mock
  231. },
  232. },
  233. {
  234. name: "negative case - tags repository error",
  235. req: req{
  236. method: fiber.MethodGet,
  237. route: "/article/" + articleURL,
  238. },
  239. res: fiber.StatusInternalServerError,
  240. err: nil,
  241. cacheMock: func(mc *minimock.Controller) CacheService {
  242. mock := mocks.NewCacheServiceMock(mc)
  243. mock.GetMock.When(ArticleCacheKey+articleURL).Then(nil, false)
  244. mock.GetMock.When(RecentArticlesCacheKey).Then(nil, false)
  245. mock.GetMock.When(UsedTagsCacheKey).Then(nil, false)
  246. mock.SetMock.Return()
  247. return mock
  248. },
  249. tagMock: func(mc *minimock.Controller) TagRepository {
  250. mock := mocks.NewTagRepositoryMock(mc)
  251. mock.GetAllUsedMock.Return(nil, internalErr)
  252. return mock
  253. },
  254. articleMock: func(mc *minimock.Controller) ArticleRepository {
  255. mock := mocks.NewArticleRepositoryMock(mc)
  256. mock.GetByURLMock.Inspect(func(ctx context.Context, url string) {
  257. assert.Equal(mc, articleURL, url)
  258. }).Return(&article, nil)
  259. mock.GetAllPreviewMock.Return(previewArticles, nil)
  260. return mock
  261. },
  262. },
  263. }
  264. for _, tt := range tests {
  265. t.Run(tt.name, func(t *testing.T) {
  266. t.Parallel()
  267. mc := minimock.NewController(t)
  268. fiberApp := fiber.New(test.GetFiberTestConfig())
  269. fiberReq := httptest.NewRequest(tt.req.method, tt.req.route, nil)
  270. fiberApp.Get("/article/:article", NewArticlePageHandler(
  271. tt.cacheMock(mc),
  272. tt.articleMock(mc),
  273. tt.tagMock(mc),
  274. ))
  275. fiberRes, fiberErr := fiberApp.Test(fiberReq)
  276. assert.Equal(t, tt.res, fiberRes.StatusCode)
  277. assert.Equal(t, tt.err, fiberErr)
  278. })
  279. }
  280. }