gotosocial/internal/processing/processor_test.go
tobi 2aaec82732
smtp + email confirmation (#285)
* add smtp configuration

* add email confirm + reset templates

* add email sender to testrig

* flesh out the email sender interface

* go fmt

* golint

* update from field with more clarity

* tidy up the email formatting

* fix tests

* add email sender to processor

* tidy client api processing a bit

* further tidying in fromClientAPI

* pin new account to user

* send msg to processor on new account creation

* generate confirm email uri

* remove emailer from account processor again

* add processCreateAccountFromClientAPI

* move emailer accountprocessor => userprocessor

* add email sender to user processor

* SendConfirmEmail function

* add noop email sender

* use noop email sender in tests

* only assemble message if callback is not nil

* use noop email sender if no smtp host is defined

* minify email html before sending

* fix wrong email address

* email confirm test

* fmt

* serve web hndler

* add email confirm handler

* init test log properly on testrig

* log emails that *would* have been sent

* go fmt ./...

* unexport confirm email handler

* updatedAt

* test confirm email function

* don't allow tokens older than 7 days

* change error message a bit

* add basic smtp docs

* add a few more snippets

* typo

* add email sender to outbox tests

* don't use dutch wikipedia link

* don't minify email html
2021-10-31 15:46:23 +01:00

242 lines
8 KiB
Go

/*
GoToSocial
Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org
This program 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.
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
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package processing_test
import (
"bytes"
"context"
"encoding/json"
"io"
"io/ioutil"
"net/http"
"git.iim.gay/grufwub/go-store/kv"
"github.com/go-fed/activity/streams"
"github.com/stretchr/testify/suite"
"github.com/superseriousbusiness/gotosocial/internal/config"
"github.com/superseriousbusiness/gotosocial/internal/db"
"github.com/superseriousbusiness/gotosocial/internal/email"
"github.com/superseriousbusiness/gotosocial/internal/federation"
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
"github.com/superseriousbusiness/gotosocial/internal/media"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
"github.com/superseriousbusiness/gotosocial/internal/processing"
"github.com/superseriousbusiness/gotosocial/internal/timeline"
"github.com/superseriousbusiness/gotosocial/internal/transport"
"github.com/superseriousbusiness/gotosocial/internal/typeutils"
"github.com/superseriousbusiness/gotosocial/testrig"
)
type ProcessingStandardTestSuite struct {
// standard suite interfaces
suite.Suite
config *config.Config
db db.DB
storage *kv.KVStore
typeconverter typeutils.TypeConverter
transportController transport.Controller
federator federation.Federator
oauthServer oauth.Server
mediaHandler media.Handler
timelineManager timeline.Manager
emailSender email.Sender
// standard suite models
testTokens map[string]*gtsmodel.Token
testClients map[string]*gtsmodel.Client
testApplications map[string]*gtsmodel.Application
testUsers map[string]*gtsmodel.User
testAccounts map[string]*gtsmodel.Account
testAttachments map[string]*gtsmodel.MediaAttachment
testStatuses map[string]*gtsmodel.Status
testTags map[string]*gtsmodel.Tag
testMentions map[string]*gtsmodel.Mention
testAutheds map[string]*oauth.Auth
testBlocks map[string]*gtsmodel.Block
testActivities map[string]testrig.ActivityWithSignature
sentHTTPRequests map[string][]byte
processor processing.Processor
}
func (suite *ProcessingStandardTestSuite) SetupSuite() {
suite.testTokens = testrig.NewTestTokens()
suite.testClients = testrig.NewTestClients()
suite.testApplications = testrig.NewTestApplications()
suite.testUsers = testrig.NewTestUsers()
suite.testAccounts = testrig.NewTestAccounts()
suite.testAttachments = testrig.NewTestAttachments()
suite.testStatuses = testrig.NewTestStatuses()
suite.testTags = testrig.NewTestTags()
suite.testMentions = testrig.NewTestMentions()
suite.testAutheds = map[string]*oauth.Auth{
"local_account_1": {
Application: suite.testApplications["local_account_1"],
User: suite.testUsers["local_account_1"],
Account: suite.testAccounts["local_account_1"],
},
}
suite.testActivities = testrig.NewTestActivities(suite.testAccounts)
suite.testBlocks = testrig.NewTestBlocks()
}
func (suite *ProcessingStandardTestSuite) SetupTest() {
testrig.InitTestLog()
suite.config = testrig.NewTestConfig()
suite.db = testrig.NewTestDB()
suite.storage = testrig.NewTestStorage()
suite.typeconverter = testrig.NewTestTypeConverter(suite.db)
// make an http client that stores POST requests it receives into a map,
// and also responds to correctly to dereference requests
suite.sentHTTPRequests = make(map[string][]byte)
httpClient := testrig.NewMockHTTPClient(func(req *http.Request) (*http.Response, error) {
if req.Method == http.MethodPost && req.Body != nil {
requestBytes, err := ioutil.ReadAll(req.Body)
if err != nil {
panic(err)
}
if err := req.Body.Close(); err != nil {
panic(err)
}
suite.sentHTTPRequests[req.URL.String()] = requestBytes
}
if req.URL.String() == suite.testAccounts["remote_account_1"].URI {
// the request is for remote account 1
satan := suite.testAccounts["remote_account_1"]
satanAS, err := suite.typeconverter.AccountToAS(context.Background(), satan)
if err != nil {
panic(err)
}
satanI, err := streams.Serialize(satanAS)
if err != nil {
panic(err)
}
satanJson, err := json.Marshal(satanI)
if err != nil {
panic(err)
}
responseType := "application/activity+json"
reader := bytes.NewReader(satanJson)
readCloser := io.NopCloser(reader)
response := &http.Response{
StatusCode: 200,
Body: readCloser,
ContentLength: int64(len(satanJson)),
Header: http.Header{
"content-type": {responseType},
},
}
return response, nil
}
if req.URL.String() == suite.testAccounts["remote_account_2"].URI {
// the request is for remote account 2
someAccount := suite.testAccounts["remote_account_2"]
someAccountAS, err := suite.typeconverter.AccountToAS(context.Background(), someAccount)
if err != nil {
panic(err)
}
someAccountI, err := streams.Serialize(someAccountAS)
if err != nil {
panic(err)
}
someAccountJson, err := json.Marshal(someAccountI)
if err != nil {
panic(err)
}
responseType := "application/activity+json"
reader := bytes.NewReader(someAccountJson)
readCloser := io.NopCloser(reader)
response := &http.Response{
StatusCode: 200,
Body: readCloser,
ContentLength: int64(len(someAccountJson)),
Header: http.Header{
"content-type": {responseType},
},
}
return response, nil
}
if req.URL.String() == "http://example.org/users/some_user/statuses/afaba698-5740-4e32-a702-af61aa543bc1" {
// the request is for the forwarded message
message := suite.testActivities["forwarded_message"].Activity.GetActivityStreamsObject().At(0).GetActivityStreamsNote()
messageI, err := streams.Serialize(message)
if err != nil {
panic(err)
}
messageJson, err := json.Marshal(messageI)
if err != nil {
panic(err)
}
responseType := "application/activity+json"
reader := bytes.NewReader(messageJson)
readCloser := io.NopCloser(reader)
response := &http.Response{
StatusCode: 200,
Body: readCloser,
ContentLength: int64(len(messageJson)),
Header: http.Header{
"content-type": {responseType},
},
}
return response, nil
}
r := ioutil.NopCloser(bytes.NewReader([]byte{}))
return &http.Response{
StatusCode: 200,
Body: r,
}, nil
})
suite.transportController = testrig.NewTestTransportController(httpClient, suite.db)
suite.federator = testrig.NewTestFederator(suite.db, suite.transportController, suite.storage)
suite.oauthServer = testrig.NewTestOauthServer(suite.db)
suite.mediaHandler = testrig.NewTestMediaHandler(suite.db, suite.storage)
suite.timelineManager = testrig.NewTestTimelineManager(suite.db)
suite.emailSender = testrig.NewEmailSender("../../web/template/", nil)
suite.processor = processing.NewProcessor(suite.config, suite.typeconverter, suite.federator, suite.oauthServer, suite.mediaHandler, suite.storage, suite.timelineManager, suite.db, suite.emailSender)
testrig.StandardDBSetup(suite.db, suite.testAccounts)
testrig.StandardStorageSetup(suite.storage, "../../testrig/media")
if err := suite.processor.Start(context.Background()); err != nil {
panic(err)
}
}
func (suite *ProcessingStandardTestSuite) TearDownTest() {
testrig.StandardDBTeardown(suite.db)
testrig.StandardStorageTeardown(suite.storage)
if err := suite.processor.Stop(); err != nil {
panic(err)
}
}