add_thing_test.go 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. package thing
  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/homethings/internal/api/v1/thing/mocks"
  12. "git.dmitriygnatenko.ru/dima/homethings/internal/dto"
  13. "git.dmitriygnatenko.ru/dima/homethings/internal/helpers/test"
  14. "git.dmitriygnatenko.ru/dima/homethings/internal/models"
  15. )
  16. func TestAddThingHandler(t *testing.T) {
  17. t.Parallel()
  18. type req struct {
  19. method string
  20. route string
  21. contentType string
  22. body *dto.AddThingRequest
  23. }
  24. var (
  25. placeID = uint64(gofakeit.Number(1, 1000))
  26. thingID = uint64(gofakeit.Number(1, 1000))
  27. title = gofakeit.Phrase()
  28. description = gofakeit.Phrase()
  29. testError = gofakeit.Error()
  30. layout = "2006-01-02 15:04:05"
  31. txMockFunc = func(ctx context.Context, f func(ctx context.Context) error) error {
  32. return f(ctx)
  33. }
  34. correctReq = req{
  35. method: fiber.MethodPost,
  36. route: "/v1/things",
  37. body: &dto.AddThingRequest{
  38. PlaceID: placeID,
  39. Title: title,
  40. Description: description,
  41. },
  42. contentType: fiber.MIMEApplicationJSON,
  43. }
  44. repoRes = models.Thing{
  45. ID: thingID,
  46. PlaceID: placeID,
  47. Title: title,
  48. Description: description,
  49. CreatedAt: gofakeit.Date(),
  50. UpdatedAt: gofakeit.Date(),
  51. }
  52. expectedRes = dto.ThingResponse{
  53. ID: thingID,
  54. PlaceID: placeID,
  55. Title: title,
  56. Description: description,
  57. CreatedAt: repoRes.CreatedAt.Format(layout),
  58. UpdatedAt: repoRes.UpdatedAt.Format(layout),
  59. }
  60. )
  61. tests := []struct {
  62. name string
  63. req req
  64. resCode int
  65. resBody interface{}
  66. tmMock func(mc *minimock.Controller) TransactionManager
  67. thingRepoMock func(mc *minimock.Controller) ThingRepository
  68. placeThingRepoMock func(mc *minimock.Controller) PlaceThingRepository
  69. }{
  70. {
  71. name: "positive case",
  72. req: correctReq,
  73. resCode: fiber.StatusOK,
  74. resBody: expectedRes,
  75. tmMock: func(mc *minimock.Controller) TransactionManager {
  76. mock := mocks.NewTransactionManagerMock(mc)
  77. mock.ReadCommittedMock.Set(txMockFunc)
  78. return mock
  79. },
  80. thingRepoMock: func(mc *minimock.Controller) ThingRepository {
  81. mock := mocks.NewThingRepositoryMock(mc)
  82. mock.AddMock.Inspect(func(ctx context.Context, req models.AddThingRequest) {
  83. assert.Equal(mc, title, req.Title)
  84. assert.Equal(mc, description, req.Description)
  85. }).Return(thingID, nil)
  86. mock.GetMock.Inspect(func(ctx context.Context, id uint64) {
  87. assert.Equal(mc, thingID, id)
  88. }).Return(&repoRes, nil)
  89. return mock
  90. },
  91. placeThingRepoMock: func(mc *minimock.Controller) PlaceThingRepository {
  92. mock := mocks.NewPlaceThingRepositoryMock(mc)
  93. mock.AddMock.Inspect(func(ctx context.Context, req models.AddPlaceThingRequest) {
  94. assert.Equal(mc, thingID, req.ThingID)
  95. assert.Equal(mc, placeID, req.PlaceID)
  96. }).Return(nil)
  97. return mock
  98. },
  99. },
  100. {
  101. name: "negative case - body parse error",
  102. req: req{
  103. method: fiber.MethodPost,
  104. route: "/v1/things",
  105. },
  106. resCode: fiber.StatusBadRequest,
  107. tmMock: func(mc *minimock.Controller) TransactionManager {
  108. return mocks.NewTransactionManagerMock(mc)
  109. },
  110. thingRepoMock: func(mc *minimock.Controller) ThingRepository {
  111. return mocks.NewThingRepositoryMock(mc)
  112. },
  113. placeThingRepoMock: func(mc *minimock.Controller) PlaceThingRepository {
  114. return mocks.NewPlaceThingRepositoryMock(mc)
  115. },
  116. },
  117. {
  118. name: "negative case - request without place_id",
  119. req: req{
  120. method: fiber.MethodPost,
  121. route: "/v1/things",
  122. contentType: fiber.MIMEApplicationJSON,
  123. body: &dto.AddThingRequest{
  124. Title: title,
  125. Description: description,
  126. },
  127. },
  128. resCode: fiber.StatusBadRequest,
  129. resBody: []*dto.ValidateErrorResponse{
  130. {
  131. Field: "AddThingRequest.PlaceID",
  132. Tag: "required",
  133. },
  134. },
  135. tmMock: func(mc *minimock.Controller) TransactionManager {
  136. return mocks.NewTransactionManagerMock(mc)
  137. },
  138. thingRepoMock: func(mc *minimock.Controller) ThingRepository {
  139. return mocks.NewThingRepositoryMock(mc)
  140. },
  141. placeThingRepoMock: func(mc *minimock.Controller) PlaceThingRepository {
  142. return mocks.NewPlaceThingRepositoryMock(mc)
  143. },
  144. },
  145. {
  146. name: "negative case - request without title",
  147. req: req{
  148. method: fiber.MethodPost,
  149. route: "/v1/things",
  150. contentType: fiber.MIMEApplicationJSON,
  151. body: &dto.AddThingRequest{
  152. PlaceID: placeID,
  153. Description: description,
  154. },
  155. },
  156. resCode: fiber.StatusBadRequest,
  157. resBody: []*dto.ValidateErrorResponse{
  158. {
  159. Field: "AddThingRequest.Title",
  160. Tag: "required",
  161. },
  162. },
  163. tmMock: func(mc *minimock.Controller) TransactionManager {
  164. return mocks.NewTransactionManagerMock(mc)
  165. },
  166. thingRepoMock: func(mc *minimock.Controller) ThingRepository {
  167. return mocks.NewThingRepositoryMock(mc)
  168. },
  169. placeThingRepoMock: func(mc *minimock.Controller) PlaceThingRepository {
  170. return mocks.NewPlaceThingRepositoryMock(mc)
  171. },
  172. },
  173. {
  174. name: "negative case - repository error (add thing)",
  175. req: correctReq,
  176. resCode: fiber.StatusInternalServerError,
  177. tmMock: func(mc *minimock.Controller) TransactionManager {
  178. mock := mocks.NewTransactionManagerMock(mc)
  179. mock.ReadCommittedMock.Set(txMockFunc)
  180. return mock
  181. },
  182. thingRepoMock: func(mc *minimock.Controller) ThingRepository {
  183. mock := mocks.NewThingRepositoryMock(mc)
  184. mock.AddMock.Inspect(func(ctx context.Context, req models.AddThingRequest) {
  185. assert.Equal(mc, title, req.Title)
  186. assert.Equal(mc, description, req.Description)
  187. }).Return(0, testError)
  188. return mock
  189. },
  190. placeThingRepoMock: func(mc *minimock.Controller) PlaceThingRepository {
  191. return mocks.NewPlaceThingRepositoryMock(mc)
  192. },
  193. },
  194. {
  195. name: "negative case - repository error (add place thing)",
  196. req: correctReq,
  197. resCode: fiber.StatusInternalServerError,
  198. tmMock: func(mc *minimock.Controller) TransactionManager {
  199. mock := mocks.NewTransactionManagerMock(mc)
  200. mock.ReadCommittedMock.Set(txMockFunc)
  201. return mock
  202. },
  203. thingRepoMock: func(mc *minimock.Controller) ThingRepository {
  204. mock := mocks.NewThingRepositoryMock(mc)
  205. mock.AddMock.Inspect(func(ctx context.Context, req models.AddThingRequest) {
  206. assert.Equal(mc, title, req.Title)
  207. assert.Equal(mc, description, req.Description)
  208. }).Return(thingID, nil)
  209. return mock
  210. },
  211. placeThingRepoMock: func(mc *minimock.Controller) PlaceThingRepository {
  212. mock := mocks.NewPlaceThingRepositoryMock(mc)
  213. mock.AddMock.Inspect(func(ctx context.Context, req models.AddPlaceThingRequest) {
  214. assert.Equal(mc, thingID, req.ThingID)
  215. assert.Equal(mc, placeID, req.PlaceID)
  216. }).Return(testError)
  217. return mock
  218. },
  219. },
  220. {
  221. name: "negative case - repository error (get thing)",
  222. req: correctReq,
  223. resCode: fiber.StatusInternalServerError,
  224. tmMock: func(mc *minimock.Controller) TransactionManager {
  225. mock := mocks.NewTransactionManagerMock(mc)
  226. mock.ReadCommittedMock.Set(txMockFunc)
  227. return mock
  228. },
  229. thingRepoMock: func(mc *minimock.Controller) ThingRepository {
  230. mock := mocks.NewThingRepositoryMock(mc)
  231. mock.AddMock.Inspect(func(ctx context.Context, req models.AddThingRequest) {
  232. assert.Equal(mc, title, req.Title)
  233. assert.Equal(mc, description, req.Description)
  234. }).Return(thingID, nil)
  235. mock.GetMock.Inspect(func(ctx context.Context, id uint64) {
  236. assert.Equal(mc, thingID, id)
  237. }).Return(nil, sql.ErrNoRows)
  238. return mock
  239. },
  240. placeThingRepoMock: func(mc *minimock.Controller) PlaceThingRepository {
  241. mock := mocks.NewPlaceThingRepositoryMock(mc)
  242. mock.AddMock.Inspect(func(ctx context.Context, req models.AddPlaceThingRequest) {
  243. assert.Equal(mc, thingID, req.ThingID)
  244. assert.Equal(mc, placeID, req.PlaceID)
  245. }).Return(nil)
  246. return mock
  247. },
  248. },
  249. }
  250. for _, tt := range tests {
  251. t.Run(tt.name, func(t *testing.T) {
  252. t.Parallel()
  253. mc := minimock.NewController(t)
  254. fiberApp := fiber.New()
  255. fiberApp.Post("/v1/things", AddThingHandler(
  256. tt.tmMock(mc),
  257. tt.thingRepoMock(mc),
  258. tt.placeThingRepoMock(mc),
  259. ))
  260. fiberReq := httptest.NewRequest(tt.req.method, tt.req.route, test.ConvertDataToIOReader(tt.req.body))
  261. fiberReq.Header.Add(fiber.HeaderContentType, tt.req.contentType)
  262. fiberRes, _ := fiberApp.Test(fiberReq, test.TestTimeout)
  263. assert.Equal(t, tt.resCode, fiberRes.StatusCode)
  264. if tt.resBody != nil {
  265. assert.Equal(t, test.MarshalResponse(tt.resBody), test.ConvertBodyToString(fiberRes.Body))
  266. }
  267. })
  268. }
  269. }