142 lines
4.5 KiB
Go
142 lines
4.5 KiB
Go
|
package recipe_test
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"context"
|
||
|
"encoding/json"
|
||
|
"errors"
|
||
|
"fmt"
|
||
|
"net/http"
|
||
|
"net/http/httptest"
|
||
|
"recipes/internal/domain/models"
|
||
|
"recipes/internal/http-server/handlers/recipe"
|
||
|
"recipes/internal/http-server/handlers/recipe/mocks"
|
||
|
"recipes/internal/lib/logger/handlers/slogdiscard"
|
||
|
"recipes/internal/storage"
|
||
|
"testing"
|
||
|
|
||
|
"github.com/stretchr/testify/assert"
|
||
|
"github.com/stretchr/testify/require"
|
||
|
)
|
||
|
|
||
|
func TestGetRecipeHandler(t *testing.T) {
|
||
|
// cases
|
||
|
cases := []struct {
|
||
|
name string // name of test
|
||
|
inputJsonPattern string // input json
|
||
|
recipe_id uint // recipe id to get
|
||
|
recipe models.Recipe // recipe data
|
||
|
wantRespStatus string // expected status of response
|
||
|
wantBody string // expected response body
|
||
|
respError string // expected response error
|
||
|
storageMockError error // mock error to return
|
||
|
storageTimes int // count of storage calls
|
||
|
}{
|
||
|
{
|
||
|
name: "Success",
|
||
|
recipe_id: 1,
|
||
|
recipe: models.Recipe{
|
||
|
ID: 1,
|
||
|
Title: "title",
|
||
|
Description: "description",
|
||
|
Image: "img.jpg",
|
||
|
CookingTime: "1 час",
|
||
|
ServingsNum: 1,
|
||
|
Calories: "1 kCal",
|
||
|
Ingredients: []models.RecipeIngredients{
|
||
|
{
|
||
|
Title: "Ингредиенты",
|
||
|
Ingredients: []string{"Ингредиент 1", "Ингредиент 2"},
|
||
|
},
|
||
|
},
|
||
|
Recipe_steps: []string{
|
||
|
"Шаг 1",
|
||
|
"Шаг 2",
|
||
|
},
|
||
|
Advices: []string{
|
||
|
"1. совет",
|
||
|
"2. совет",
|
||
|
},
|
||
|
Categories: []string{
|
||
|
"Категория 1",
|
||
|
"Категория 2",
|
||
|
},
|
||
|
},
|
||
|
wantBody: "{\"status\":\"OK\",\"recipe\":{\"id\":1,\"title\":\"title\",\"desc\":\"description\",\"img\":\"img.jpg\",\"ctime\":\"1 час\",\"snum\":1,\"cal\":\"1 kCal\",\"ingredients\":[{\"title\":\"Ингредиенты\",\"ingredients\":[\"Ингредиент 1\",\"Ингредиент 2\"]}],\"recipe_steps\":[\"Шаг 1\",\"Шаг 2\"],\"advices\":[\"1. совет\",\"2. совет\"],\"categories\":[\"Категория 1\",\"Категория 2\"]}}\n",
|
||
|
storageTimes: 1,
|
||
|
wantRespStatus: "OK",
|
||
|
inputJsonPattern: `{"recipe_id": %d}`,
|
||
|
},
|
||
|
{
|
||
|
name: "Broken JSON",
|
||
|
respError: "failed to decode request",
|
||
|
inputJsonPattern: `{"recipe_id: %d}`,
|
||
|
wantRespStatus: "Error",
|
||
|
wantBody: "{\"status\":\"Error\",\"error\":\"failed to decode request\"}\n",
|
||
|
storageTimes: 0,
|
||
|
},
|
||
|
{
|
||
|
name: "Recipe not exists",
|
||
|
respError: "recipe not found",
|
||
|
inputJsonPattern: `{"recipe_id": %d}`,
|
||
|
recipe_id: 1,
|
||
|
wantRespStatus: "Error",
|
||
|
storageMockError: storage.ErrRecipeNotFound,
|
||
|
storageTimes: 1,
|
||
|
wantBody: "{\"status\":\"Error\",\"error\":\"recipe not found\"}\n",
|
||
|
},
|
||
|
{
|
||
|
name: "Storage error",
|
||
|
respError: "failed to get recipe",
|
||
|
inputJsonPattern: `{"recipe_id": %d}`,
|
||
|
recipe_id: 1,
|
||
|
wantRespStatus: "Error",
|
||
|
storageMockError: errors.New("SOME ERROR"),
|
||
|
storageTimes: 1,
|
||
|
wantBody: "{\"status\":\"Error\",\"error\":\"failed to get recipe\"}\n",
|
||
|
},
|
||
|
{
|
||
|
name: "Miss recipe_id",
|
||
|
inputJsonPattern: "{}",
|
||
|
respError: "field RecipeId is a required field",
|
||
|
wantRespStatus: "Error",
|
||
|
wantBody: "{\"status\":\"Error\",\"error\":\"field RecipeId is a required field\"}\n",
|
||
|
storageTimes: 0,
|
||
|
},
|
||
|
}
|
||
|
|
||
|
for _, tc := range cases {
|
||
|
tc := tc
|
||
|
|
||
|
t.Run(tc.name, func(t *testing.T) {
|
||
|
t.Parallel()
|
||
|
// create storage mock
|
||
|
recipeProviderMock := mocks.NewRecipeProvider(t)
|
||
|
if tc.storageTimes > 0 {
|
||
|
recipeProviderMock.On("GetRecipe", context.Background(), tc.recipe_id).Return(tc.recipe, tc.storageMockError).Times(tc.storageTimes)
|
||
|
}
|
||
|
// create handler
|
||
|
handler := recipe.New(slogdiscard.NewDiscardLogger(), recipeProviderMock)
|
||
|
//
|
||
|
input := fmt.Sprintf(tc.inputJsonPattern, 1)
|
||
|
// http request
|
||
|
req, err := http.NewRequest(http.MethodGet, "/recipe", bytes.NewReader([]byte(input)))
|
||
|
require.NoError(t, err)
|
||
|
// create request
|
||
|
rr := httptest.NewRecorder()
|
||
|
handler.ServeHTTP(rr, req)
|
||
|
// compare expected and actual
|
||
|
assert.Equal(t, http.StatusOK, rr.Code)
|
||
|
|
||
|
body := rr.Body.String()
|
||
|
assert.Equal(t, tc.wantBody, body)
|
||
|
|
||
|
var resp recipe.Response
|
||
|
require.NoError(t, json.Unmarshal([]byte(body), &resp))
|
||
|
assert.Equal(t, tc.respError, resp.Error)
|
||
|
assert.Equal(t, tc.wantRespStatus, resp.Status)
|
||
|
assert.Equal(t, tc.recipe, resp.Recipe)
|
||
|
})
|
||
|
}
|
||
|
}
|