forked from wgroeneveld/go-jamming
attempt at primitive DI, mock own rest client
This commit is contained in:
parent
95abdcc7f0
commit
f82a581731
|
@ -6,6 +6,7 @@ import (
|
|||
"fmt"
|
||||
|
||||
"github.com/wgroeneveld/go-jamming/common"
|
||||
"github.com/wgroeneveld/go-jamming/rest"
|
||||
)
|
||||
|
||||
func HandleGet(conf *common.Config) http.HandlerFunc {
|
||||
|
@ -21,26 +22,31 @@ func HandlePut(conf *common.Config) http.HandlerFunc {
|
|||
}
|
||||
|
||||
func HandlePost(conf *common.Config) http.HandlerFunc {
|
||||
httpClient := &rest.HttpClient{}
|
||||
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
r.ParseForm()
|
||||
if !validate(r, r.Header, conf) {
|
||||
common.BadRequest(w)
|
||||
rest.BadRequest(w)
|
||||
return
|
||||
}
|
||||
|
||||
target := r.FormValue("target")
|
||||
if !isValidTargetUrl(target) {
|
||||
common.BadRequest(w)
|
||||
if !isValidTargetUrl(target, httpClient) {
|
||||
rest.BadRequest(w)
|
||||
return
|
||||
}
|
||||
|
||||
wm := &webmention{
|
||||
wm := webmention{
|
||||
source: r.FormValue("source"),
|
||||
target: target,
|
||||
}
|
||||
recv := &receiver{
|
||||
restClient: httpClient,
|
||||
}
|
||||
|
||||
go wm.receive()
|
||||
common.Accept(w)
|
||||
go recv.receive(wm)
|
||||
rest.Accept(w)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ package webmention
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/wgroeneveld/go-jamming/common"
|
||||
"github.com/wgroeneveld/go-jamming/rest"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
@ -18,23 +18,29 @@ func (wm *webmention) String() string {
|
|||
return fmt.Sprintf("source: %s, target: %s", wm.source, wm.target)
|
||||
}
|
||||
|
||||
func (wm *webmention) receive() {
|
||||
// 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
|
||||
}
|
||||
|
||||
func (recv *receiver) receive(wm webmention) {
|
||||
log.Info().Str("webmention", wm.String()).Msg("OK: looks valid")
|
||||
body, geterr := common.Get(wm.source)
|
||||
body, geterr := recv.restClient.GetBody(wm.source)
|
||||
|
||||
if geterr != nil {
|
||||
log.Warn().Str("source", wm.source).Msg(" ABORT: invalid url")
|
||||
wm.deletePossibleOlderWebmention()
|
||||
recv.deletePossibleOlderWebmention(wm)
|
||||
return
|
||||
}
|
||||
|
||||
wm.processSourceBody(body)
|
||||
recv.processSourceBody(body, wm)
|
||||
}
|
||||
|
||||
func (wm *webmention) deletePossibleOlderWebmention() {
|
||||
func (recv *receiver) deletePossibleOlderWebmention(wm webmention) {
|
||||
|
||||
}
|
||||
|
||||
func (wm *webmention) processSourceBody(body string) {
|
||||
func (recv *receiver) processSourceBody(body string, wm webmention) {
|
||||
|
||||
}
|
||||
|
|
|
@ -3,9 +3,9 @@ package webmention
|
|||
|
||||
import (
|
||||
"strings"
|
||||
"net/http"
|
||||
|
||||
"github.com/wgroeneveld/go-jamming/common"
|
||||
"github.com/wgroeneveld/go-jamming/rest"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
@ -24,16 +24,8 @@ func isValidDomain(url string, conf *common.Config) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
// great, these are needed to do the structural typing for the tests...
|
||||
type httpReq interface {
|
||||
FormValue(key string) string
|
||||
}
|
||||
type httpHeader interface {
|
||||
Get(key string) string
|
||||
}
|
||||
|
||||
func isValidTargetUrl(url string) bool {
|
||||
_, err := http.Get(url)
|
||||
func isValidTargetUrl(url string, httpClient rest.Client) bool {
|
||||
_, err := httpClient.Get(url)
|
||||
if err != nil {
|
||||
log.Warn().Str("target", url).Msg("Invalid target URL")
|
||||
return false
|
||||
|
@ -41,7 +33,7 @@ func isValidTargetUrl(url string) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
func validate(r httpReq, h httpHeader, conf *common.Config) bool {
|
||||
func validate(r rest.HttpReq, h rest.HttpHeader, conf *common.Config) bool {
|
||||
return h.Get("Content-Type") == "application/x-www-form-urlencoded" &&
|
||||
isValidUrl(r.FormValue("source")) &&
|
||||
isValidUrl(r.FormValue("target")) &&
|
||||
|
|
|
@ -3,6 +3,8 @@ package webmention
|
|||
|
||||
import (
|
||||
"testing"
|
||||
"errors"
|
||||
"net/http"
|
||||
|
||||
"github.com/wgroeneveld/go-jamming/common"
|
||||
)
|
||||
|
@ -110,6 +112,33 @@ func TestValidate(t *testing.T) {
|
|||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
type restClientMock struct {
|
||||
}
|
||||
|
||||
func (client *restClientMock) Get(url string) (*http.Response, error) {
|
||||
if url == "failing" {
|
||||
return nil, errors.New("whoops")
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
func (client *restClientMock) GetBody(url string) (string, error) {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func TestIsValidTargetUrlFalseIfGetFails(t *testing.T) {
|
||||
client := &restClientMock{}
|
||||
result := isValidTargetUrl("failing", client)
|
||||
if result != false {
|
||||
t.Fatalf("expected to fail")
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsValidTargetUrlTrueIfGetSucceeds(t *testing.T) {
|
||||
client := &restClientMock{}
|
||||
result := isValidTargetUrl("valid stuff!", client)
|
||||
if result != true {
|
||||
t.Fatalf("expected to succeed")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
|
||||
package common
|
||||
package rest
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
@ -7,17 +7,16 @@ import (
|
|||
"io/ioutil"
|
||||
)
|
||||
|
||||
func BadRequest(w http.ResponseWriter) {
|
||||
http.Error(w, "400 bad request", http.StatusBadRequest)
|
||||
type Client interface {
|
||||
Get(url string) (*http.Response, error)
|
||||
GetBody(url string) (string, error)
|
||||
}
|
||||
|
||||
func Accept(w http.ResponseWriter) {
|
||||
w.WriteHeader(202)
|
||||
w.Write([]byte("Thanks, bro. Will send these webmentions soon, pinky swear!"))
|
||||
type HttpClient struct {
|
||||
}
|
||||
|
||||
// something like this? https://freshman.tech/snippets/go/http-response-to-string/
|
||||
func Get(url string) (string, error) {
|
||||
func (client *HttpClient) GetBody(url string) (string, error) {
|
||||
resp, geterr := http.Get(url)
|
||||
if geterr != nil {
|
||||
return "", geterr
|
||||
|
@ -35,3 +34,8 @@ func Get(url string) (string, error) {
|
|||
|
||||
return string(body), nil
|
||||
}
|
||||
|
||||
|
||||
func (client *HttpClient) Get(url string) (*http.Response, error) {
|
||||
return http.Get(url)
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
|
||||
package rest
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func BadRequest(w http.ResponseWriter) {
|
||||
http.Error(w, "400 bad request", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
func Accept(w http.ResponseWriter) {
|
||||
w.WriteHeader(202)
|
||||
w.Write([]byte("Thanks, bro. Will send these webmentions soon, pinky swear!"))
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
|
||||
package rest
|
||||
|
||||
// great, these are needed to do the structural typing for the tests...
|
||||
type HttpReq interface {
|
||||
FormValue(key string) string
|
||||
}
|
||||
type HttpHeader interface {
|
||||
Get(key string) string
|
||||
}
|
Loading…
Reference in New Issue