Avoid a byte copy when delivering a HTTP request
Added tests for the HTTP sig transport.
This commit is contained in:
parent
c3b24964d4
commit
107afb6f17
|
@ -0,0 +1,166 @@
|
|||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: ../../httpsig/httpsig.go
|
||||
|
||||
// Package pub is a generated GoMock package.
|
||||
package pub
|
||||
|
||||
import (
|
||||
crypto "crypto"
|
||||
httpsig "github.com/go-fed/httpsig"
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
http "net/http"
|
||||
reflect "reflect"
|
||||
)
|
||||
|
||||
// MockSigner is a mock of Signer interface
|
||||
type MockSigner struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockSignerMockRecorder
|
||||
}
|
||||
|
||||
// MockSignerMockRecorder is the mock recorder for MockSigner
|
||||
type MockSignerMockRecorder struct {
|
||||
mock *MockSigner
|
||||
}
|
||||
|
||||
// NewMockSigner creates a new mock instance
|
||||
func NewMockSigner(ctrl *gomock.Controller) *MockSigner {
|
||||
mock := &MockSigner{ctrl: ctrl}
|
||||
mock.recorder = &MockSignerMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use
|
||||
func (m *MockSigner) EXPECT() *MockSignerMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// SignRequest mocks base method
|
||||
func (m *MockSigner) SignRequest(pKey crypto.PrivateKey, pubKeyId string, r *http.Request, body []byte) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "SignRequest", pKey, pubKeyId, r, body)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// SignRequest indicates an expected call of SignRequest
|
||||
func (mr *MockSignerMockRecorder) SignRequest(pKey, pubKeyId, r, body interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SignRequest", reflect.TypeOf((*MockSigner)(nil).SignRequest), pKey, pubKeyId, r, body)
|
||||
}
|
||||
|
||||
// SignResponse mocks base method
|
||||
func (m *MockSigner) SignResponse(pKey crypto.PrivateKey, pubKeyId string, r http.ResponseWriter, body []byte) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "SignResponse", pKey, pubKeyId, r, body)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// SignResponse indicates an expected call of SignResponse
|
||||
func (mr *MockSignerMockRecorder) SignResponse(pKey, pubKeyId, r, body interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SignResponse", reflect.TypeOf((*MockSigner)(nil).SignResponse), pKey, pubKeyId, r, body)
|
||||
}
|
||||
|
||||
// MockSSHSigner is a mock of SSHSigner interface
|
||||
type MockSSHSigner struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockSSHSignerMockRecorder
|
||||
}
|
||||
|
||||
// MockSSHSignerMockRecorder is the mock recorder for MockSSHSigner
|
||||
type MockSSHSignerMockRecorder struct {
|
||||
mock *MockSSHSigner
|
||||
}
|
||||
|
||||
// NewMockSSHSigner creates a new mock instance
|
||||
func NewMockSSHSigner(ctrl *gomock.Controller) *MockSSHSigner {
|
||||
mock := &MockSSHSigner{ctrl: ctrl}
|
||||
mock.recorder = &MockSSHSignerMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use
|
||||
func (m *MockSSHSigner) EXPECT() *MockSSHSignerMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// SignRequest mocks base method
|
||||
func (m *MockSSHSigner) SignRequest(pubKeyId string, r *http.Request, body []byte) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "SignRequest", pubKeyId, r, body)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// SignRequest indicates an expected call of SignRequest
|
||||
func (mr *MockSSHSignerMockRecorder) SignRequest(pubKeyId, r, body interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SignRequest", reflect.TypeOf((*MockSSHSigner)(nil).SignRequest), pubKeyId, r, body)
|
||||
}
|
||||
|
||||
// SignResponse mocks base method
|
||||
func (m *MockSSHSigner) SignResponse(pubKeyId string, r http.ResponseWriter, body []byte) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "SignResponse", pubKeyId, r, body)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// SignResponse indicates an expected call of SignResponse
|
||||
func (mr *MockSSHSignerMockRecorder) SignResponse(pubKeyId, r, body interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SignResponse", reflect.TypeOf((*MockSSHSigner)(nil).SignResponse), pubKeyId, r, body)
|
||||
}
|
||||
|
||||
// MockVerifier is a mock of Verifier interface
|
||||
type MockVerifier struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockVerifierMockRecorder
|
||||
}
|
||||
|
||||
// MockVerifierMockRecorder is the mock recorder for MockVerifier
|
||||
type MockVerifierMockRecorder struct {
|
||||
mock *MockVerifier
|
||||
}
|
||||
|
||||
// NewMockVerifier creates a new mock instance
|
||||
func NewMockVerifier(ctrl *gomock.Controller) *MockVerifier {
|
||||
mock := &MockVerifier{ctrl: ctrl}
|
||||
mock.recorder = &MockVerifierMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use
|
||||
func (m *MockVerifier) EXPECT() *MockVerifierMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// KeyId mocks base method
|
||||
func (m *MockVerifier) KeyId() string {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "KeyId")
|
||||
ret0, _ := ret[0].(string)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// KeyId indicates an expected call of KeyId
|
||||
func (mr *MockVerifierMockRecorder) KeyId() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "KeyId", reflect.TypeOf((*MockVerifier)(nil).KeyId))
|
||||
}
|
||||
|
||||
// Verify mocks base method
|
||||
func (m *MockVerifier) Verify(pKey crypto.PublicKey, algo httpsig.Algorithm) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Verify", pKey, algo)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Verify indicates an expected call of Verify
|
||||
func (mr *MockVerifierMockRecorder) Verify(pKey, algo interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Verify", reflect.TypeOf((*MockVerifier)(nil).Verify), pKey, algo)
|
||||
}
|
|
@ -137,10 +137,7 @@ func (h HttpSigTransport) Dereference(c context.Context, iri *url.URL) ([]byte,
|
|||
|
||||
// Deliver sends a POST request with an HTTP Signature.
|
||||
func (h HttpSigTransport) Deliver(c context.Context, b []byte, to *url.URL) error {
|
||||
byteCopy := make([]byte, len(b))
|
||||
copy(byteCopy, b)
|
||||
buf := bytes.NewBuffer(byteCopy)
|
||||
req, err := http.NewRequest("POST", to.String(), buf)
|
||||
req, err := http.NewRequest("POST", to.String(), bytes.NewReader(b))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -0,0 +1,159 @@
|
|||
package pub
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
)
|
||||
|
||||
const (
|
||||
testAppAgent = "testApp"
|
||||
testPubKeyId = "myPubKeyId"
|
||||
)
|
||||
|
||||
var (
|
||||
testPrivKey = []byte("some private key")
|
||||
testRespBody = []byte("test resp body")
|
||||
httpSigSetupFn = func(ctl *gomock.Controller) (t *HttpSigTransport, c *MockClock, hc *MockHttpClient, gs, ps *MockSigner) {
|
||||
c = NewMockClock(ctl)
|
||||
hc = NewMockHttpClient(ctl)
|
||||
gs = NewMockSigner(ctl)
|
||||
ps = NewMockSigner(ctl)
|
||||
t = NewHttpSigTransport(
|
||||
hc,
|
||||
testAppAgent,
|
||||
c,
|
||||
gs,
|
||||
ps,
|
||||
testPubKeyId,
|
||||
testPrivKey)
|
||||
return
|
||||
}
|
||||
)
|
||||
|
||||
func TestHttpSigTransportDereference(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
t.Run("ReturnsErrorWhenHTTPStatusError", func(t *testing.T) {
|
||||
// Setup
|
||||
ctl := gomock.NewController(t)
|
||||
defer ctl.Finish()
|
||||
tp, c, hc, gs, _ := httpSigSetupFn(ctl)
|
||||
resp := &http.Response{}
|
||||
testErr := fmt.Errorf("test error")
|
||||
// Mock
|
||||
c.EXPECT().Now().Return(now())
|
||||
gs.EXPECT().SignRequest(testPrivKey, testPubKeyId, gomock.Any(), nil)
|
||||
hc.EXPECT().Do(gomock.Any()).Return(resp, testErr)
|
||||
// Run & Verify
|
||||
b, err := tp.Dereference(ctx, mustParse(testNoteId1))
|
||||
assertEqual(t, len(b), 0)
|
||||
assertEqual(t, err, testErr)
|
||||
})
|
||||
t.Run("Dereferences", func(t *testing.T) {
|
||||
// Setup
|
||||
ctl := gomock.NewController(t)
|
||||
defer ctl.Finish()
|
||||
tp, c, hc, gs, _ := httpSigSetupFn(ctl)
|
||||
expectReq, err := http.NewRequest("GET", testNoteId1, nil)
|
||||
assertEqual(t, err, nil)
|
||||
expectReq = expectReq.WithContext(ctx)
|
||||
expectReq.Header.Add(acceptHeader, acceptHeaderValue)
|
||||
expectReq.Header.Add("Accept-Charset", "utf-8")
|
||||
expectReq.Header.Add("Date", nowDateHeader())
|
||||
expectReq.Header.Add("User-Agent", fmt.Sprintf("%s %s", testAppAgent, goFedUserAgent()))
|
||||
respR := httptest.NewRecorder()
|
||||
respR.Write(testRespBody)
|
||||
resp := respR.Result()
|
||||
// Mock
|
||||
c.EXPECT().Now().Return(now())
|
||||
gs.EXPECT().SignRequest(testPrivKey, testPubKeyId, expectReq, nil)
|
||||
hc.EXPECT().Do(expectReq).Return(resp, nil)
|
||||
// Run & Verify
|
||||
b, err := tp.Dereference(ctx, mustParse(testNoteId1))
|
||||
assertByteEqual(t, b, testRespBody)
|
||||
assertEqual(t, err, nil)
|
||||
})
|
||||
}
|
||||
|
||||
func TestHttpSigTransportDeliver(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
t.Run("ReturnsErrorWhenHTTPStatusError", func(t *testing.T) {
|
||||
// Setup
|
||||
ctl := gomock.NewController(t)
|
||||
defer ctl.Finish()
|
||||
tp, c, hc, _, ps := httpSigSetupFn(ctl)
|
||||
resp := &http.Response{}
|
||||
testErr := fmt.Errorf("test error")
|
||||
// Mock
|
||||
c.EXPECT().Now().Return(now())
|
||||
ps.EXPECT().SignRequest(testPrivKey, testPubKeyId, gomock.Any(), gomock.Any())
|
||||
hc.EXPECT().Do(gomock.Any()).Return(resp, testErr)
|
||||
// Run & Verify
|
||||
err := tp.Deliver(ctx, testRespBody, mustParse(testNoteId1))
|
||||
assertEqual(t, err, testErr)
|
||||
})
|
||||
t.Run("Delivers", func(t *testing.T) {
|
||||
// Setup
|
||||
ctl := gomock.NewController(t)
|
||||
defer ctl.Finish()
|
||||
tp, c, hc, _, ps := httpSigSetupFn(ctl)
|
||||
// gomock cannot handle http.NewRequest w/ Body differences.
|
||||
respR := httptest.NewRecorder()
|
||||
respR.WriteHeader(http.StatusOK)
|
||||
resp := respR.Result()
|
||||
// Mock
|
||||
c.EXPECT().Now().Return(now())
|
||||
ps.EXPECT().SignRequest(testPrivKey, testPubKeyId, gomock.Any(), testRespBody)
|
||||
hc.EXPECT().Do(gomock.Any()).Return(resp, nil)
|
||||
// Run & Verify
|
||||
err := tp.Deliver(ctx, testRespBody, mustParse(testFederatedActorIRI))
|
||||
assertEqual(t, err, nil)
|
||||
})
|
||||
}
|
||||
|
||||
func TestHttpSigTransportBatchDeliver(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
t.Run("BatchDelivers", func(t *testing.T) {
|
||||
// Setup
|
||||
ctl := gomock.NewController(t)
|
||||
defer ctl.Finish()
|
||||
tp, c, hc, _, ps := httpSigSetupFn(ctl)
|
||||
// gomock cannot handle http.NewRequest w/ Body differences.
|
||||
respR := httptest.NewRecorder()
|
||||
respR.WriteHeader(http.StatusOK)
|
||||
resp := respR.Result()
|
||||
// Mock
|
||||
c.EXPECT().Now().Return(now()).Times(2)
|
||||
ps.EXPECT().SignRequest(testPrivKey, testPubKeyId, gomock.Any(), testRespBody).Times(2)
|
||||
hc.EXPECT().Do(gomock.Any()).Return(resp, nil).Times(2)
|
||||
// Run & Verify
|
||||
err := tp.BatchDeliver(ctx, testRespBody, []*url.URL{mustParse(testFederatedActorIRI), mustParse(testFederatedActorIRI2)})
|
||||
assertEqual(t, err, nil)
|
||||
})
|
||||
t.Run("ReturnsErrorWhenOneErrors", func(t *testing.T) {
|
||||
// Setup
|
||||
ctl := gomock.NewController(t)
|
||||
defer ctl.Finish()
|
||||
tp, c, hc, _, ps := httpSigSetupFn(ctl)
|
||||
// gomock cannot handle http.NewRequest w/ Body differences.
|
||||
respR := httptest.NewRecorder()
|
||||
respR.WriteHeader(http.StatusOK)
|
||||
resp := respR.Result()
|
||||
errResp := &http.Response{}
|
||||
testErr := fmt.Errorf("test error")
|
||||
// Mock
|
||||
c.EXPECT().Now().Return(now()).Times(2)
|
||||
ps.EXPECT().SignRequest(testPrivKey, testPubKeyId, gomock.Any(), testRespBody).Times(2)
|
||||
first := hc.EXPECT().Do(gomock.Any()).Return(resp, nil)
|
||||
hc.EXPECT().Do(gomock.Any()).Return(errResp, testErr).After(first)
|
||||
// Run & Verify
|
||||
err := tp.BatchDeliver(ctx, testRespBody, []*url.URL{mustParse(testFederatedActorIRI), mustParse(testFederatedActorIRI2)})
|
||||
assertNotEqual(t, err, nil)
|
||||
|
||||
})
|
||||
}
|
Loading…
Reference in New Issue