refactor out mocks in separate package

This commit is contained in:
Wouter Groeneveld 2021-04-08 12:16:33 +02:00
parent 2b31d8c016
commit c77ac41e1c
9 changed files with 130 additions and 22 deletions

1
.gitignore vendored
View File

@ -1,5 +1,6 @@
data/*
testdata
# this is the binary
go-jamming

View File

@ -32,7 +32,9 @@ func (s *server) authorizedOnly(h http.HandlerFunc) http.HandlerFunc {
func Start() {
r := mux.NewRouter()
server := &server{router: r, conf: common.Configure()}
config := common.Configure()
config.SetupDataDirs()
server := &server{router: r, conf: config}
server.routes()
http.Handle("/", r)

View File

@ -43,6 +43,7 @@ func HandlePost(conf *common.Config) http.HandlerFunc {
}
recv := &receiver{
restClient: httpClient,
conf: conf,
}
go recv.receive(wm)

View File

@ -3,7 +3,10 @@ package webmention
import (
"fmt"
"os"
"crypto/md5"
"github.com/wgroeneveld/go-jamming/common"
"github.com/wgroeneveld/go-jamming/rest"
"github.com/rs/zerolog/log"
@ -18,10 +21,17 @@ func (wm *webmention) String() string {
return fmt.Sprintf("source: %s, target: %s", wm.source, wm.target)
}
func (wm *webmention) asPath(conf *common.Config) string {
filename := fmt.Sprintf("%x", md5.Sum([]byte("source=" + wm.source + ",target=" + wm.target)))
domain, _ := conf.FetchDomain(wm.target)
return conf.DataPath + "/" + domain + "/" + filename + ".json"
}
// used as a "class" to iject dependencies, just to be able to test. Do NOT like htis.
// Is there a better way? e.g. in validate, I just pass rest.Client as an arg. Not great either.
type receiver struct {
restClient rest.Client
conf *common.Config
}
func (recv *receiver) receive(wm webmention) {
@ -38,7 +48,7 @@ func (recv *receiver) receive(wm webmention) {
}
func (recv *receiver) deletePossibleOlderWebmention(wm webmention) {
os.Remove(wm.asPath(recv.conf))
}
func (recv *receiver) processSourceBody(body string, wm webmention) {

View File

@ -0,0 +1,64 @@
package webmention
import (
"testing"
"os"
"errors"
"github.com/wgroeneveld/go-jamming/common"
"github.com/wgroeneveld/go-jamming/mocks"
)
var conf = &common.Config{
AllowedWebmentionSources: []string {
"jefklakscodex.com",
},
DataPath: "testdata",
}
func TestConvertWebmentionToPath(t *testing.T) {
wm := webmention{
source: "https://brainbaking.com",
target: "https://jefklakscodex.com/articles",
}
result := wm.asPath(conf)
if result != "testdata/jefklakscodex.com/99be66594fdfcf482545fead8e7e4948.json" {
t.Fatalf("md5 hash check failed, got " + result)
}
}
func writeSomethingTo(filename string) {
file, _ := os.Create(filename)
file.WriteString("lolz")
defer file.Close()
}
func TestReceiveTargetDoesNotExistAnymoreDeletesPossiblyOlderWebmention(t *testing.T) {
os.MkdirAll("testdata/jefklakscodex.com", os.ModePerm)
defer os.RemoveAll("testdata")
wm := webmention{
source: "https://brainbaking.com",
target: "https://jefklakscodex.com/articles",
}
filename := wm.asPath(conf)
writeSomethingTo(filename)
client := &mocks.RestClientMock{
GetBodyFunc: func(url string) (string, error) {
return "", errors.New("whoops")
},
}
receiver := &receiver {
conf: conf,
restClient: client,
}
receiver.receive(wm)
if _, err := os.Stat(filename); err == nil {
t.Fatalf("Expected possibly older webmention to be deleted, but it wasn't!")
}
}

View File

@ -16,12 +16,11 @@ func isValidUrl(url string) bool {
}
func isValidDomain(url string, conf *common.Config) bool {
for _, domain := range conf.AllowedWebmentionSources {
if strings.Index(url, domain) != -1 {
return true
}
_, err := conf.FetchDomain(url)
if err != nil {
return false
}
return false
return true
}
func isValidTargetUrl(url string, httpClient rest.Client) bool {

View File

@ -7,6 +7,7 @@ import (
"net/http"
"github.com/wgroeneveld/go-jamming/common"
"github.com/wgroeneveld/go-jamming/mocks"
)
type httpReqMock struct {
@ -114,21 +115,8 @@ func TestValidate(t *testing.T) {
}
}
// neat trick! https://medium.com/@matryer/meet-moq-easily-mock-interfaces-in-go-476444187d10
type restClientMock struct {
GetFunc func(string) (*http.Response, error)
}
// although these are still requied to match the rest.Client interface.
func (m *restClientMock) Get(url string) (*http.Response, error) {
return m.GetFunc(url)
}
func (m *restClientMock) GetBody(url string) (string, error) {
return "", nil
}
func TestIsValidTargetUrlFalseIfGetFails(t *testing.T) {
client := &restClientMock{
client := &mocks.RestClientMock{
GetFunc: func(url string) (*http.Response, error) {
return nil, errors.New("whoops")
},
@ -140,7 +128,7 @@ func TestIsValidTargetUrlFalseIfGetFails(t *testing.T) {
}
func TestIsValidTargetUrlTrueIfGetSucceeds(t *testing.T) {
client := &restClientMock{
client := &mocks.RestClientMock{
GetFunc: func(url string) (*http.Response, error) {
return nil, nil
},

View File

@ -4,16 +4,37 @@ package common
import (
"os"
"strconv"
"errors"
"strings"
"github.com/rs/zerolog/log"
)
type Config struct {
Port int
Token string
UtcOffset int
DataPath string
AllowedWebmentionSources []string
DisallowedWebmentionDomains []string
}
func (c *Config) FetchDomain(url string) (string, error) {
for _, domain := range c.AllowedWebmentionSources {
if strings.Index(url, domain) != -1 {
return domain, nil
}
}
return "", errors.New("no allowed domain found for url " + url)
}
func (c *Config) SetupDataDirs() {
for _, domain := range c.AllowedWebmentionSources {
os.MkdirAll(c.DataPath + "/" + domain, os.ModePerm)
log.Info().Str("allowedDomain", domain).Msg("Configured")
}
}
func Configure() (c *Config) {
portstr := os.Getenv("PORT")
port, err := strconv.Atoi(portstr)
@ -29,6 +50,7 @@ func Configure() (c *Config) {
Port: port,
Token: token,
UtcOffset: 60,
DataPath: "data",
AllowedWebmentionSources: []string{ "brainbaking.com", "jefklakscodex.com" },
DisallowedWebmentionDomains: []string{ "youtube.com" },
}

21
mocks/restclient.go Normal file
View File

@ -0,0 +1,21 @@
package mocks
import (
"net/http"
)
// neat trick! https://medium.com/@matryer/meet-moq-easily-mock-interfaces-in-go-476444187d10
type RestClientMock struct {
GetFunc func(string) (*http.Response, error)
GetBodyFunc func(string) (string, error)
}
// although these are still requied to match the rest.Client interface.
func (m *RestClientMock) Get(url string) (*http.Response, error) {
return m.GetFunc(url)
}
func (m *RestClientMock) GetBody(url string) (string, error) {
return m.GetBodyFunc(url)
}