mirror of
https://github.com/dnote/dnote
synced 2026-03-15 15:05:51 +01:00
* Require explicit configuration for database connection * Test validation * Remove stutter * Only use packr for self hosting * Restart server upon change
254 lines
7.2 KiB
Go
254 lines
7.2 KiB
Go
/* Copyright (C) 2019 Monomax Software Pty Ltd
|
|
*
|
|
* This file is part of Dnote.
|
|
*
|
|
* Dnote is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Affero General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* Dnote 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
|
|
* GNU Affero General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Affero General Public License
|
|
* along with Dnote. If not, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
// Package testutils provides utilities used in tests
|
|
package testutils
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"os"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/dnote/dnote/pkg/server/database"
|
|
"github.com/stripe/stripe-go"
|
|
|
|
"github.com/jinzhu/gorm"
|
|
"github.com/pkg/errors"
|
|
)
|
|
|
|
// InitTestDB establishes connection pool with the test database specified by
|
|
// the environment variable configuration and initalizes a new schema
|
|
func InitTestDB() {
|
|
c := database.Config{
|
|
Host: os.Getenv("DBHost"),
|
|
Port: os.Getenv("DBPort"),
|
|
Name: os.Getenv("DBName"),
|
|
User: os.Getenv("DBUser"),
|
|
Password: os.Getenv("DBPassword"),
|
|
}
|
|
database.Open(c)
|
|
database.InitSchema()
|
|
}
|
|
|
|
// SetupUserData creates and returns a new user for testing purposes
|
|
func SetupUserData() database.User {
|
|
db := database.DBConn
|
|
|
|
user := database.User{
|
|
APIKey: "test-api-key",
|
|
Name: "user-name",
|
|
Cloud: true,
|
|
}
|
|
|
|
if err := db.Save(&user).Error; err != nil {
|
|
panic(errors.Wrap(err, "Failed to prepare user"))
|
|
}
|
|
|
|
return user
|
|
}
|
|
|
|
// SetupAccountData creates and returns a new account for the user
|
|
func SetupAccountData(user database.User, email string) database.Account {
|
|
db := database.DBConn
|
|
|
|
// email: alice@example.com
|
|
// password: pass1234
|
|
// masterKey: WbUvagj9O6o1Z+4+7COjo7Uqm4MD2QE9EWFXne8+U+8=
|
|
// authKey: /XCYisXJ6/o+vf6NUEtmrdYzJYPz+T9oAUCtMpOjhzc=
|
|
account := database.Account{
|
|
UserID: user.ID,
|
|
Salt: "Et0joOigYjdgHBKMN/ijxg==",
|
|
AuthKeyHash: "SeN3PMz4H/7q9lINB+VPKpygexAuK68wO8pDAgQ4OOQ=",
|
|
CipherKeyEnc: "f7aFFCh7YS1WlHEOxAmDfs8rUQQoX5tr8AB7ZJQaTYCEM8NhAZCbQTsjFgKOf5iPQhhkm8eDAgPNTuhO",
|
|
ClientKDFIteration: 100000,
|
|
ServerKDFIteration: 100000,
|
|
}
|
|
if email != "" {
|
|
account.Email = database.ToNullString(email)
|
|
}
|
|
|
|
if err := db.Save(&account).Error; err != nil {
|
|
panic(errors.Wrap(err, "Failed to prepare account"))
|
|
}
|
|
|
|
return account
|
|
}
|
|
|
|
// SetupSession creates and returns a new user session
|
|
func SetupSession(t *testing.T, user database.User) database.Session {
|
|
db := database.DBConn
|
|
|
|
session := database.Session{
|
|
Key: "Vvgm3eBXfXGEFWERI7faiRJ3DAzJw+7DdT9J1LEyNfI=",
|
|
UserID: user.ID,
|
|
ExpiresAt: time.Now().Add(time.Hour * 24),
|
|
}
|
|
if err := db.Save(&session).Error; err != nil {
|
|
t.Fatal(errors.Wrap(err, "Failed to prepare user"))
|
|
}
|
|
|
|
return session
|
|
}
|
|
|
|
// SetupEmailPreferenceData creates and returns a new email frequency for a user
|
|
func SetupEmailPreferenceData(user database.User, digestWeekly bool) database.EmailPreference {
|
|
db := database.DBConn
|
|
|
|
frequency := database.EmailPreference{
|
|
UserID: user.ID,
|
|
DigestWeekly: digestWeekly,
|
|
}
|
|
|
|
if err := db.Save(&frequency).Error; err != nil {
|
|
panic(errors.Wrap(err, "Failed to prepare email frequency"))
|
|
}
|
|
|
|
return frequency
|
|
}
|
|
|
|
// ClearData deletes all records from the database
|
|
func ClearData() {
|
|
db := database.DBConn
|
|
|
|
if err := db.Delete(&database.Book{}).Error; err != nil {
|
|
panic(errors.Wrap(err, "Failed to clear books"))
|
|
}
|
|
if err := db.Delete(&database.Note{}).Error; err != nil {
|
|
panic(errors.Wrap(err, "Failed to clear notes"))
|
|
}
|
|
if err := db.Delete(&database.Notification{}).Error; err != nil {
|
|
panic(errors.Wrap(err, "Failed to clear notifications"))
|
|
}
|
|
if err := db.Delete(&database.User{}).Error; err != nil {
|
|
panic(errors.Wrap(err, "Failed to clear users"))
|
|
}
|
|
if err := db.Delete(&database.Account{}).Error; err != nil {
|
|
panic(errors.Wrap(err, "Failed to clear accounts"))
|
|
}
|
|
if err := db.Delete(&database.Token{}).Error; err != nil {
|
|
panic(errors.Wrap(err, "Failed to clear reset_tokens"))
|
|
}
|
|
if err := db.Delete(&database.EmailPreference{}).Error; err != nil {
|
|
panic(errors.Wrap(err, "Failed to clear reset_tokens"))
|
|
}
|
|
if err := db.Delete(&database.Session{}).Error; err != nil {
|
|
panic(errors.Wrap(err, "Failed to clear sessions"))
|
|
}
|
|
if err := db.Delete(&database.Digest{}).Error; err != nil {
|
|
panic(errors.Wrap(err, "Failed to clear digests"))
|
|
}
|
|
}
|
|
|
|
// HTTPDo makes an HTTP request and returns a response
|
|
func HTTPDo(t *testing.T, req *http.Request) *http.Response {
|
|
hc := http.Client{
|
|
// Do not follow redirects.
|
|
// e.g. /logout redirects to a page but we'd like to test the redirect
|
|
// itself, not what happens after the redirect
|
|
CheckRedirect: func(req *http.Request, via []*http.Request) error {
|
|
return http.ErrUseLastResponse
|
|
},
|
|
}
|
|
|
|
res, err := hc.Do(req)
|
|
if err != nil {
|
|
t.Fatal(errors.Wrap(err, "performing http request"))
|
|
}
|
|
|
|
return res
|
|
}
|
|
|
|
// HTTPAuthDo makes an HTTP request with an appropriate authorization header for a user
|
|
func HTTPAuthDo(t *testing.T, req *http.Request, user database.User) *http.Response {
|
|
db := database.DBConn
|
|
|
|
session := database.Session{
|
|
Key: "Vvgm3eBXfXGEFWERI7faiRJ3DAzJw+7DdT9J1LEyNfI=",
|
|
UserID: user.ID,
|
|
ExpiresAt: time.Now().Add(time.Hour * 10 * 24),
|
|
}
|
|
if err := db.Save(&session).Error; err != nil {
|
|
t.Fatal(errors.Wrap(err, "Failed to prepare user"))
|
|
}
|
|
|
|
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", session.Key))
|
|
|
|
return HTTPDo(t, req)
|
|
|
|
}
|
|
|
|
// MakeReq makes an HTTP request and returns a response
|
|
func MakeReq(server *httptest.Server, method, url, data string) *http.Request {
|
|
endpoint := fmt.Sprintf("%s%s", server.URL, url)
|
|
|
|
req, err := http.NewRequest(method, endpoint, strings.NewReader(data))
|
|
if err != nil {
|
|
panic(errors.Wrap(err, "constructing http request"))
|
|
}
|
|
|
|
return req
|
|
}
|
|
|
|
// MustExec fails the test if the given database query has error
|
|
func MustExec(t *testing.T, db *gorm.DB, message string) {
|
|
if err := db.Error; err != nil {
|
|
t.Fatalf("%s: %s", message, err.Error())
|
|
}
|
|
}
|
|
|
|
// GetCookieByName returns a cookie with the given name
|
|
func GetCookieByName(cookies []*http.Cookie, name string) *http.Cookie {
|
|
var ret *http.Cookie
|
|
|
|
for i := 0; i < len(cookies); i++ {
|
|
if cookies[i].Name == name {
|
|
ret = cookies[i]
|
|
break
|
|
}
|
|
}
|
|
|
|
return ret
|
|
}
|
|
|
|
// CreateMockStripeBackend returns a mock stripe backend that uses
|
|
// the given test server
|
|
func CreateMockStripeBackend(ts *httptest.Server) stripe.Backend {
|
|
stripeMockBackend := stripe.GetBackendWithConfig(
|
|
stripe.APIBackend,
|
|
&stripe.BackendConfig{
|
|
URL: ts.URL,
|
|
HTTPClient: ts.Client(),
|
|
},
|
|
)
|
|
|
|
return stripeMockBackend
|
|
}
|
|
|
|
// MustRespondJSON responds with the JSON-encoding of the given interface. If the encoding
|
|
// fails, the test fails. It is used by test servers.
|
|
func MustRespondJSON(t *testing.T, w http.ResponseWriter, i interface{}, message string) {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
if err := json.NewEncoder(w).Encode(i); err != nil {
|
|
t.Fatal(message)
|
|
}
|
|
}
|