chrly/internal/http/api_test.go

173 lines
4.5 KiB
Go

package http
import (
"bytes"
"errors"
"io"
"net/http"
"net/http/httptest"
"net/url"
"strings"
"testing"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/suite"
"ely.by/chrly/internal/db"
"ely.by/chrly/internal/profiles"
)
type ProfilesManagerMock struct {
mock.Mock
}
func (m *ProfilesManagerMock) PersistProfile(profile *db.Profile) error {
return m.Called(profile).Error(0)
}
func (m *ProfilesManagerMock) RemoveProfileByUuid(uuid string) error {
return m.Called(uuid).Error(0)
}
type ApiTestSuite struct {
suite.Suite
App *Api
ProfilesManager *ProfilesManagerMock
}
func (t *ApiTestSuite) SetupSubTest() {
t.ProfilesManager = &ProfilesManagerMock{}
t.App = &Api{
ProfilesManager: t.ProfilesManager,
}
}
func (t *ApiTestSuite) TearDownSubTest() {
t.ProfilesManager.AssertExpectations(t.T())
}
func (t *ApiTestSuite) TestPostProfile() {
t.Run("successfully post profile", func() {
t.ProfilesManager.On("PersistProfile", &db.Profile{
Uuid: "0f657aa8-bfbe-415d-b700-5750090d3af3",
Username: "mock_username",
SkinUrl: "https://example.com/skin.png",
SkinModel: "slim",
CapeUrl: "https://example.com/cape.png",
MojangTextures: "bW9jawo=",
MojangSignature: "bW9jawo=",
}).Once().Return(nil)
req := httptest.NewRequest("POST", "http://chrly/profiles", bytes.NewBufferString(url.Values{
"uuid": {"0f657aa8-bfbe-415d-b700-5750090d3af3"},
"username": {"mock_username"},
"skinUrl": {"https://example.com/skin.png"},
"skinModel": {"slim"},
"capeUrl": {"https://example.com/cape.png"},
"mojangTextures": {"bW9jawo="},
"mojangSignature": {"bW9jawo="},
}.Encode()))
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
w := httptest.NewRecorder()
t.App.Handler().ServeHTTP(w, req)
result := w.Result()
t.Equal(http.StatusCreated, result.StatusCode)
body, _ := io.ReadAll(result.Body)
t.Empty(body)
})
t.Run("handle malformed body", func() {
req := httptest.NewRequest("POST", "http://chrly/profiles", strings.NewReader("invalid;=url?encoded_string"))
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
w := httptest.NewRecorder()
t.App.Handler().ServeHTTP(w, req)
result := w.Result()
t.Equal(http.StatusBadRequest, result.StatusCode)
body, _ := io.ReadAll(result.Body)
t.JSONEq(`{
"errors": {
"body": [
"The body of the request must be a valid url-encoded string"
]
}
}`, string(body))
})
t.Run("receive validation errors", func() {
t.ProfilesManager.On("PersistProfile", mock.Anything).Once().Return(&profiles.ValidationError{
Errors: map[string][]string{
"mock": {"error1", "error2"},
},
})
req := httptest.NewRequest("POST", "http://chrly/profiles", strings.NewReader(""))
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
w := httptest.NewRecorder()
t.App.Handler().ServeHTTP(w, req)
result := w.Result()
t.Equal(http.StatusBadRequest, result.StatusCode)
body, _ := io.ReadAll(result.Body)
t.JSONEq(`{
"errors": {
"mock": [
"error1",
"error2"
]
}
}`, string(body))
})
t.Run("receive other error", func() {
t.ProfilesManager.On("PersistProfile", mock.Anything).Once().Return(errors.New("mock error"))
req := httptest.NewRequest("POST", "http://chrly/profiles", strings.NewReader(""))
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
w := httptest.NewRecorder()
t.App.Handler().ServeHTTP(w, req)
result := w.Result()
t.Equal(http.StatusInternalServerError, result.StatusCode)
})
}
func (t *ApiTestSuite) TestDeleteProfileByUuid() {
t.Run("successfully delete", func() {
t.ProfilesManager.On("RemoveProfileByUuid", "0f657aa8-bfbe-415d-b700-5750090d3af3").Once().Return(nil)
req := httptest.NewRequest("DELETE", "http://chrly/profiles/0f657aa8-bfbe-415d-b700-5750090d3af3", nil)
w := httptest.NewRecorder()
t.App.Handler().ServeHTTP(w, req)
resp := w.Result()
t.Equal(http.StatusNoContent, resp.StatusCode)
body, _ := io.ReadAll(resp.Body)
t.Empty(body)
})
t.Run("error from manager", func() {
t.ProfilesManager.On("RemoveProfileByUuid", mock.Anything).Return(errors.New("mock error"))
req := httptest.NewRequest("DELETE", "http://chrly/profiles/0f657aa8-bfbe-415d-b700-5750090d3af3", nil)
w := httptest.NewRecorder()
t.App.Handler().ServeHTTP(w, req)
resp := w.Result()
t.Equal(http.StatusInternalServerError, resp.StatusCode)
})
}
func TestApi(t *testing.T) {
suite.Run(t, new(ApiTestSuite))
}