article_test.go 8.2 KB

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