2020-02-07 17:27:45 +01:00
|
|
|
// Vikunja is a to-do list application to facilitate your life.
|
2021-02-02 20:19:13 +01:00
|
|
|
// Copyright 2018-2021 Vikunja and contributors. All rights reserved.
|
2019-04-21 20:18:17 +02:00
|
|
|
//
|
2019-12-04 20:39:56 +01:00
|
|
|
// This program is free software: you can redistribute it and/or modify
|
2020-12-23 16:41:52 +01:00
|
|
|
// it under the terms of the GNU Affero General Public Licensee as published by
|
2019-12-04 20:39:56 +01:00
|
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
|
|
// (at your option) any later version.
|
2019-04-21 20:18:17 +02:00
|
|
|
//
|
2019-12-04 20:39:56 +01:00
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
2020-12-23 16:41:52 +01:00
|
|
|
// GNU Affero General Public Licensee for more details.
|
2019-04-21 20:18:17 +02:00
|
|
|
//
|
2020-12-23 16:41:52 +01:00
|
|
|
// You should have received a copy of the GNU Affero General Public Licensee
|
2019-12-04 20:39:56 +01:00
|
|
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
2019-04-21 20:18:17 +02:00
|
|
|
|
|
|
|
package integrations
|
|
|
|
|
|
|
|
import (
|
2020-10-11 22:10:03 +02:00
|
|
|
"net/http"
|
|
|
|
"net/http/httptest"
|
|
|
|
"net/url"
|
|
|
|
"os"
|
|
|
|
"strings"
|
|
|
|
"testing"
|
|
|
|
|
2019-04-21 20:18:17 +02:00
|
|
|
"code.vikunja.io/api/pkg/config"
|
2019-10-16 22:52:29 +02:00
|
|
|
"code.vikunja.io/api/pkg/db"
|
2021-07-13 22:56:02 +02:00
|
|
|
"code.vikunja.io/api/pkg/events"
|
2021-07-30 15:31:51 +02:00
|
|
|
"code.vikunja.io/api/pkg/files"
|
2019-04-21 20:18:17 +02:00
|
|
|
"code.vikunja.io/api/pkg/models"
|
2020-11-21 17:38:58 +01:00
|
|
|
"code.vikunja.io/api/pkg/modules/auth"
|
2021-07-30 15:31:51 +02:00
|
|
|
"code.vikunja.io/api/pkg/modules/keyvalue"
|
2019-04-21 20:18:17 +02:00
|
|
|
"code.vikunja.io/api/pkg/routes"
|
2020-01-26 18:08:06 +01:00
|
|
|
"code.vikunja.io/api/pkg/user"
|
2019-04-21 20:18:17 +02:00
|
|
|
"code.vikunja.io/web"
|
|
|
|
"code.vikunja.io/web/handler"
|
2021-08-03 23:43:18 +02:00
|
|
|
"github.com/golang-jwt/jwt/v4"
|
2019-05-07 21:42:24 +02:00
|
|
|
"github.com/labstack/echo/v4"
|
2019-04-21 20:18:17 +02:00
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
)
|
|
|
|
|
|
|
|
// These are the test users, the same way they are in the test database
|
|
|
|
var (
|
2020-01-26 18:08:06 +01:00
|
|
|
testuser1 = user.User{
|
2019-04-21 20:18:17 +02:00
|
|
|
ID: 1,
|
|
|
|
Username: "user1",
|
|
|
|
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
|
|
|
Email: "user1@example.com",
|
|
|
|
}
|
2020-01-26 18:08:06 +01:00
|
|
|
testuser2 = user.User{
|
2019-04-21 20:18:17 +02:00
|
|
|
ID: 2,
|
|
|
|
Username: "user2",
|
|
|
|
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
|
|
|
Email: "user2@example.com",
|
|
|
|
}
|
2020-01-26 18:08:06 +01:00
|
|
|
testuser3 = user.User{
|
2021-07-13 22:56:02 +02:00
|
|
|
ID: 3,
|
|
|
|
Username: "user3",
|
|
|
|
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
|
|
|
Email: "user3@example.com",
|
2019-04-21 20:18:17 +02:00
|
|
|
}
|
2020-01-26 18:08:06 +01:00
|
|
|
testuser4 = user.User{
|
2021-07-13 22:56:02 +02:00
|
|
|
ID: 4,
|
|
|
|
Username: "user4",
|
|
|
|
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
|
|
|
Email: "user4@example.com",
|
2019-04-21 20:18:17 +02:00
|
|
|
}
|
2020-01-26 18:08:06 +01:00
|
|
|
testuser5 = user.User{
|
2021-07-13 22:56:02 +02:00
|
|
|
ID: 4,
|
|
|
|
Username: "user5",
|
|
|
|
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
|
|
|
Email: "user5@example.com",
|
|
|
|
Status: user.StatusDisabled,
|
2019-04-21 20:18:17 +02:00
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
func setupTestEnv() (e *echo.Echo, err error) {
|
2019-10-16 22:52:29 +02:00
|
|
|
config.InitDefaultConfig()
|
|
|
|
// We need to set the root path even if we're not using the config, otherwise fixtures are not loaded correctly
|
|
|
|
config.ServiceRootpath.Set(os.Getenv("VIKUNJA_SERVICE_ROOTPATH"))
|
|
|
|
// Some tests use the file engine, so we'll need to initialize that
|
|
|
|
files.InitTests()
|
2020-01-26 18:08:06 +01:00
|
|
|
user.InitTests()
|
|
|
|
models.SetupTests()
|
2021-02-02 23:48:37 +01:00
|
|
|
events.Fake()
|
2021-07-30 15:31:51 +02:00
|
|
|
keyvalue.InitStorage()
|
2019-04-21 20:18:17 +02:00
|
|
|
|
2019-10-16 22:52:29 +02:00
|
|
|
err = db.LoadFixtures()
|
2019-04-21 20:18:17 +02:00
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
e = routes.NewEcho()
|
|
|
|
routes.RegisterRoutes(e)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func bootstrapTestRequest(t *testing.T, method string, payload string, queryParam url.Values) (c echo.Context, rec *httptest.ResponseRecorder) {
|
|
|
|
// Setup
|
|
|
|
e, err := setupTestEnv()
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
// Do the actual request
|
|
|
|
req := httptest.NewRequest(method, "/", strings.NewReader(payload))
|
|
|
|
req.Header.Set(echo.HeaderContentType, echo.MIMEApplicationJSON)
|
|
|
|
req.URL.RawQuery = queryParam.Encode()
|
|
|
|
rec = httptest.NewRecorder()
|
|
|
|
|
|
|
|
c = e.NewContext(req, rec)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2021-04-11 15:17:50 +02:00
|
|
|
func newTestRequest(t *testing.T, method string, handler func(ctx echo.Context) error, payload string, queryParams url.Values, urlParams map[string]string) (rec *httptest.ResponseRecorder, err error) {
|
|
|
|
rec, c := testRequestSetup(t, method, payload, queryParams, urlParams)
|
2019-04-21 20:18:17 +02:00
|
|
|
err = handler(c)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2020-01-26 18:08:06 +01:00
|
|
|
func addUserTokenToContext(t *testing.T, user *user.User, c echo.Context) {
|
2019-04-21 20:18:17 +02:00
|
|
|
// Get the token as a string
|
2022-02-06 14:18:08 +01:00
|
|
|
token, err := auth.NewUserJWTAuthtoken(user, false)
|
2019-04-21 20:18:17 +02:00
|
|
|
assert.NoError(t, err)
|
|
|
|
// We send the string token through the parsing function to get a valid jwt.Token
|
|
|
|
tken, err := jwt.Parse(token, func(t *jwt.Token) (interface{}, error) {
|
2019-07-06 22:12:26 +02:00
|
|
|
return []byte(config.ServiceJWTSecret.GetString()), nil
|
2019-04-21 20:18:17 +02:00
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
c.Set("user", tken)
|
|
|
|
}
|
|
|
|
|
2019-08-31 22:56:41 +02:00
|
|
|
func addLinkShareTokenToContext(t *testing.T, share *models.LinkSharing, c echo.Context) {
|
|
|
|
// Get the token as a string
|
2020-11-21 17:38:58 +01:00
|
|
|
token, err := auth.NewLinkShareJWTAuthtoken(share)
|
2019-08-31 22:56:41 +02:00
|
|
|
assert.NoError(t, err)
|
|
|
|
// We send the string token through the parsing function to get a valid jwt.Token
|
|
|
|
tken, err := jwt.Parse(token, func(t *jwt.Token) (interface{}, error) {
|
|
|
|
return []byte(config.ServiceJWTSecret.GetString()), nil
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
c.Set("user", tken)
|
|
|
|
}
|
|
|
|
|
|
|
|
func testRequestSetup(t *testing.T, method string, payload string, queryParams url.Values, urlParams map[string]string) (rec *httptest.ResponseRecorder, c echo.Context) {
|
|
|
|
c, rec = bootstrapTestRequest(t, method, payload, queryParams)
|
2019-04-21 20:18:17 +02:00
|
|
|
|
|
|
|
var paramNames []string
|
|
|
|
var paramValues []string
|
|
|
|
for name, value := range urlParams {
|
|
|
|
paramNames = append(paramNames, name)
|
|
|
|
paramValues = append(paramValues, value)
|
|
|
|
}
|
|
|
|
c.SetParamNames(paramNames...)
|
|
|
|
c.SetParamValues(paramValues...)
|
2019-08-31 22:56:41 +02:00
|
|
|
return
|
|
|
|
}
|
2019-04-21 20:18:17 +02:00
|
|
|
|
2020-01-26 18:08:06 +01:00
|
|
|
func newTestRequestWithUser(t *testing.T, method string, handler echo.HandlerFunc, user *user.User, payload string, queryParams url.Values, urlParams map[string]string) (rec *httptest.ResponseRecorder, err error) {
|
2019-08-31 22:56:41 +02:00
|
|
|
rec, c := testRequestSetup(t, method, payload, queryParams, urlParams)
|
|
|
|
addUserTokenToContext(t, user, c)
|
|
|
|
err = handler(c)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func newTestRequestWithLinkShare(t *testing.T, method string, handler echo.HandlerFunc, share *models.LinkSharing, payload string, queryParams url.Values, urlParams map[string]string) (rec *httptest.ResponseRecorder, err error) {
|
|
|
|
rec, c := testRequestSetup(t, method, payload, queryParams, urlParams)
|
|
|
|
addLinkShareTokenToContext(t, share, c)
|
2019-04-21 20:18:17 +02:00
|
|
|
err = handler(c)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func assertHandlerErrorCode(t *testing.T, err error, expectedErrorCode int) {
|
|
|
|
if err == nil {
|
|
|
|
t.Error("Error is nil")
|
|
|
|
t.FailNow()
|
|
|
|
}
|
|
|
|
httperr, ok := err.(*echo.HTTPError)
|
|
|
|
if !ok {
|
|
|
|
t.Error("Error is not *echo.HTTPError")
|
|
|
|
t.FailNow()
|
|
|
|
}
|
|
|
|
webhttperr, ok := httperr.Message.(web.HTTPError)
|
|
|
|
if !ok {
|
|
|
|
t.Error("Error is not *web.HTTPError")
|
|
|
|
t.FailNow()
|
|
|
|
}
|
|
|
|
assert.Equal(t, expectedErrorCode, webhttperr.Code)
|
|
|
|
}
|
|
|
|
|
|
|
|
type webHandlerTest struct {
|
2020-01-26 18:08:06 +01:00
|
|
|
user *user.User
|
2019-08-31 22:56:41 +02:00
|
|
|
linkShare *models.LinkSharing
|
|
|
|
strFunc func() handler.CObject
|
|
|
|
t *testing.T
|
2019-04-21 20:18:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func (h *webHandlerTest) getHandler() handler.WebHandler {
|
|
|
|
return handler.WebHandler{
|
|
|
|
EmptyStruct: func() handler.CObject {
|
|
|
|
return h.strFunc()
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-31 22:56:41 +02:00
|
|
|
func (h *webHandlerTest) testReadAllWithUser(queryParams url.Values, urlParams map[string]string) (rec *httptest.ResponseRecorder, err error) {
|
2019-04-21 20:18:17 +02:00
|
|
|
hndl := h.getHandler()
|
|
|
|
return newTestRequestWithUser(h.t, http.MethodGet, hndl.ReadAllWeb, h.user, "", queryParams, urlParams)
|
|
|
|
}
|
|
|
|
|
2019-08-31 22:56:41 +02:00
|
|
|
func (h *webHandlerTest) testReadOneWithUser(queryParams url.Values, urlParams map[string]string) (rec *httptest.ResponseRecorder, err error) {
|
2019-04-21 20:18:17 +02:00
|
|
|
hndl := h.getHandler()
|
|
|
|
return newTestRequestWithUser(h.t, http.MethodGet, hndl.ReadOneWeb, h.user, "", queryParams, urlParams)
|
|
|
|
}
|
|
|
|
|
2019-08-31 22:56:41 +02:00
|
|
|
func (h *webHandlerTest) testCreateWithUser(queryParams url.Values, urlParams map[string]string, payload string) (rec *httptest.ResponseRecorder, err error) {
|
2019-04-21 20:18:17 +02:00
|
|
|
hndl := h.getHandler()
|
|
|
|
return newTestRequestWithUser(h.t, http.MethodPut, hndl.CreateWeb, h.user, payload, queryParams, urlParams)
|
|
|
|
}
|
|
|
|
|
2019-08-31 22:56:41 +02:00
|
|
|
func (h *webHandlerTest) testUpdateWithUser(queryParams url.Values, urlParams map[string]string, payload string) (rec *httptest.ResponseRecorder, err error) {
|
2019-04-21 20:18:17 +02:00
|
|
|
hndl := h.getHandler()
|
|
|
|
return newTestRequestWithUser(h.t, http.MethodPost, hndl.UpdateWeb, h.user, payload, queryParams, urlParams)
|
|
|
|
}
|
|
|
|
|
2020-03-15 22:50:39 +01:00
|
|
|
func (h *webHandlerTest) testDeleteWithUser(queryParams url.Values, urlParams map[string]string, payload ...string) (rec *httptest.ResponseRecorder, err error) {
|
|
|
|
pl := ""
|
|
|
|
if len(payload) > 0 {
|
|
|
|
pl = payload[0]
|
|
|
|
}
|
2019-04-21 20:18:17 +02:00
|
|
|
hndl := h.getHandler()
|
2020-03-15 22:50:39 +01:00
|
|
|
return newTestRequestWithUser(h.t, http.MethodDelete, hndl.DeleteWeb, h.user, pl, queryParams, urlParams)
|
2019-04-21 20:18:17 +02:00
|
|
|
}
|
2019-08-31 22:56:41 +02:00
|
|
|
|
|
|
|
func (h *webHandlerTest) testReadAllWithLinkShare(queryParams url.Values, urlParams map[string]string) (rec *httptest.ResponseRecorder, err error) {
|
|
|
|
hndl := h.getHandler()
|
|
|
|
return newTestRequestWithLinkShare(h.t, http.MethodGet, hndl.ReadAllWeb, h.linkShare, "", queryParams, urlParams)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (h *webHandlerTest) testReadOneWithLinkShare(queryParams url.Values, urlParams map[string]string) (rec *httptest.ResponseRecorder, err error) {
|
|
|
|
hndl := h.getHandler()
|
|
|
|
return newTestRequestWithLinkShare(h.t, http.MethodGet, hndl.ReadOneWeb, h.linkShare, "", queryParams, urlParams)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (h *webHandlerTest) testCreateWithLinkShare(queryParams url.Values, urlParams map[string]string, payload string) (rec *httptest.ResponseRecorder, err error) {
|
|
|
|
hndl := h.getHandler()
|
|
|
|
return newTestRequestWithLinkShare(h.t, http.MethodPut, hndl.CreateWeb, h.linkShare, payload, queryParams, urlParams)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (h *webHandlerTest) testUpdateWithLinkShare(queryParams url.Values, urlParams map[string]string, payload string) (rec *httptest.ResponseRecorder, err error) {
|
|
|
|
hndl := h.getHandler()
|
|
|
|
return newTestRequestWithLinkShare(h.t, http.MethodPost, hndl.UpdateWeb, h.linkShare, payload, queryParams, urlParams)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (h *webHandlerTest) testDeleteWithLinkShare(queryParams url.Values, urlParams map[string]string) (rec *httptest.ResponseRecorder, err error) {
|
|
|
|
hndl := h.getHandler()
|
|
|
|
return newTestRequestWithLinkShare(h.t, http.MethodDelete, hndl.DeleteWeb, h.linkShare, "", queryParams, urlParams)
|
|
|
|
}
|