add_image_test.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  1. package image
  2. import (
  3. "bytes"
  4. "context"
  5. "mime/multipart"
  6. "net/http/httptest"
  7. "strconv"
  8. "testing"
  9. "github.com/brianvoe/gofakeit/v6"
  10. "github.com/gofiber/fiber/v2"
  11. "github.com/gojuno/minimock/v3"
  12. "github.com/stretchr/testify/assert"
  13. "git.dmitriygnatenko.ru/dima/homethings/internal/api/v1/image/mocks"
  14. "git.dmitriygnatenko.ru/dima/homethings/internal/dto"
  15. "git.dmitriygnatenko.ru/dima/homethings/internal/helpers/test"
  16. "git.dmitriygnatenko.ru/dima/homethings/internal/models"
  17. )
  18. // nolint:errcheck
  19. func TestAddImageHandler(t *testing.T) {
  20. t.Parallel()
  21. type req struct {
  22. method string
  23. route string
  24. contentType string
  25. body []byte
  26. }
  27. var (
  28. placeID = gofakeit.Uint64()
  29. thingID = gofakeit.Uint64()
  30. testError = gofakeit.Error()
  31. txMockFunc = func(ctx context.Context, f func(ctx context.Context) error) error {
  32. return f(ctx)
  33. }
  34. )
  35. // Correct request for adding place image
  36. addPlaceCorrectBody := &bytes.Buffer{}
  37. addPlaceCorrectWriter := multipart.NewWriter(addPlaceCorrectBody)
  38. addPlaceCorrectWriter.WriteField("place_id", strconv.FormatUint(placeID, 10))
  39. addPlaceCorrectWriter.CreateFormFile("files", gofakeit.Word())
  40. addPlaceCorrectContentType := addPlaceCorrectWriter.FormDataContentType()
  41. addPlaceCorrectWriter.Close()
  42. // Correct request for adding thing image
  43. addThingCorrectBody := &bytes.Buffer{}
  44. addThingCorrectWriter := multipart.NewWriter(addThingCorrectBody)
  45. addThingCorrectWriter.WriteField("thing_id", strconv.FormatUint(thingID, 10))
  46. addThingCorrectWriter.CreateFormFile("files", gofakeit.Word())
  47. addThingCorrectContentType := addThingCorrectWriter.FormDataContentType()
  48. addThingCorrectWriter.Close()
  49. // Incorrect request for adding place image
  50. addPlaceIncorrectBody := &bytes.Buffer{}
  51. addPlaceIncorrectWriter := multipart.NewWriter(addPlaceIncorrectBody)
  52. addPlaceIncorrectWriter.WriteField("place_id", gofakeit.Word())
  53. addPlaceIncorrectContentType := addPlaceIncorrectWriter.FormDataContentType()
  54. addPlaceIncorrectWriter.Close()
  55. // Incorrect request for adding thing image
  56. addThingIncorrectBody := &bytes.Buffer{}
  57. addThingIncorrectWriter := multipart.NewWriter(addThingIncorrectBody)
  58. addThingIncorrectWriter.WriteField("thing_id", gofakeit.Word())
  59. addThingIncorrectContentType := addThingIncorrectWriter.FormDataContentType()
  60. addThingIncorrectWriter.Close()
  61. // Incorrect empty request
  62. emptyBody := &bytes.Buffer{}
  63. emptyWriter := multipart.NewWriter(emptyBody)
  64. emptyContentType := emptyWriter.FormDataContentType()
  65. emptyWriter.Close()
  66. tests := []struct {
  67. name string
  68. req req
  69. resCode int
  70. resBody interface{}
  71. tmMock func(mc *minimock.Controller) TransactionManager
  72. fileRepoMock func(mc *minimock.Controller) FileRepository
  73. placeImageRepoMock func(mc *minimock.Controller) PlaceImageRepository
  74. thingImageRepoMock func(mc *minimock.Controller) ThingImageRepository
  75. }{
  76. {
  77. name: "negative case - bad request",
  78. req: req{
  79. method: fiber.MethodPost,
  80. route: "/v1/images",
  81. },
  82. resCode: fiber.StatusBadRequest,
  83. tmMock: func(mc *minimock.Controller) TransactionManager {
  84. return mocks.NewTransactionManagerMock(mc)
  85. },
  86. placeImageRepoMock: func(mc *minimock.Controller) PlaceImageRepository {
  87. return mocks.NewPlaceImageRepositoryMock(mc)
  88. },
  89. thingImageRepoMock: func(mc *minimock.Controller) ThingImageRepository {
  90. return mocks.NewThingImageRepositoryMock(mc)
  91. },
  92. fileRepoMock: func(mc *minimock.Controller) FileRepository {
  93. return mocks.NewFileRepositoryMock(mc)
  94. },
  95. },
  96. {
  97. name: "negative case - incorrect request",
  98. req: req{
  99. method: fiber.MethodPost,
  100. route: "/v1/images",
  101. body: addPlaceIncorrectBody.Bytes(),
  102. contentType: addPlaceIncorrectContentType,
  103. },
  104. resCode: fiber.StatusBadRequest,
  105. tmMock: func(mc *minimock.Controller) TransactionManager {
  106. return mocks.NewTransactionManagerMock(mc)
  107. },
  108. placeImageRepoMock: func(mc *minimock.Controller) PlaceImageRepository {
  109. return mocks.NewPlaceImageRepositoryMock(mc)
  110. },
  111. thingImageRepoMock: func(mc *minimock.Controller) ThingImageRepository {
  112. return mocks.NewThingImageRepositoryMock(mc)
  113. },
  114. fileRepoMock: func(mc *minimock.Controller) FileRepository {
  115. return mocks.NewFileRepositoryMock(mc)
  116. },
  117. },
  118. {
  119. name: "negative case - incorrect request",
  120. req: req{
  121. method: fiber.MethodPost,
  122. route: "/v1/images",
  123. body: addThingIncorrectBody.Bytes(),
  124. contentType: addThingIncorrectContentType,
  125. },
  126. resCode: fiber.StatusBadRequest,
  127. tmMock: func(mc *minimock.Controller) TransactionManager {
  128. return mocks.NewTransactionManagerMock(mc)
  129. },
  130. placeImageRepoMock: func(mc *minimock.Controller) PlaceImageRepository {
  131. return mocks.NewPlaceImageRepositoryMock(mc)
  132. },
  133. thingImageRepoMock: func(mc *minimock.Controller) ThingImageRepository {
  134. return mocks.NewThingImageRepositoryMock(mc)
  135. },
  136. fileRepoMock: func(mc *minimock.Controller) FileRepository {
  137. return mocks.NewFileRepositoryMock(mc)
  138. },
  139. },
  140. {
  141. name: "negative case - empty request",
  142. req: req{
  143. method: fiber.MethodPost,
  144. route: "/v1/images",
  145. body: emptyBody.Bytes(),
  146. contentType: emptyContentType,
  147. },
  148. resCode: fiber.StatusBadRequest,
  149. tmMock: func(mc *minimock.Controller) TransactionManager {
  150. return mocks.NewTransactionManagerMock(mc)
  151. },
  152. placeImageRepoMock: func(mc *minimock.Controller) PlaceImageRepository {
  153. return mocks.NewPlaceImageRepositoryMock(mc)
  154. },
  155. thingImageRepoMock: func(mc *minimock.Controller) ThingImageRepository {
  156. return mocks.NewThingImageRepositoryMock(mc)
  157. },
  158. fileRepoMock: func(mc *minimock.Controller) FileRepository {
  159. return mocks.NewFileRepositoryMock(mc)
  160. },
  161. },
  162. {
  163. name: "negative case - repository error (add image)",
  164. req: req{
  165. method: fiber.MethodPost,
  166. route: "/v1/images",
  167. body: addPlaceCorrectBody.Bytes(),
  168. contentType: addPlaceCorrectContentType,
  169. },
  170. resCode: fiber.StatusInternalServerError,
  171. tmMock: func(mc *minimock.Controller) TransactionManager {
  172. mock := mocks.NewTransactionManagerMock(mc)
  173. mock.ReadCommittedMock.Set(txMockFunc)
  174. return mock
  175. },
  176. placeImageRepoMock: func(mc *minimock.Controller) PlaceImageRepository {
  177. mock := mocks.NewPlaceImageRepositoryMock(mc)
  178. mock.AddMock.Inspect(func(ctx context.Context, req models.AddPlaceImageRequest) {
  179. assert.Equal(mc, placeID, req.PlaceID)
  180. }).Return(testError)
  181. return mock
  182. },
  183. thingImageRepoMock: func(mc *minimock.Controller) ThingImageRepository {
  184. return mocks.NewThingImageRepositoryMock(mc)
  185. },
  186. fileRepoMock: func(mc *minimock.Controller) FileRepository {
  187. mock := mocks.NewFileRepositoryMock(mc)
  188. mock.SaveMock.Return(nil)
  189. return mock
  190. },
  191. },
  192. {
  193. name: "positive case - add place image",
  194. req: req{
  195. method: fiber.MethodPost,
  196. route: "/v1/images",
  197. body: addPlaceCorrectBody.Bytes(),
  198. contentType: addPlaceCorrectContentType,
  199. },
  200. resCode: fiber.StatusOK,
  201. resBody: dto.EmptyResponse{},
  202. tmMock: func(mc *minimock.Controller) TransactionManager {
  203. mock := mocks.NewTransactionManagerMock(mc)
  204. mock.ReadCommittedMock.Set(txMockFunc)
  205. return mock
  206. },
  207. placeImageRepoMock: func(mc *minimock.Controller) PlaceImageRepository {
  208. mock := mocks.NewPlaceImageRepositoryMock(mc)
  209. mock.AddMock.Inspect(func(ctx context.Context, req models.AddPlaceImageRequest) {
  210. assert.Equal(mc, placeID, req.PlaceID)
  211. }).Return(nil)
  212. return mock
  213. },
  214. thingImageRepoMock: func(mc *minimock.Controller) ThingImageRepository {
  215. return mocks.NewThingImageRepositoryMock(mc)
  216. },
  217. fileRepoMock: func(mc *minimock.Controller) FileRepository {
  218. mock := mocks.NewFileRepositoryMock(mc)
  219. mock.SaveMock.Return(nil)
  220. return mock
  221. },
  222. },
  223. {
  224. name: "negative case - repository error (add image)",
  225. req: req{
  226. method: fiber.MethodPost,
  227. route: "/v1/images",
  228. body: addThingCorrectBody.Bytes(),
  229. contentType: addThingCorrectContentType,
  230. },
  231. resCode: fiber.StatusInternalServerError,
  232. tmMock: func(mc *minimock.Controller) TransactionManager {
  233. mock := mocks.NewTransactionManagerMock(mc)
  234. mock.ReadCommittedMock.Set(txMockFunc)
  235. return mock
  236. },
  237. placeImageRepoMock: func(mc *minimock.Controller) PlaceImageRepository {
  238. return mocks.NewPlaceImageRepositoryMock(mc)
  239. },
  240. thingImageRepoMock: func(mc *minimock.Controller) ThingImageRepository {
  241. mock := mocks.NewThingImageRepositoryMock(mc)
  242. mock.AddMock.Inspect(func(ctx context.Context, req models.AddThingImageRequest) {
  243. assert.Equal(mc, thingID, req.ThingID)
  244. }).Return(testError)
  245. return mock
  246. },
  247. fileRepoMock: func(mc *minimock.Controller) FileRepository {
  248. mock := mocks.NewFileRepositoryMock(mc)
  249. mock.SaveMock.Return(nil)
  250. return mock
  251. },
  252. },
  253. {
  254. name: "positive case - add thing image",
  255. req: req{
  256. method: fiber.MethodPost,
  257. route: "/v1/images",
  258. body: addThingCorrectBody.Bytes(),
  259. contentType: addThingCorrectContentType,
  260. },
  261. resCode: fiber.StatusOK,
  262. resBody: dto.EmptyResponse{},
  263. tmMock: func(mc *minimock.Controller) TransactionManager {
  264. mock := mocks.NewTransactionManagerMock(mc)
  265. mock.ReadCommittedMock.Set(txMockFunc)
  266. return mock
  267. },
  268. placeImageRepoMock: func(mc *minimock.Controller) PlaceImageRepository {
  269. return mocks.NewPlaceImageRepositoryMock(mc)
  270. },
  271. thingImageRepoMock: func(mc *minimock.Controller) ThingImageRepository {
  272. mock := mocks.NewThingImageRepositoryMock(mc)
  273. mock.AddMock.Inspect(func(ctx context.Context, req models.AddThingImageRequest) {
  274. assert.Equal(mc, thingID, req.ThingID)
  275. }).Return(nil)
  276. return mock
  277. },
  278. fileRepoMock: func(mc *minimock.Controller) FileRepository {
  279. mock := mocks.NewFileRepositoryMock(mc)
  280. mock.SaveMock.Return(nil)
  281. return mock
  282. },
  283. },
  284. {
  285. name: "negative case - save file error",
  286. req: req{
  287. method: fiber.MethodPost,
  288. route: "/v1/images",
  289. body: addThingCorrectBody.Bytes(),
  290. contentType: addThingCorrectContentType,
  291. },
  292. resCode: fiber.StatusInternalServerError,
  293. tmMock: func(mc *minimock.Controller) TransactionManager {
  294. return mocks.NewTransactionManagerMock(mc)
  295. },
  296. placeImageRepoMock: func(mc *minimock.Controller) PlaceImageRepository {
  297. return mocks.NewPlaceImageRepositoryMock(mc)
  298. },
  299. thingImageRepoMock: func(mc *minimock.Controller) ThingImageRepository {
  300. return mocks.NewThingImageRepositoryMock(mc)
  301. },
  302. fileRepoMock: func(mc *minimock.Controller) FileRepository {
  303. mock := mocks.NewFileRepositoryMock(mc)
  304. mock.SaveMock.Return(testError)
  305. return mock
  306. },
  307. },
  308. }
  309. for _, tt := range tests {
  310. t.Run(tt.name, func(t *testing.T) {
  311. t.Parallel()
  312. mc := minimock.NewController(t)
  313. fiberApp := fiber.New()
  314. fiberApp.Post("/v1/images", AddImageHandler(
  315. tt.tmMock(mc),
  316. tt.fileRepoMock(mc),
  317. tt.thingImageRepoMock(mc),
  318. tt.placeImageRepoMock(mc),
  319. ))
  320. fiberReq := httptest.NewRequest(tt.req.method, tt.req.route, bytes.NewReader(tt.req.body))
  321. fiberReq.Header.Add(fiber.HeaderContentType, tt.req.contentType)
  322. fiberRes, _ := fiberApp.Test(fiberReq, test.TestTimeout)
  323. assert.Equal(t, tt.resCode, fiberRes.StatusCode)
  324. if tt.resBody != nil {
  325. assert.Equal(t, test.MarshalResponse(tt.resBody), test.ConvertBodyToString(fiberRes.Body))
  326. }
  327. })
  328. }
  329. }