article_test.go 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  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. article = models.Article{
  27. ID: articleID,
  28. URL: articleURL,
  29. Title: gofakeit.Phrase(),
  30. Text: gofakeit.Phrase(),
  31. PublishTime: publishTime,
  32. PreviewText: sql.NullString{Valid: true, String: gofakeit.Phrase()},
  33. Image: sql.NullString{Valid: true, String: gofakeit.URL()},
  34. IsActive: true,
  35. Language: models.LangRu,
  36. }
  37. notActiveArticle = models.Article{
  38. ID: articleID,
  39. URL: articleURL,
  40. Title: gofakeit.Phrase(),
  41. Text: gofakeit.Phrase(),
  42. PublishTime: publishTime,
  43. PreviewText: sql.NullString{Valid: true, String: gofakeit.Phrase()},
  44. Image: sql.NullString{Valid: true, String: gofakeit.URL()},
  45. Language: models.LangRu,
  46. }
  47. tags = []models.Tag{
  48. {
  49. ID: gofakeit.Uint64(),
  50. Tag: gofakeit.Word(),
  51. URL: gofakeit.Word(),
  52. },
  53. {
  54. ID: gofakeit.Uint64(),
  55. Tag: gofakeit.Word(),
  56. URL: gofakeit.Word(),
  57. },
  58. }
  59. previewArticles = []models.ArticlePreview{
  60. {
  61. ID: gofakeit.Uint64(),
  62. URL: gofakeit.URL(),
  63. Title: gofakeit.Phrase(),
  64. PublishTime: publishTime,
  65. PreviewText: sql.NullString{Valid: true, String: gofakeit.Phrase()},
  66. Image: sql.NullString{Valid: true, String: gofakeit.URL()},
  67. },
  68. {
  69. ID: gofakeit.Uint64(),
  70. URL: gofakeit.URL(),
  71. Title: gofakeit.Phrase(),
  72. PublishTime: publishTime,
  73. PreviewText: sql.NullString{Valid: true, String: gofakeit.Phrase()},
  74. Image: sql.NullString{Valid: true, String: gofakeit.URL()},
  75. },
  76. {
  77. ID: gofakeit.Uint64(),
  78. URL: gofakeit.URL(),
  79. Title: gofakeit.Phrase(),
  80. PublishTime: publishTime,
  81. PreviewText: sql.NullString{Valid: true, String: gofakeit.Phrase()},
  82. Image: sql.NullString{Valid: true, String: gofakeit.URL()},
  83. },
  84. {
  85. ID: gofakeit.Uint64(),
  86. URL: gofakeit.URL(),
  87. Title: gofakeit.Phrase(),
  88. PublishTime: publishTime,
  89. PreviewText: sql.NullString{Valid: true, String: gofakeit.Phrase()},
  90. Image: sql.NullString{Valid: true, String: gofakeit.URL()},
  91. },
  92. }
  93. )
  94. tests := []struct {
  95. name string
  96. req req
  97. res int
  98. err error
  99. cacheMock func(mc *minimock.Controller) CacheService
  100. tagMock func(mc *minimock.Controller) TagRepository
  101. articleMock func(mc *minimock.Controller) ArticleRepository
  102. }{
  103. {
  104. name: "positive case",
  105. req: req{
  106. method: fiber.MethodGet,
  107. route: "/article/" + articleURL,
  108. },
  109. res: fiber.StatusOK,
  110. err: nil,
  111. cacheMock: func(mc *minimock.Controller) CacheService {
  112. mock := mocks.NewCacheServiceMock(mc)
  113. mock.GetMock.Return(nil, false)
  114. mock.SetMock.Return()
  115. return mock
  116. },
  117. tagMock: func(mc *minimock.Controller) TagRepository {
  118. mock := mocks.NewTagRepositoryMock(mc)
  119. mock.GetAllUsedMock.Return(tags, nil)
  120. return mock
  121. },
  122. articleMock: func(mc *minimock.Controller) ArticleRepository {
  123. mock := mocks.NewArticleRepositoryMock(mc)
  124. mock.GetByURLMock.Inspect(func(ctx context.Context, url string, lang models.Language) {
  125. assert.Equal(mc, articleURL, url)
  126. assert.Equal(mc, models.LangRu, lang)
  127. }).Return(&article, nil)
  128. mock.GetAllPreviewMock.Return(previewArticles, nil)
  129. return mock
  130. },
  131. },
  132. {
  133. name: "negative case - article not found",
  134. req: req{
  135. method: fiber.MethodGet,
  136. route: "/article/" + articleURL,
  137. },
  138. res: fiber.StatusNotFound,
  139. err: nil,
  140. cacheMock: func(mc *minimock.Controller) CacheService {
  141. mock := mocks.NewCacheServiceMock(mc)
  142. mock.GetMock.Return(nil, false)
  143. return mock
  144. },
  145. tagMock: func(mc *minimock.Controller) TagRepository {
  146. mock := mocks.NewTagRepositoryMock(mc)
  147. return mock
  148. },
  149. articleMock: func(mc *minimock.Controller) ArticleRepository {
  150. mock := mocks.NewArticleRepositoryMock(mc)
  151. mock.GetByURLMock.Inspect(func(ctx context.Context, url string, lang models.Language) {
  152. assert.Equal(mc, articleURL, url)
  153. assert.Equal(mc, models.LangRu, lang)
  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.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, lang models.Language) {
  177. assert.Equal(mc, articleURL, url)
  178. assert.Equal(mc, models.LangRu, lang)
  179. }).Return(nil, internalErr)
  180. return mock
  181. },
  182. },
  183. {
  184. name: "negative case - article not active",
  185. req: req{
  186. method: fiber.MethodGet,
  187. route: "/article/" + articleURL,
  188. },
  189. res: fiber.StatusNotFound,
  190. err: nil,
  191. cacheMock: func(mc *minimock.Controller) CacheService {
  192. mock := mocks.NewCacheServiceMock(mc)
  193. mock.GetMock.Return(nil, false)
  194. return mock
  195. },
  196. tagMock: func(mc *minimock.Controller) TagRepository {
  197. return mocks.NewTagRepositoryMock(mc)
  198. },
  199. articleMock: func(mc *minimock.Controller) ArticleRepository {
  200. mock := mocks.NewArticleRepositoryMock(mc)
  201. mock.GetByURLMock.Inspect(func(ctx context.Context, url string, lang models.Language) {
  202. assert.Equal(mc, articleURL, url)
  203. assert.Equal(mc, models.LangRu, lang)
  204. }).Return(&notActiveArticle, nil)
  205. return mock
  206. },
  207. },
  208. {
  209. name: "negative case - tags repository error",
  210. req: req{
  211. method: fiber.MethodGet,
  212. route: "/article/" + articleURL,
  213. },
  214. res: fiber.StatusInternalServerError,
  215. err: nil,
  216. cacheMock: func(mc *minimock.Controller) CacheService {
  217. mock := mocks.NewCacheServiceMock(mc)
  218. // mock.GetMock.Return(nil, false)
  219. return mock
  220. },
  221. tagMock: func(mc *minimock.Controller) TagRepository {
  222. mock := mocks.NewTagRepositoryMock(mc)
  223. mock.GetAllUsedMock.Return(nil, internalErr)
  224. return mock
  225. },
  226. articleMock: func(mc *minimock.Controller) ArticleRepository {
  227. mock := mocks.NewArticleRepositoryMock(mc)
  228. mock.GetByURLMock.Inspect(func(ctx context.Context, url string, lang models.Language) {
  229. assert.Equal(mc, articleURL, url)
  230. assert.Equal(mc, models.LangRu, lang)
  231. }).Return(&article, nil)
  232. return mock
  233. },
  234. },
  235. {
  236. name: "negative case - articles repository error",
  237. req: req{
  238. method: fiber.MethodGet,
  239. route: "/article/" + articleURL,
  240. },
  241. res: fiber.StatusInternalServerError,
  242. err: nil,
  243. cacheMock: func(mc *minimock.Controller) CacheService {
  244. mock := mocks.NewCacheServiceMock(mc)
  245. mock.GetMock.Return(nil, false)
  246. return mock
  247. },
  248. tagMock: func(mc *minimock.Controller) TagRepository {
  249. mock := mocks.NewTagRepositoryMock(mc)
  250. mock.GetAllUsedMock.Return(tags, nil)
  251. return mock
  252. },
  253. articleMock: func(mc *minimock.Controller) ArticleRepository {
  254. mock := mocks.NewArticleRepositoryMock(mc)
  255. mock.GetByURLMock.Inspect(func(ctx context.Context, url string, lang models.Language) {
  256. assert.Equal(mc, articleURL, url)
  257. assert.Equal(mc, models.LangRu, lang)
  258. }).Return(&article, nil)
  259. mock.GetAllPreviewMock.Return(nil, internalErr)
  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", ArticleHandler(
  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. }