Add tests for the base actor.

Removed old pub tests.
This commit is contained in:
Cory Slep 2019-02-16 20:30:18 +01:00
parent dc16296d74
commit 52bc5fb9a5
9 changed files with 1303 additions and 9018 deletions

View File

@ -158,6 +158,7 @@ func (b *baseActor) PostInbox(c context.Context, w http.ResponseWriter, r *http.
if err != nil {
return true, err
} else if shouldReturn {
w.WriteHeader(http.StatusForbidden)
return true, nil
}
// Begin processing the request, but have not yet applied
@ -192,6 +193,7 @@ func (b *baseActor) PostInbox(c context.Context, w http.ResponseWriter, r *http.
if err != nil {
return true, err
} else if shouldReturn {
w.WriteHeader(http.StatusForbidden)
return true, nil
}
// Post the activity to the actor's inbox and trigger side effects for
@ -234,6 +236,7 @@ func (b *baseActor) GetInbox(c context.Context, w http.ResponseWriter, r *http.R
if err != nil {
return true, err
} else if shouldReturn {
w.WriteHeader(http.StatusForbidden)
return true, nil
}
// Everything is good to begin processing the request.
@ -287,6 +290,7 @@ func (b *baseActor) PostOutbox(c context.Context, w http.ResponseWriter, r *http
if err != nil {
return true, err
} else if shouldReturn {
w.WriteHeader(http.StatusForbidden)
return true, nil
}
// Everything is good to begin processing the request.
@ -356,7 +360,7 @@ func (b *baseActor) PostOutbox(c context.Context, w http.ResponseWriter, r *http
}
}
// Respond to the request with the new Activity's IRI location.
w.Header().Set("Location", activity.GetActivityStreamsId().Get().String())
w.Header().Set(locationHeader, activity.GetActivityStreamsId().Get().String())
w.WriteHeader(http.StatusCreated)
return true, nil
}
@ -374,6 +378,7 @@ func (b *baseActor) GetOutbox(c context.Context, w http.ResponseWriter, r *http.
if err != nil {
return true, err
} else if shouldReturn {
w.WriteHeader(http.StatusForbidden)
return true, nil
}
// Everything is good to begin processing the request.

724
pub/base_actor_test.go Normal file
View File

@ -0,0 +1,724 @@
package pub
import (
"context"
"github.com/go-fed/activity/streams/vocab"
"github.com/golang/mock/gomock"
"io/ioutil"
"net/http"
"net/http/httptest"
"net/url"
"testing"
)
// TestBaseActorSocialProtocol tests the Actor returned with NewCustomActor
// and only having the SocialProtocol enabled.
func TestBaseActorSocialProtocol(t *testing.T) {
// Set up test case
setupData()
ctx := context.Background()
setupFn := func(ctl *gomock.Controller) (delegate *MockDelegateActor, clock *MockClock, a Actor) {
delegate = NewMockDelegateActor(ctl)
clock = NewMockClock(ctl)
a = NewCustomActor(
delegate,
/*enableSocialProtocol=*/ true,
/*enableFederatedProtocol=*/ false,
clock)
return
}
// Run tests
t.Run("PostInboxIgnoresNonActivityPubRequest", func(t *testing.T) {
// Setup
ctl := gomock.NewController(t)
defer ctl.Finish()
_, _, a := setupFn(ctl)
resp := httptest.NewRecorder()
req := toPostInboxRequest(testCreate)
// Run the test
handled, err := a.PostInbox(ctx, resp, req)
// Verify results
assertEqual(t, err, nil)
assertEqual(t, handled, false)
assertEqual(t, len(resp.Result().Header), 0)
})
t.Run("PostInboxNotAllowed", func(t *testing.T) {
// Setup
ctl := gomock.NewController(t)
defer ctl.Finish()
_, _, a := setupFn(ctl)
resp := httptest.NewRecorder()
req := toAPRequest(toPostInboxRequest(testCreate))
// Run the test
handled, err := a.PostInbox(ctx, resp, req)
// Verify results
assertEqual(t, err, nil)
assertEqual(t, handled, true)
assertEqual(t, resp.Code, http.StatusMethodNotAllowed)
})
t.Run("GetInboxIgnoresNonActivityPubRequest", func(t *testing.T) {
// Setup
ctl := gomock.NewController(t)
defer ctl.Finish()
_, _, a := setupFn(ctl)
resp := httptest.NewRecorder()
req := toGetInboxRequest()
// Run the test
handled, err := a.GetInbox(ctx, resp, req)
// Verify results
assertEqual(t, err, nil)
assertEqual(t, handled, false)
assertEqual(t, len(resp.Result().Header), 0)
})
t.Run("GetInboxDeniesIfNotAuthenticated", func(t *testing.T) {
// Setup
ctl := gomock.NewController(t)
defer ctl.Finish()
delegate, _, a := setupFn(ctl)
resp := httptest.NewRecorder()
req := toAPRequest(toGetInboxRequest())
delegate.EXPECT().AuthenticateGetInbox(ctx, resp, req).Return(true, nil)
// Run the test
handled, err := a.GetInbox(ctx, resp, req)
// Verify results
assertEqual(t, err, nil)
assertEqual(t, handled, true)
assertEqual(t, resp.Code, http.StatusForbidden)
})
t.Run("GetInboxRespondsWithDataAndHeaders", func(t *testing.T) {
// Setup
ctl := gomock.NewController(t)
defer ctl.Finish()
delegate, clock, a := setupFn(ctl)
resp := httptest.NewRecorder()
req := toAPRequest(toGetInboxRequest())
delegate.EXPECT().AuthenticateGetInbox(ctx, resp, req).Return(false, nil)
delegate.EXPECT().GetInbox(ctx, req).Return(testOrderedCollectionUniqueElems, nil)
clock.EXPECT().Now().Return(now())
// Run the test
handled, err := a.GetInbox(ctx, resp, req)
// Verify results
assertEqual(t, err, nil)
assertEqual(t, handled, true)
assertEqual(t, resp.Code, http.StatusOK)
respV := resp.Result()
assertEqual(t, respV.Header.Get(contentTypeHeader), "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"")
assertEqual(t, respV.Header.Get(dateHeader), nowDateHeader())
assertNotEqual(t, len(respV.Header.Get(digestHeader)), 0)
b, err := ioutil.ReadAll(respV.Body)
assertEqual(t, err, nil)
assertByteEqual(t, b, []byte(testOrderedCollectionUniqueElemsString))
})
t.Run("GetInboxDeduplicatesData", func(t *testing.T) {
// Setup
ctl := gomock.NewController(t)
defer ctl.Finish()
delegate, clock, a := setupFn(ctl)
resp := httptest.NewRecorder()
req := toAPRequest(toGetInboxRequest())
delegate.EXPECT().AuthenticateGetInbox(ctx, resp, req).Return(false, nil)
delegate.EXPECT().GetInbox(ctx, req).Return(testOrderedCollectionDupedElems, nil)
clock.EXPECT().Now().Return(now())
// Run the test
_, err := a.GetInbox(ctx, resp, req)
// Verify results
assertEqual(t, err, nil)
respV := resp.Result()
b, err := ioutil.ReadAll(respV.Body)
assertEqual(t, err, nil)
assertByteEqual(t, b, []byte(testOrderedCollectionDedupedElemsString))
})
t.Run("PostOutboxIgnoresNonActivityPubRequest", func(t *testing.T) {
// Setup
ctl := gomock.NewController(t)
defer ctl.Finish()
_, _, a := setupFn(ctl)
resp := httptest.NewRecorder()
req := toPostOutboxRequest(testCreateNoId)
// Run the test
handled, err := a.PostOutbox(ctx, resp, req)
// Verify results
assertEqual(t, err, nil)
assertEqual(t, handled, false)
assertEqual(t, len(resp.Result().Header), 0)
})
t.Run("PostOutboxDeniesIfNotAuthenticated", func(t *testing.T) {
// Setup
ctl := gomock.NewController(t)
defer ctl.Finish()
delegate, _, a := setupFn(ctl)
resp := httptest.NewRecorder()
req := toAPRequest(toPostOutboxRequest(testCreateNoId))
delegate.EXPECT().AuthenticatePostOutbox(ctx, resp, req).Return(true, nil)
// Run the test
handled, err := a.PostOutbox(ctx, resp, req)
// Verify results
assertEqual(t, err, nil)
assertEqual(t, handled, true)
assertEqual(t, resp.Code, http.StatusForbidden)
})
t.Run("PostOutboxBadRequestIfUnknownType", func(t *testing.T) {
// Setup
ctl := gomock.NewController(t)
defer ctl.Finish()
delegate, _, a := setupFn(ctl)
resp := httptest.NewRecorder()
req := toAPRequest(toPostOutboxUnknownRequest())
delegate.EXPECT().AuthenticatePostOutbox(ctx, resp, req).Return(false, nil)
// Run the test
handled, err := a.PostOutbox(ctx, resp, req)
// Verify results
assertEqual(t, err, nil)
assertEqual(t, handled, true)
assertEqual(t, resp.Code, http.StatusBadRequest)
})
t.Run("PostOutboxRespondsWithDataAndHeaders", func(t *testing.T) {
// Setup
ctl := gomock.NewController(t)
defer ctl.Finish()
delegate, _, a := setupFn(ctl)
resp := httptest.NewRecorder()
req := toAPRequest(toPostOutboxRequest(testCreateNoId))
delegate.EXPECT().AuthenticatePostOutbox(ctx, resp, req).Return(false, nil)
delegate.EXPECT().AddNewIds(ctx, toDeserializedForm(testCreateNoId)).DoAndReturn(func(c context.Context, activity Activity) error {
activity = withNewId(activity)
return nil
})
delegate.EXPECT().PostOutbox(
ctx,
withNewId(toDeserializedForm(testCreateNoId)),
mustParse(testMyOutboxIRI),
mustSerialize(testCreateNoId),
).Return(true, nil)
// Run the test
handled, err := a.PostOutbox(ctx, resp, req)
// Verify results
assertEqual(t, err, nil)
assertEqual(t, handled, true)
assertEqual(t, resp.Code, http.StatusCreated)
respV := resp.Result()
assertEqual(t, respV.Header.Get(locationHeader), testNewActivityIRI)
})
t.Run("PostOutboxWrapsInCreate", func(t *testing.T) {
// Setup
ctl := gomock.NewController(t)
defer ctl.Finish()
delegate, _, a := setupFn(ctl)
resp := httptest.NewRecorder()
req := toAPRequest(toPostOutboxRequest(testMyNote))
delegate.EXPECT().AuthenticatePostOutbox(ctx, resp, req).Return(false, nil)
delegate.EXPECT().WrapInCreate(ctx, toDeserializedForm(testMyNote), mustParse(testMyOutboxIRI)).DoAndReturn(func(c context.Context, t vocab.Type, u *url.URL) (vocab.ActivityStreamsCreate, error) {
return wrappedInCreate(t), nil
})
delegate.EXPECT().AddNewIds(ctx, wrappedInCreate(toDeserializedForm(testMyNote))).DoAndReturn(func(c context.Context, activity Activity) error {
activity = withNewId(activity)
return nil
})
delegate.EXPECT().PostOutbox(
ctx,
withNewId(wrappedInCreate(toDeserializedForm(testMyNote))),
mustParse(testMyOutboxIRI),
mustSerialize(toDeserializedForm(testMyNote)),
).Return(true, nil)
// Run the test
handled, err := a.PostOutbox(ctx, resp, req)
// Verify results
assertEqual(t, err, nil)
assertEqual(t, handled, true)
assertEqual(t, resp.Code, http.StatusCreated)
})
t.Run("PostOutboxBadRequestForErrObjectRequired", func(t *testing.T) {
// Setup
ctl := gomock.NewController(t)
defer ctl.Finish()
delegate, _, a := setupFn(ctl)
resp := httptest.NewRecorder()
req := toAPRequest(toPostOutboxRequest(testCreateNoId))
delegate.EXPECT().AuthenticatePostOutbox(ctx, resp, req).Return(false, nil)
delegate.EXPECT().AddNewIds(ctx, toDeserializedForm(testCreateNoId)).DoAndReturn(func(c context.Context, activity Activity) error {
activity = withNewId(activity)
return nil
})
delegate.EXPECT().PostOutbox(
ctx,
withNewId(toDeserializedForm(testCreateNoId)),
mustParse(testMyOutboxIRI),
mustSerialize(testCreateNoId),
).Return(true, ErrObjectRequired)
// Run the test
handled, err := a.PostOutbox(ctx, resp, req)
// Verify results
assertEqual(t, err, nil)
assertEqual(t, handled, true)
assertEqual(t, resp.Code, http.StatusBadRequest)
})
t.Run("PostOutboxBadRequestForErrTargetRequired", func(t *testing.T) {
// Setup
ctl := gomock.NewController(t)
defer ctl.Finish()
delegate, _, a := setupFn(ctl)
resp := httptest.NewRecorder()
req := toAPRequest(toPostOutboxRequest(testCreateNoId))
delegate.EXPECT().AuthenticatePostOutbox(ctx, resp, req).Return(false, nil)
delegate.EXPECT().AddNewIds(ctx, toDeserializedForm(testCreateNoId)).DoAndReturn(func(c context.Context, activity Activity) error {
activity = withNewId(activity)
return nil
})
delegate.EXPECT().PostOutbox(
ctx,
withNewId(toDeserializedForm(testCreateNoId)),
mustParse(testMyOutboxIRI),
mustSerialize(testCreateNoId),
).Return(true, ErrTargetRequired)
// Run the test
handled, err := a.PostOutbox(ctx, resp, req)
// Verify results
assertEqual(t, err, nil)
assertEqual(t, handled, true)
assertEqual(t, resp.Code, http.StatusBadRequest)
})
t.Run("GetOutboxIgnoresNonActivityPubRequest", func(t *testing.T) {
// Setup
ctl := gomock.NewController(t)
defer ctl.Finish()
_, _, a := setupFn(ctl)
resp := httptest.NewRecorder()
req := toGetOutboxRequest()
// Run the test
handled, err := a.GetOutbox(ctx, resp, req)
// Verify results
assertEqual(t, err, nil)
assertEqual(t, handled, false)
assertEqual(t, len(resp.Result().Header), 0)
})
t.Run("GetOutboxDeniesIfNotAuthenticated", func(t *testing.T) {
// Setup
ctl := gomock.NewController(t)
defer ctl.Finish()
delegate, _, a := setupFn(ctl)
resp := httptest.NewRecorder()
req := toAPRequest(toGetOutboxRequest())
delegate.EXPECT().AuthenticateGetOutbox(ctx, resp, req).Return(true, nil)
// Run the test
handled, err := a.GetOutbox(ctx, resp, req)
// Verify results
assertEqual(t, err, nil)
assertEqual(t, handled, true)
assertEqual(t, resp.Code, http.StatusForbidden)
})
t.Run("GetOutboxRespondsWithDataAndHeaders", func(t *testing.T) {
// Setup
ctl := gomock.NewController(t)
defer ctl.Finish()
delegate, clock, a := setupFn(ctl)
resp := httptest.NewRecorder()
req := toAPRequest(toGetOutboxRequest())
delegate.EXPECT().AuthenticateGetOutbox(ctx, resp, req).Return(false, nil)
delegate.EXPECT().GetOutbox(ctx, req).Return(testOrderedCollectionUniqueElems, nil)
clock.EXPECT().Now().Return(now())
// Run the test
handled, err := a.GetOutbox(ctx, resp, req)
// Verify results
assertEqual(t, err, nil)
assertEqual(t, handled, true)
assertEqual(t, resp.Code, http.StatusOK)
respV := resp.Result()
assertEqual(t, respV.Header.Get(contentTypeHeader), "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"")
assertEqual(t, respV.Header.Get(dateHeader), nowDateHeader())
assertNotEqual(t, len(respV.Header.Get(digestHeader)), 0)
b, err := ioutil.ReadAll(respV.Body)
assertEqual(t, err, nil)
assertByteEqual(t, b, []byte(testOrderedCollectionUniqueElemsString))
})
}
// TestBaseActorFederatingProtocol tests the Actor returned with
// NewCustomActor and only having the FederatingProtocol enabled.
func TestBaseActorFederatingProtocol(t *testing.T) {
// Set up test case
setupData()
ctx := context.Background()
setupFn := func(ctl *gomock.Controller) (delegate *MockDelegateActor, clock *MockClock, a Actor) {
delegate = NewMockDelegateActor(ctl)
clock = NewMockClock(ctl)
a = NewCustomActor(
delegate,
/*enableSocialProtocol=*/ false,
/*enableFederatedProtocol=*/ true,
clock)
return
}
// Run tests
t.Run("PostInboxIgnoresNonActivityPubRequest", func(t *testing.T) {
// Setup
ctl := gomock.NewController(t)
defer ctl.Finish()
_, _, a := setupFn(ctl)
resp := httptest.NewRecorder()
req := toPostInboxRequest(testCreate)
// Run the test
handled, err := a.PostInbox(ctx, resp, req)
// Verify results
assertEqual(t, err, nil)
assertEqual(t, handled, false)
assertEqual(t, len(resp.Result().Header), 0)
})
t.Run("PostInboxDeniesIfNotAuthenticated", func(t *testing.T) {
// Setup
ctl := gomock.NewController(t)
defer ctl.Finish()
delegate, _, a := setupFn(ctl)
resp := httptest.NewRecorder()
req := toAPRequest(toPostInboxRequest(testCreate))
delegate.EXPECT().AuthenticatePostInbox(ctx, resp, req).Return(true, nil)
// Run the test
handled, err := a.PostInbox(ctx, resp, req)
// Verify results
assertEqual(t, err, nil)
assertEqual(t, handled, true)
assertEqual(t, resp.Code, http.StatusForbidden)
})
t.Run("PostInboxBadRequestIfUnknownType", func(t *testing.T) {
// Setup
ctl := gomock.NewController(t)
defer ctl.Finish()
delegate, _, a := setupFn(ctl)
resp := httptest.NewRecorder()
req := toAPRequest(toPostInboxUnknownRequest())
delegate.EXPECT().AuthenticatePostInbox(ctx, resp, req).Return(false, nil)
// Run the test
handled, err := a.PostInbox(ctx, resp, req)
// Verify results
assertEqual(t, err, nil)
assertEqual(t, handled, true)
assertEqual(t, resp.Code, http.StatusBadRequest)
})
t.Run("PostInboxBadRequestIfActivityHasNoId", func(t *testing.T) {
// Setup
ctl := gomock.NewController(t)
defer ctl.Finish()
delegate, _, a := setupFn(ctl)
resp := httptest.NewRecorder()
req := toAPRequest(toPostOutboxRequest(testCreateNoId))
delegate.EXPECT().AuthenticatePostInbox(ctx, resp, req).Return(false, nil)
// Run the test
handled, err := a.PostInbox(ctx, resp, req)
// Verify results
assertEqual(t, err, nil)
assertEqual(t, handled, true)
assertEqual(t, resp.Code, http.StatusBadRequest)
})
t.Run("PostInboxDeniesIfNotAuthorized", func(t *testing.T) {
// Setup
ctl := gomock.NewController(t)
defer ctl.Finish()
delegate, _, a := setupFn(ctl)
resp := httptest.NewRecorder()
req := toAPRequest(toPostInboxRequest(testCreate))
delegate.EXPECT().AuthenticatePostInbox(ctx, resp, req).Return(false, nil)
delegate.EXPECT().AuthorizePostInbox(ctx, resp, toDeserializedForm(testCreate)).Return(true, nil)
// Run the test
handled, err := a.PostInbox(ctx, resp, req)
// Verify results
assertEqual(t, err, nil)
assertEqual(t, handled, true)
assertEqual(t, resp.Code, http.StatusForbidden)
})
t.Run("PostInboxRespondsWithStatus", func(t *testing.T) {
// Setup
ctl := gomock.NewController(t)
defer ctl.Finish()
delegate, _, a := setupFn(ctl)
resp := httptest.NewRecorder()
req := toAPRequest(toPostInboxRequest(testCreate))
delegate.EXPECT().AuthenticatePostInbox(ctx, resp, req).Return(false, nil)
delegate.EXPECT().AuthorizePostInbox(ctx, resp, toDeserializedForm(testCreate)).Return(false, nil)
delegate.EXPECT().PostInbox(ctx, mustParse(testMyInboxIRI), toDeserializedForm(testCreate)).Return(nil)
delegate.EXPECT().InboxForwarding(ctx, mustParse(testMyInboxIRI), toDeserializedForm(testCreate)).Return(nil)
// Run the test
handled, err := a.PostInbox(ctx, resp, req)
// Verify results
assertEqual(t, err, nil)
assertEqual(t, handled, true)
assertEqual(t, resp.Code, http.StatusOK)
})
t.Run("PostInboxBadRequestForErrObjectRequired", func(t *testing.T) {
// Setup
ctl := gomock.NewController(t)
defer ctl.Finish()
delegate, _, a := setupFn(ctl)
resp := httptest.NewRecorder()
req := toAPRequest(toPostInboxRequest(testCreate))
delegate.EXPECT().AuthenticatePostInbox(ctx, resp, req).Return(false, nil)
delegate.EXPECT().AuthorizePostInbox(ctx, resp, toDeserializedForm(testCreate)).Return(false, nil)
delegate.EXPECT().PostInbox(ctx, mustParse(testMyInboxIRI), toDeserializedForm(testCreate)).Return(ErrObjectRequired)
// Run the test
handled, err := a.PostInbox(ctx, resp, req)
// Verify results
assertEqual(t, err, nil)
assertEqual(t, handled, true)
assertEqual(t, resp.Code, http.StatusBadRequest)
})
t.Run("PostInboxBadRequestForErrTargetRequired", func(t *testing.T) {
// Setup
ctl := gomock.NewController(t)
defer ctl.Finish()
delegate, _, a := setupFn(ctl)
resp := httptest.NewRecorder()
req := toAPRequest(toPostInboxRequest(testCreate))
delegate.EXPECT().AuthenticatePostInbox(ctx, resp, req).Return(false, nil)
delegate.EXPECT().AuthorizePostInbox(ctx, resp, toDeserializedForm(testCreate)).Return(false, nil)
delegate.EXPECT().PostInbox(ctx, mustParse(testMyInboxIRI), toDeserializedForm(testCreate)).Return(ErrTargetRequired)
// Run the test
handled, err := a.PostInbox(ctx, resp, req)
// Verify results
assertEqual(t, err, nil)
assertEqual(t, handled, true)
assertEqual(t, resp.Code, http.StatusBadRequest)
})
t.Run("GetInboxIgnoresNonActivityPubRequest", func(t *testing.T) {
// Setup
ctl := gomock.NewController(t)
defer ctl.Finish()
_, _, a := setupFn(ctl)
resp := httptest.NewRecorder()
req := toGetInboxRequest()
// Run the test
handled, err := a.GetInbox(ctx, resp, req)
// Verify results
assertEqual(t, err, nil)
assertEqual(t, handled, false)
assertEqual(t, len(resp.Result().Header), 0)
})
t.Run("GetInboxDeniesIfNotAuthenticated", func(t *testing.T) {
// Setup
ctl := gomock.NewController(t)
defer ctl.Finish()
delegate, _, a := setupFn(ctl)
resp := httptest.NewRecorder()
req := toAPRequest(toGetInboxRequest())
delegate.EXPECT().AuthenticateGetInbox(ctx, resp, req).Return(true, nil)
// Run the test
handled, err := a.GetInbox(ctx, resp, req)
// Verify results
assertEqual(t, err, nil)
assertEqual(t, handled, true)
assertEqual(t, resp.Code, http.StatusForbidden)
})
t.Run("GetInboxRespondsWithDataAndHeaders", func(t *testing.T) {
// Setup
ctl := gomock.NewController(t)
defer ctl.Finish()
delegate, clock, a := setupFn(ctl)
resp := httptest.NewRecorder()
req := toAPRequest(toGetInboxRequest())
delegate.EXPECT().AuthenticateGetInbox(ctx, resp, req).Return(false, nil)
delegate.EXPECT().GetInbox(ctx, req).Return(testOrderedCollectionUniqueElems, nil)
clock.EXPECT().Now().Return(now())
// Run the test
handled, err := a.GetInbox(ctx, resp, req)
// Verify results
assertEqual(t, err, nil)
assertEqual(t, handled, true)
assertEqual(t, resp.Code, http.StatusOK)
respV := resp.Result()
assertEqual(t, respV.Header.Get(contentTypeHeader), "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"")
assertEqual(t, respV.Header.Get(dateHeader), nowDateHeader())
assertNotEqual(t, len(respV.Header.Get(digestHeader)), 0)
b, err := ioutil.ReadAll(respV.Body)
assertEqual(t, err, nil)
assertByteEqual(t, b, []byte(testOrderedCollectionUniqueElemsString))
})
t.Run("GetInboxDeduplicatesData", func(t *testing.T) {
// Setup
ctl := gomock.NewController(t)
defer ctl.Finish()
delegate, clock, a := setupFn(ctl)
resp := httptest.NewRecorder()
req := toAPRequest(toGetInboxRequest())
delegate.EXPECT().AuthenticateGetInbox(ctx, resp, req).Return(false, nil)
delegate.EXPECT().GetInbox(ctx, req).Return(testOrderedCollectionDupedElems, nil)
clock.EXPECT().Now().Return(now())
// Run the test
_, err := a.GetInbox(ctx, resp, req)
// Verify results
assertEqual(t, err, nil)
respV := resp.Result()
b, err := ioutil.ReadAll(respV.Body)
assertEqual(t, err, nil)
assertByteEqual(t, b, []byte(testOrderedCollectionDedupedElemsString))
})
t.Run("PostOutboxIgnoresNonActivityPubRequest", func(t *testing.T) {
// Setup
ctl := gomock.NewController(t)
defer ctl.Finish()
_, _, a := setupFn(ctl)
resp := httptest.NewRecorder()
req := toPostOutboxRequest(testCreateNoId)
// Run the test
handled, err := a.PostOutbox(ctx, resp, req)
// Verify results
assertEqual(t, err, nil)
assertEqual(t, handled, false)
assertEqual(t, len(resp.Result().Header), 0)
})
t.Run("PostOutboxNotAllowed", func(t *testing.T) {
// Setup
ctl := gomock.NewController(t)
defer ctl.Finish()
_, _, a := setupFn(ctl)
resp := httptest.NewRecorder()
req := toAPRequest(toPostOutboxRequest(testCreateNoId))
// Run the test
handled, err := a.PostOutbox(ctx, resp, req)
// Verify results
assertEqual(t, err, nil)
assertEqual(t, handled, true)
assertEqual(t, resp.Code, http.StatusMethodNotAllowed)
})
t.Run("GetOutboxIgnoresNonActivityPubRequest", func(t *testing.T) {
// Setup
ctl := gomock.NewController(t)
defer ctl.Finish()
_, _, a := setupFn(ctl)
resp := httptest.NewRecorder()
req := toGetOutboxRequest()
// Run the test
handled, err := a.GetOutbox(ctx, resp, req)
// Verify results
assertEqual(t, err, nil)
assertEqual(t, handled, false)
assertEqual(t, len(resp.Result().Header), 0)
})
t.Run("GetOutboxDeniesIfNotAuthenticated", func(t *testing.T) {
// Setup
ctl := gomock.NewController(t)
defer ctl.Finish()
delegate, _, a := setupFn(ctl)
resp := httptest.NewRecorder()
req := toAPRequest(toGetOutboxRequest())
delegate.EXPECT().AuthenticateGetOutbox(ctx, resp, req).Return(true, nil)
// Run the test
handled, err := a.GetOutbox(ctx, resp, req)
// Verify results
assertEqual(t, err, nil)
assertEqual(t, handled, true)
assertEqual(t, resp.Code, http.StatusForbidden)
})
t.Run("GetOutboxRespondsWithDataAndHeaders", func(t *testing.T) {
// Setup
ctl := gomock.NewController(t)
defer ctl.Finish()
delegate, clock, a := setupFn(ctl)
resp := httptest.NewRecorder()
req := toAPRequest(toGetOutboxRequest())
delegate.EXPECT().AuthenticateGetOutbox(ctx, resp, req).Return(false, nil)
delegate.EXPECT().GetOutbox(ctx, req).Return(testOrderedCollectionUniqueElems, nil)
clock.EXPECT().Now().Return(now())
// Run the test
handled, err := a.GetOutbox(ctx, resp, req)
// Verify results
assertEqual(t, err, nil)
assertEqual(t, handled, true)
assertEqual(t, resp.Code, http.StatusOK)
respV := resp.Result()
assertEqual(t, respV.Header.Get(contentTypeHeader), "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"")
assertEqual(t, respV.Header.Get(dateHeader), nowDateHeader())
assertNotEqual(t, len(respV.Header.Get(digestHeader)), 0)
b, err := ioutil.ReadAll(respV.Body)
assertEqual(t, err, nil)
assertByteEqual(t, b, []byte(testOrderedCollectionUniqueElemsString))
})
}
// TestBaseActor tests the Actor returned with NewCustomActor and having both
// the SocialProtocol and FederatingProtocol enabled.
func TestBaseActor(t *testing.T) {
// Set up test case
setupData()
ctx := context.Background()
setupFn := func(ctl *gomock.Controller) (delegate *MockDelegateActor, clock *MockClock, a Actor) {
delegate = NewMockDelegateActor(ctl)
clock = NewMockClock(ctl)
a = NewCustomActor(
delegate,
/*enableSocialProtocol=*/ true,
/*enableFederatedProtocol=*/ true,
clock)
return
}
// Run tests
t.Run("PostInboxRespondsWithStatus", func(t *testing.T) {
// Setup
ctl := gomock.NewController(t)
defer ctl.Finish()
delegate, _, a := setupFn(ctl)
resp := httptest.NewRecorder()
req := toAPRequest(toPostInboxRequest(testCreate))
delegate.EXPECT().AuthenticatePostInbox(ctx, resp, req).Return(false, nil)
delegate.EXPECT().AuthorizePostInbox(ctx, resp, toDeserializedForm(testCreate)).Return(false, nil)
delegate.EXPECT().PostInbox(ctx, mustParse(testMyInboxIRI), toDeserializedForm(testCreate)).Return(nil)
delegate.EXPECT().InboxForwarding(ctx, mustParse(testMyInboxIRI), toDeserializedForm(testCreate)).Return(nil)
// Run the test
handled, err := a.PostInbox(ctx, resp, req)
// Verify results
assertEqual(t, err, nil)
assertEqual(t, handled, true)
assertEqual(t, resp.Code, http.StatusOK)
})
t.Run("PostOutboxRespondsWithDataAndHeaders", func(t *testing.T) {
// Setup
ctl := gomock.NewController(t)
defer ctl.Finish()
delegate, _, a := setupFn(ctl)
resp := httptest.NewRecorder()
req := toAPRequest(toPostOutboxRequest(testCreateNoId))
delegate.EXPECT().AuthenticatePostOutbox(ctx, resp, req).Return(false, nil)
delegate.EXPECT().AddNewIds(ctx, toDeserializedForm(testCreateNoId)).DoAndReturn(func(c context.Context, activity Activity) error {
activity = withNewId(activity)
return nil
})
delegate.EXPECT().PostOutbox(
ctx,
withNewId(toDeserializedForm(testCreateNoId)),
mustParse(testMyOutboxIRI),
mustSerialize(testCreateNoId),
).Return(false, nil)
// Run the test
handled, err := a.PostOutbox(ctx, resp, req)
// Verify results
assertEqual(t, err, nil)
assertEqual(t, handled, true)
assertEqual(t, resp.Code, http.StatusCreated)
respV := resp.Result()
assertEqual(t, respV.Header.Get(locationHeader), testNewActivityIRI)
})
t.Run("PostOutboxFederates", func(t *testing.T) {
// Setup
ctl := gomock.NewController(t)
defer ctl.Finish()
delegate, _, a := setupFn(ctl)
resp := httptest.NewRecorder()
req := toAPRequest(toPostOutboxRequest(testCreateNoId))
delegate.EXPECT().AuthenticatePostOutbox(ctx, resp, req).Return(false, nil)
delegate.EXPECT().AddNewIds(ctx, toDeserializedForm(testCreateNoId)).DoAndReturn(func(c context.Context, activity Activity) error {
activity = withNewId(activity)
return nil
})
delegate.EXPECT().PostOutbox(
ctx,
withNewId(toDeserializedForm(testCreateNoId)),
mustParse(testMyOutboxIRI),
mustSerialize(testCreateNoId),
).Return(true, nil)
delegate.EXPECT().Deliver(ctx, mustParse(testMyOutboxIRI), withNewId(toDeserializedForm(testCreateNoId))).Return(nil)
// Run the test
handled, err := a.PostOutbox(ctx, resp, req)
// Verify results
assertEqual(t, err, nil)
assertEqual(t, handled, true)
assertEqual(t, resp.Code, http.StatusCreated)
respV := resp.Result()
assertEqual(t, respV.Header.Get(locationHeader), testNewActivityIRI)
})
}

File diff suppressed because it is too large Load Diff

View File

@ -1,698 +0,0 @@
package pub
import (
"context"
"crypto"
"github.com/go-fed/activity/vocab"
"github.com/go-fed/httpsig"
"net/http"
"net/http/httptest"
"net/url"
"testing"
)
func TestServeActivityPubObject(t *testing.T) {
tests := []struct {
name string
app *MockApplication
clock *MockClock
input *http.Request
expectedCode int
expectedObjFn func() vocab.Serializer
expectHandled bool
}{
{
name: "unsigned request",
app: &MockApplication{
t: t,
get: func(c context.Context, id *url.URL, rw RWType) (PubObject, error) {
if rw != Read {
t.Fatalf("expected RWType of %v, got %v", Read, rw)
} else if s := id.String(); s != noteURIString {
t.Fatalf("expected %s, got %s", noteURIString, s)
}
testNote = &vocab.Note{}
testNote.SetId(noteIRI)
testNote.AppendNameString(noteName)
testNote.AppendContentString("This is a simple note")
return testNote, nil
},
owns: func(c context.Context, id *url.URL) bool {
if s := id.String(); s != noteURIString {
t.Fatalf("expected %s, got %s", noteURIString, s)
}
return true
},
},
clock: &MockClock{now},
input: ActivityPubRequest(httptest.NewRequest("GET", noteURIString, nil)),
expectedCode: http.StatusOK,
expectedObjFn: func() vocab.Serializer {
testNote = &vocab.Note{}
testNote.SetId(noteIRI)
testNote.AppendNameString(noteName)
testNote.AppendContentString("This is a simple note")
return testNote
},
expectHandled: true,
},
{
name: "http signature request",
input: Sign(ActivityPubRequest(httptest.NewRequest("GET", noteURIString, nil))),
app: &MockApplication{
t: t,
getPublicKey: func(c context.Context, publicKeyId string) (crypto.PublicKey, httpsig.Algorithm, *url.URL, error) {
if publicKeyId != testPublicKeyId {
t.Fatalf("expected %s, got %s", testPublicKeyId, publicKeyId)
}
return testPrivateKey.Public(), httpsig.RSA_SHA256, samIRI, nil
},
getAsVerifiedUser: func(c context.Context, id, user *url.URL, rw RWType) (PubObject, error) {
if rw != Read {
t.Fatalf("expected RWType of %v, got %v", Read, rw)
} else if s := id.String(); s != noteURIString {
t.Fatalf("expected %s, got %s", noteURIString, s)
} else if u := user.String(); u != samIRIString {
t.Fatalf("expected %s, got %s", samIRIString, u)
}
testNote = &vocab.Note{}
testNote.SetId(noteIRI)
testNote.AppendNameString(noteName)
testNote.AppendContentString("This is a simple note")
return testNote, nil
},
owns: func(c context.Context, id *url.URL) bool {
if s := id.String(); s != noteURIString {
t.Fatalf("expected %s, got %s", noteURIString, s)
}
return true
},
},
clock: &MockClock{now},
expectedCode: http.StatusOK,
expectedObjFn: func() vocab.Serializer {
testNote = &vocab.Note{}
testNote.SetId(noteIRI)
testNote.AppendNameString(noteName)
testNote.AppendContentString("This is a simple note")
return testNote
},
expectHandled: true,
},
{
name: "not owned",
input: ActivityPubRequest(httptest.NewRequest("GET", noteURIString, nil)),
app: &MockApplication{
t: t,
owns: func(c context.Context, id *url.URL) bool {
if s := id.String(); s != noteURIString {
t.Fatalf("expected %s, got %s", noteURIString, s)
}
return false
},
},
expectedCode: http.StatusNotFound,
expectHandled: true,
},
{
name: "not activitypub get",
input: httptest.NewRequest("GET", noteURIString, nil),
expectHandled: false,
},
{
name: "bad http signature",
input: BadSignature(ActivityPubRequest(httptest.NewRequest("GET", noteURIString, nil))),
app: &MockApplication{
t: t,
getPublicKey: func(c context.Context, publicKeyId string) (crypto.PublicKey, httpsig.Algorithm, *url.URL, error) {
if publicKeyId != testPublicKeyId {
t.Fatalf("expected %s, got %s", testPublicKeyId, publicKeyId)
}
return testPrivateKey.Public(), httpsig.RSA_SHA256, samIRI, nil
},
owns: func(c context.Context, id *url.URL) bool {
if s := id.String(); s != noteURIString {
t.Fatalf("expected %s, got %s", noteURIString, s)
}
return true
},
},
expectedCode: http.StatusForbidden,
expectHandled: true,
},
{
name: "remove bto & bcc",
app: &MockApplication{
t: t,
get: func(c context.Context, id *url.URL, rw RWType) (PubObject, error) {
if rw != Read {
t.Fatalf("expected RWType of %v, got %v", Read, rw)
} else if s := id.String(); s != noteURIString {
t.Fatalf("expected %s, got %s", noteURIString, s)
}
testNote = &vocab.Note{}
testNote.SetId(noteIRI)
testNote.AppendNameString(noteName)
testNote.AppendContentString("This is a simple note")
testNote.AppendBtoIRI(samIRI)
testNote.AppendBccIRI(sallyIRI)
return testNote, nil
},
owns: func(c context.Context, id *url.URL) bool {
if s := id.String(); s != noteURIString {
t.Fatalf("expected %s, got %s", noteURIString, s)
}
return true
},
},
clock: &MockClock{now},
input: ActivityPubRequest(httptest.NewRequest("GET", noteURIString, nil)),
expectedCode: http.StatusOK,
expectedObjFn: func() vocab.Serializer {
testNote = &vocab.Note{}
testNote.SetId(noteIRI)
testNote.AppendNameString(noteName)
testNote.AppendContentString("This is a simple note")
return testNote
},
expectHandled: true,
},
{
name: "tombstone is status gone",
app: &MockApplication{
t: t,
get: func(c context.Context, id *url.URL, rw RWType) (PubObject, error) {
if rw != Read {
t.Fatalf("expected RWType of %v, got %v", Read, rw)
} else if s := id.String(); s != testNewIRIString {
t.Fatalf("expected %s, got %s", testNewIRIString, s)
}
tombstone := &vocab.Tombstone{}
tombstone.SetId(testNewIRI)
return tombstone, nil
},
owns: func(c context.Context, id *url.URL) bool {
if s := id.String(); s != testNewIRIString {
t.Fatalf("expected %s, got %s", testNewIRIString, s)
}
return true
},
},
clock: &MockClock{now},
input: ActivityPubRequest(httptest.NewRequest("GET", testNewIRIString, nil)),
expectedCode: http.StatusGone,
expectedObjFn: func() vocab.Serializer {
tombstone := &vocab.Tombstone{}
tombstone.SetId(testNewIRI)
return tombstone
},
expectHandled: true,
},
}
for _, test := range tests {
t.Logf("Running table test case %q", test.name)
resp := httptest.NewRecorder()
fnUnderTest := ServeActivityPubObject(test.app, test.clock)
handled, err := fnUnderTest(context.Background(), resp, test.input)
if err != nil {
t.Fatalf("(%q) %s", test.name, err)
} else if handled != test.expectHandled {
t.Fatalf("(%q) expected %v, got %v", test.name, test.expectHandled, handled)
} else if test.expectedCode != 0 {
if resp.Code != test.expectedCode {
t.Fatalf("(%q) expected %d, got %d", test.name, test.expectedCode, resp.Code)
}
} else if test.expectedObjFn != nil {
if err := VocabEquals(resp.Body, test.expectedObjFn()); err != nil {
t.Fatalf("(%q) unexpected object: %s", test.name, err)
}
}
}
}
func TestServeActivityPubObjectWithVerificationMethod(t *testing.T) {
tests := []struct {
name string
app *MockApplication
clock *MockClock
verifier *MockSocialAPIVerifier
input *http.Request
expectedCode int
expectedObjFn func() vocab.Serializer
expectHandled bool
}{
{
name: "unsigned request",
app: &MockApplication{
t: t,
get: func(c context.Context, id *url.URL, rw RWType) (PubObject, error) {
if rw != Read {
t.Fatalf("expected RWType of %v, got %v", Read, rw)
} else if s := id.String(); s != noteURIString {
t.Fatalf("expected %s, got %s", noteURIString, s)
}
testNote = &vocab.Note{}
testNote.SetId(noteIRI)
testNote.AppendNameString(noteName)
testNote.AppendContentString("This is a simple note")
return testNote, nil
},
owns: func(c context.Context, id *url.URL) bool {
if s := id.String(); s != noteURIString {
t.Fatalf("expected %s, got %s", noteURIString, s)
}
return true
},
},
clock: &MockClock{now},
input: ActivityPubRequest(httptest.NewRequest("GET", noteURIString, nil)),
expectedCode: http.StatusOK,
expectedObjFn: func() vocab.Serializer {
testNote = &vocab.Note{}
testNote.SetId(noteIRI)
testNote.AppendNameString(noteName)
testNote.AppendContentString("This is a simple note")
return testNote
},
expectHandled: true,
},
{
name: "http signature request",
input: Sign(ActivityPubRequest(httptest.NewRequest("GET", noteURIString, nil))),
app: &MockApplication{
t: t,
getPublicKey: func(c context.Context, publicKeyId string) (crypto.PublicKey, httpsig.Algorithm, *url.URL, error) {
if publicKeyId != testPublicKeyId {
t.Fatalf("expected %s, got %s", testPublicKeyId, publicKeyId)
}
return testPrivateKey.Public(), httpsig.RSA_SHA256, samIRI, nil
},
getAsVerifiedUser: func(c context.Context, id, user *url.URL, rw RWType) (PubObject, error) {
if rw != Read {
t.Fatalf("expected RWType of %v, got %v", Read, rw)
} else if s := id.String(); s != noteURIString {
t.Fatalf("expected %s, got %s", noteURIString, s)
} else if u := user.String(); u != samIRIString {
t.Fatalf("expected %s, got %s", samIRIString, u)
}
testNote = &vocab.Note{}
testNote.SetId(noteIRI)
testNote.AppendNameString(noteName)
testNote.AppendContentString("This is a simple note")
return testNote, nil
},
owns: func(c context.Context, id *url.URL) bool {
if s := id.String(); s != noteURIString {
t.Fatalf("expected %s, got %s", noteURIString, s)
}
return true
},
},
clock: &MockClock{now},
expectedCode: http.StatusOK,
expectedObjFn: func() vocab.Serializer {
testNote = &vocab.Note{}
testNote.SetId(noteIRI)
testNote.AppendNameString(noteName)
testNote.AppendContentString("This is a simple note")
return testNote
},
expectHandled: true,
},
{
name: "not owned",
input: ActivityPubRequest(httptest.NewRequest("GET", noteURIString, nil)),
app: &MockApplication{
t: t,
owns: func(c context.Context, id *url.URL) bool {
if s := id.String(); s != noteURIString {
t.Fatalf("expected %s, got %s", noteURIString, s)
}
return false
},
},
expectedCode: http.StatusNotFound,
expectHandled: true,
},
{
name: "not activitypub get",
input: httptest.NewRequest("GET", noteURIString, nil),
expectHandled: false,
},
{
name: "bad http signature",
input: BadSignature(ActivityPubRequest(httptest.NewRequest("GET", noteURIString, nil))),
app: &MockApplication{
t: t,
getPublicKey: func(c context.Context, publicKeyId string) (crypto.PublicKey, httpsig.Algorithm, *url.URL, error) {
if publicKeyId != testPublicKeyId {
t.Fatalf("expected %s, got %s", testPublicKeyId, publicKeyId)
}
return testPrivateKey.Public(), httpsig.RSA_SHA256, samIRI, nil
},
owns: func(c context.Context, id *url.URL) bool {
if s := id.String(); s != noteURIString {
t.Fatalf("expected %s, got %s", noteURIString, s)
}
return true
},
},
expectedCode: http.StatusForbidden,
expectHandled: true,
},
{
name: "unsigned request passes verifier",
app: &MockApplication{
t: t,
getAsVerifiedUser: func(c context.Context, id, user *url.URL, rw RWType) (PubObject, error) {
if rw != Read {
t.Fatalf("expected RWType of %v, got %v", Read, rw)
} else if s := id.String(); s != noteURIString {
t.Fatalf("expected %s, got %s", noteURIString, s)
} else if u := user.String(); u != samIRIString {
t.Fatalf("expected %s, got %s", samIRIString, u)
}
testNote = &vocab.Note{}
testNote.SetId(noteIRI)
testNote.AppendNameString(noteName)
testNote.AppendContentString("This is a simple note")
return testNote, nil
},
owns: func(c context.Context, id *url.URL) bool {
if s := id.String(); s != noteURIString {
t.Fatalf("expected %s, got %s", noteURIString, s)
}
return true
},
},
clock: &MockClock{now},
verifier: &MockSocialAPIVerifier{
t: t,
verify: func(r *http.Request) (*url.URL, bool, bool, error) {
return samIRI, true, true, nil
},
},
input: ActivityPubRequest(httptest.NewRequest("GET", noteURIString, nil)),
expectedCode: http.StatusOK,
expectedObjFn: func() vocab.Serializer {
testNote = &vocab.Note{}
testNote.SetId(noteIRI)
testNote.AppendNameString(noteName)
testNote.AppendContentString("This is a simple note")
return testNote
},
expectHandled: true,
},
{
name: "http signature request passes verifier",
input: Sign(ActivityPubRequest(httptest.NewRequest("GET", noteURIString, nil))),
app: &MockApplication{
t: t,
getAsVerifiedUser: func(c context.Context, id, user *url.URL, rw RWType) (PubObject, error) {
if rw != Read {
t.Fatalf("expected RWType of %v, got %v", Read, rw)
} else if s := id.String(); s != noteURIString {
t.Fatalf("expected %s, got %s", noteURIString, s)
} else if u := user.String(); u != samIRIString {
t.Fatalf("expected %s, got %s", samIRIString, u)
}
testNote = &vocab.Note{}
testNote.SetId(noteIRI)
testNote.AppendNameString(noteName)
testNote.AppendContentString("This is a simple note")
return testNote, nil
},
owns: func(c context.Context, id *url.URL) bool {
if s := id.String(); s != noteURIString {
t.Fatalf("expected %s, got %s", noteURIString, s)
}
return true
},
},
clock: &MockClock{now},
verifier: &MockSocialAPIVerifier{
t: t,
verify: func(r *http.Request) (*url.URL, bool, bool, error) {
return samIRI, true, true, nil
},
},
expectedCode: http.StatusOK,
expectedObjFn: func() vocab.Serializer {
testNote = &vocab.Note{}
testNote.SetId(noteIRI)
testNote.AppendNameString(noteName)
testNote.AppendContentString("This is a simple note")
return testNote
},
expectHandled: true,
},
{
name: "verifier authed unauthz",
app: &MockApplication{
t: t,
owns: func(c context.Context, id *url.URL) bool {
if s := id.String(); s != noteURIString {
t.Fatalf("expected %s, got %s", noteURIString, s)
}
return true
},
},
clock: &MockClock{now},
verifier: &MockSocialAPIVerifier{
t: t,
verify: func(r *http.Request) (*url.URL, bool, bool, error) {
return samIRI, true, false, nil
},
},
input: ActivityPubRequest(httptest.NewRequest("GET", noteURIString, nil)),
expectedCode: http.StatusForbidden,
expectHandled: true,
},
{
name: "verifier unauthed unauthz",
app: &MockApplication{
t: t,
owns: func(c context.Context, id *url.URL) bool {
if s := id.String(); s != noteURIString {
t.Fatalf("expected %s, got %s", noteURIString, s)
}
return true
},
},
clock: &MockClock{now},
verifier: &MockSocialAPIVerifier{
t: t,
verify: func(r *http.Request) (*url.URL, bool, bool, error) {
return nil, false, false, nil
},
},
input: ActivityPubRequest(httptest.NewRequest("GET", noteURIString, nil)),
expectedCode: http.StatusBadRequest,
expectHandled: true,
},
{
name: "verifier unauthed authz unsigned fails",
app: &MockApplication{
t: t,
owns: func(c context.Context, id *url.URL) bool {
if s := id.String(); s != noteURIString {
t.Fatalf("expected %s, got %s", noteURIString, s)
}
return true
},
},
clock: &MockClock{now},
verifier: &MockSocialAPIVerifier{
t: t,
verify: func(r *http.Request) (*url.URL, bool, bool, error) {
return nil, false, true, nil
},
},
input: ActivityPubRequest(httptest.NewRequest("GET", noteURIString, nil)),
expectedCode: http.StatusBadRequest,
expectHandled: true,
},
{
name: "verifier unauthed authz signed success",
input: Sign(ActivityPubRequest(httptest.NewRequest("GET", noteURIString, nil))),
app: &MockApplication{
t: t,
getPublicKey: func(c context.Context, publicKeyId string) (crypto.PublicKey, httpsig.Algorithm, *url.URL, error) {
if publicKeyId != testPublicKeyId {
t.Fatalf("expected %s, got %s", testPublicKeyId, publicKeyId)
}
return testPrivateKey.Public(), httpsig.RSA_SHA256, samIRI, nil
},
getAsVerifiedUser: func(c context.Context, id, user *url.URL, rw RWType) (PubObject, error) {
if rw != Read {
t.Fatalf("expected RWType of %v, got %v", Read, rw)
} else if s := id.String(); s != noteURIString {
t.Fatalf("expected %s, got %s", noteURIString, s)
} else if u := user.String(); u != samIRIString {
t.Fatalf("expected %s, got %s", samIRIString, u)
}
testNote = &vocab.Note{}
testNote.SetId(noteIRI)
testNote.AppendNameString(noteName)
testNote.AppendContentString("This is a simple note")
return testNote, nil
},
owns: func(c context.Context, id *url.URL) bool {
if s := id.String(); s != noteURIString {
t.Fatalf("expected %s, got %s", noteURIString, s)
}
return true
},
},
clock: &MockClock{now},
verifier: &MockSocialAPIVerifier{
t: t,
verify: func(r *http.Request) (*url.URL, bool, bool, error) {
return nil, false, true, nil
},
},
expectedCode: http.StatusOK,
expectedObjFn: func() vocab.Serializer {
testNote = &vocab.Note{}
testNote.SetId(noteIRI)
testNote.AppendNameString(noteName)
testNote.AppendContentString("This is a simple note")
return testNote
},
expectHandled: true,
},
{
name: "verifier unauthed authz unsigned fails with bad impl returning user",
app: &MockApplication{
t: t,
owns: func(c context.Context, id *url.URL) bool {
if s := id.String(); s != noteURIString {
t.Fatalf("expected %s, got %s", noteURIString, s)
}
return true
},
},
clock: &MockClock{now},
verifier: &MockSocialAPIVerifier{
t: t,
verify: func(r *http.Request) (*url.URL, bool, bool, error) {
return samIRI, false, true, nil
},
},
input: ActivityPubRequest(httptest.NewRequest("GET", noteURIString, nil)),
expectedCode: http.StatusBadRequest,
expectHandled: true,
},
{
name: "remove bto & bcc",
app: &MockApplication{
t: t,
getPublicKey: func(c context.Context, publicKeyId string) (crypto.PublicKey, httpsig.Algorithm, *url.URL, error) {
if publicKeyId != testPublicKeyId {
t.Fatalf("expected %s, got %s", testPublicKeyId, publicKeyId)
}
return testPrivateKey.Public(), httpsig.RSA_SHA256, samIRI, nil
},
getAsVerifiedUser: func(c context.Context, id, user *url.URL, rw RWType) (PubObject, error) {
if rw != Read {
t.Fatalf("expected RWType of %v, got %v", Read, rw)
} else if s := id.String(); s != noteURIString {
t.Fatalf("expected %s, got %s", noteURIString, s)
} else if u := user.String(); u != samIRIString {
t.Fatalf("expected %s, got %s", samIRIString, u)
}
testNote = &vocab.Note{}
testNote.SetId(noteIRI)
testNote.AppendNameString(noteName)
testNote.AppendContentString("This is a simple note")
testNote.AppendBtoIRI(samIRI)
testNote.AppendBccIRI(sallyIRI)
return testNote, nil
},
owns: func(c context.Context, id *url.URL) bool {
if s := id.String(); s != noteURIString {
t.Fatalf("expected %s, got %s", noteURIString, s)
}
return true
},
},
clock: &MockClock{now},
input: Sign(ActivityPubRequest(httptest.NewRequest("GET", noteURIString, nil))),
expectedCode: http.StatusOK,
expectedObjFn: func() vocab.Serializer {
testNote = &vocab.Note{}
testNote.SetId(noteIRI)
testNote.AppendNameString(noteName)
testNote.AppendContentString("This is a simple note")
return testNote
},
expectHandled: true,
},
{
name: "tombstone is status gone",
app: &MockApplication{
t: t,
getPublicKey: func(c context.Context, publicKeyId string) (crypto.PublicKey, httpsig.Algorithm, *url.URL, error) {
if publicKeyId != testPublicKeyId {
t.Fatalf("expected %s, got %s", testPublicKeyId, publicKeyId)
}
return testPrivateKey.Public(), httpsig.RSA_SHA256, samIRI, nil
},
getAsVerifiedUser: func(c context.Context, id, user *url.URL, rw RWType) (PubObject, error) {
if rw != Read {
t.Fatalf("expected RWType of %v, got %v", Read, rw)
} else if s := id.String(); s != testNewIRIString {
t.Fatalf("expected %s, got %s", testNewIRIString, s)
} else if u := user.String(); u != samIRIString {
t.Fatalf("expected %s, got %s", samIRIString, u)
}
tombstone := &vocab.Tombstone{}
tombstone.SetId(testNewIRI)
return tombstone, nil
},
owns: func(c context.Context, id *url.URL) bool {
if s := id.String(); s != testNewIRIString {
t.Fatalf("expected %s, got %s", testNewIRIString, s)
}
return true
},
},
clock: &MockClock{now},
input: Sign(ActivityPubRequest(httptest.NewRequest("GET", testNewIRIString, nil))),
expectedCode: http.StatusGone,
expectedObjFn: func() vocab.Serializer {
tombstone := &vocab.Tombstone{}
tombstone.SetId(testNewIRI)
return tombstone
},
expectHandled: true,
},
}
for _, test := range tests {
t.Logf("Running table test case %q", test.name)
resp := httptest.NewRecorder()
var fnUnderTest HandlerFunc
if test.verifier != nil {
verifierFn := func(c context.Context) SocialAPIVerifier {
return test.verifier
}
fnUnderTest = ServeActivityPubObjectWithVerificationMethod(test.app, test.clock, verifierFn)
} else {
fnUnderTest = ServeActivityPubObjectWithVerificationMethod(test.app, test.clock, nil)
}
handled, err := fnUnderTest(context.Background(), resp, test.input)
if err != nil {
t.Fatalf("(%q) %s", test.name, err)
} else if handled != test.expectHandled {
t.Fatalf("(%q) expected %v, got %v", test.name, test.expectHandled, handled)
} else if test.expectedCode != 0 {
if resp.Code != test.expectedCode {
t.Fatalf("(%q) expected %d, got %d", test.name, test.expectedCode, resp.Code)
}
} else if test.expectedObjFn != nil {
if err := VocabEquals(resp.Body, test.expectedObjFn()); err != nil {
t.Fatalf("(%q) unexpected object: %s", test.name, err)
}
}
}
}

47
pub/mock_clock_test.go Normal file
View File

@ -0,0 +1,47 @@
package pub
// Code generated by MockGen. DO NOT EDIT.
// Source: clock.go
import (
gomock "github.com/golang/mock/gomock"
reflect "reflect"
time "time"
)
// MockClock is a mock of Clock interface
type MockClock struct {
ctrl *gomock.Controller
recorder *MockClockMockRecorder
}
// MockClockMockRecorder is the mock recorder for MockClock
type MockClockMockRecorder struct {
mock *MockClock
}
// NewMockClock creates a new mock instance
func NewMockClock(ctrl *gomock.Controller) *MockClock {
mock := &MockClock{ctrl: ctrl}
mock.recorder = &MockClockMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use
func (m *MockClock) EXPECT() *MockClockMockRecorder {
return m.recorder
}
// Now mocks base method
func (m *MockClock) Now() time.Time {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Now")
ret0, _ := ret[0].(time.Time)
return ret0
}
// Now indicates an expected call of Now
func (mr *MockClockMockRecorder) Now() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Now", reflect.TypeOf((*MockClock)(nil).Now))
}

View File

@ -0,0 +1,227 @@
package pub
// Code generated by MockGen. DO NOT EDIT.
// Source: delegate_actor.go
import (
context "context"
vocab "github.com/go-fed/activity/streams/vocab"
gomock "github.com/golang/mock/gomock"
http "net/http"
url "net/url"
reflect "reflect"
)
// MockDelegateActor is a mock of DelegateActor interface
type MockDelegateActor struct {
ctrl *gomock.Controller
recorder *MockDelegateActorMockRecorder
}
// MockDelegateActorMockRecorder is the mock recorder for MockDelegateActor
type MockDelegateActorMockRecorder struct {
mock *MockDelegateActor
}
// NewMockDelegateActor creates a new mock instance
func NewMockDelegateActor(ctrl *gomock.Controller) *MockDelegateActor {
mock := &MockDelegateActor{ctrl: ctrl}
mock.recorder = &MockDelegateActorMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use
func (m *MockDelegateActor) EXPECT() *MockDelegateActorMockRecorder {
return m.recorder
}
// AuthenticatePostInbox mocks base method
func (m *MockDelegateActor) AuthenticatePostInbox(c context.Context, w http.ResponseWriter, r *http.Request) (bool, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "AuthenticatePostInbox", c, w, r)
ret0, _ := ret[0].(bool)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// AuthenticatePostInbox indicates an expected call of AuthenticatePostInbox
func (mr *MockDelegateActorMockRecorder) AuthenticatePostInbox(c, w, r interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AuthenticatePostInbox", reflect.TypeOf((*MockDelegateActor)(nil).AuthenticatePostInbox), c, w, r)
}
// AuthenticateGetInbox mocks base method
func (m *MockDelegateActor) AuthenticateGetInbox(c context.Context, w http.ResponseWriter, r *http.Request) (bool, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "AuthenticateGetInbox", c, w, r)
ret0, _ := ret[0].(bool)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// AuthenticateGetInbox indicates an expected call of AuthenticateGetInbox
func (mr *MockDelegateActorMockRecorder) AuthenticateGetInbox(c, w, r interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AuthenticateGetInbox", reflect.TypeOf((*MockDelegateActor)(nil).AuthenticateGetInbox), c, w, r)
}
// AuthorizePostInbox mocks base method
func (m *MockDelegateActor) AuthorizePostInbox(c context.Context, w http.ResponseWriter, activity Activity) (bool, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "AuthorizePostInbox", c, w, activity)
ret0, _ := ret[0].(bool)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// AuthorizePostInbox indicates an expected call of AuthorizePostInbox
func (mr *MockDelegateActorMockRecorder) AuthorizePostInbox(c, w, activity interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AuthorizePostInbox", reflect.TypeOf((*MockDelegateActor)(nil).AuthorizePostInbox), c, w, activity)
}
// PostInbox mocks base method
func (m *MockDelegateActor) PostInbox(c context.Context, inboxIRI *url.URL, activity Activity) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "PostInbox", c, inboxIRI, activity)
ret0, _ := ret[0].(error)
return ret0
}
// PostInbox indicates an expected call of PostInbox
func (mr *MockDelegateActorMockRecorder) PostInbox(c, inboxIRI, activity interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PostInbox", reflect.TypeOf((*MockDelegateActor)(nil).PostInbox), c, inboxIRI, activity)
}
// InboxForwarding mocks base method
func (m *MockDelegateActor) InboxForwarding(c context.Context, inboxIRI *url.URL, activity Activity) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "InboxForwarding", c, inboxIRI, activity)
ret0, _ := ret[0].(error)
return ret0
}
// InboxForwarding indicates an expected call of InboxForwarding
func (mr *MockDelegateActorMockRecorder) InboxForwarding(c, inboxIRI, activity interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InboxForwarding", reflect.TypeOf((*MockDelegateActor)(nil).InboxForwarding), c, inboxIRI, activity)
}
// PostOutbox mocks base method
func (m *MockDelegateActor) PostOutbox(c context.Context, a Activity, outboxIRI *url.URL, rawJSON map[string]interface{}) (bool, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "PostOutbox", c, a, outboxIRI, rawJSON)
ret0, _ := ret[0].(bool)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// PostOutbox indicates an expected call of PostOutbox
func (mr *MockDelegateActorMockRecorder) PostOutbox(c, a, outboxIRI, rawJSON interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PostOutbox", reflect.TypeOf((*MockDelegateActor)(nil).PostOutbox), c, a, outboxIRI, rawJSON)
}
// AddNewIds mocks base method
func (m *MockDelegateActor) AddNewIds(c context.Context, a Activity) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "AddNewIds", c, a)
ret0, _ := ret[0].(error)
return ret0
}
// AddNewIds indicates an expected call of AddNewIds
func (mr *MockDelegateActorMockRecorder) AddNewIds(c, a interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddNewIds", reflect.TypeOf((*MockDelegateActor)(nil).AddNewIds), c, a)
}
// Deliver mocks base method
func (m *MockDelegateActor) Deliver(c context.Context, outbox *url.URL, activity Activity) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Deliver", c, outbox, activity)
ret0, _ := ret[0].(error)
return ret0
}
// Deliver indicates an expected call of Deliver
func (mr *MockDelegateActorMockRecorder) Deliver(c, outbox, activity interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Deliver", reflect.TypeOf((*MockDelegateActor)(nil).Deliver), c, outbox, activity)
}
// AuthenticatePostOutbox mocks base method
func (m *MockDelegateActor) AuthenticatePostOutbox(c context.Context, w http.ResponseWriter, r *http.Request) (bool, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "AuthenticatePostOutbox", c, w, r)
ret0, _ := ret[0].(bool)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// AuthenticatePostOutbox indicates an expected call of AuthenticatePostOutbox
func (mr *MockDelegateActorMockRecorder) AuthenticatePostOutbox(c, w, r interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AuthenticatePostOutbox", reflect.TypeOf((*MockDelegateActor)(nil).AuthenticatePostOutbox), c, w, r)
}
// AuthenticateGetOutbox mocks base method
func (m *MockDelegateActor) AuthenticateGetOutbox(c context.Context, w http.ResponseWriter, r *http.Request) (bool, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "AuthenticateGetOutbox", c, w, r)
ret0, _ := ret[0].(bool)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// AuthenticateGetOutbox indicates an expected call of AuthenticateGetOutbox
func (mr *MockDelegateActorMockRecorder) AuthenticateGetOutbox(c, w, r interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AuthenticateGetOutbox", reflect.TypeOf((*MockDelegateActor)(nil).AuthenticateGetOutbox), c, w, r)
}
// WrapInCreate mocks base method
func (m *MockDelegateActor) WrapInCreate(c context.Context, value vocab.Type, outboxIRI *url.URL) (vocab.ActivityStreamsCreate, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "WrapInCreate", c, value, outboxIRI)
ret0, _ := ret[0].(vocab.ActivityStreamsCreate)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// WrapInCreate indicates an expected call of WrapInCreate
func (mr *MockDelegateActorMockRecorder) WrapInCreate(c, value, outboxIRI interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WrapInCreate", reflect.TypeOf((*MockDelegateActor)(nil).WrapInCreate), c, value, outboxIRI)
}
// GetOutbox mocks base method
func (m *MockDelegateActor) GetOutbox(c context.Context, r *http.Request) (vocab.ActivityStreamsOrderedCollectionPage, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetOutbox", c, r)
ret0, _ := ret[0].(vocab.ActivityStreamsOrderedCollectionPage)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetOutbox indicates an expected call of GetOutbox
func (mr *MockDelegateActorMockRecorder) GetOutbox(c, r interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetOutbox", reflect.TypeOf((*MockDelegateActor)(nil).GetOutbox), c, r)
}
// GetInbox mocks base method
func (m *MockDelegateActor) GetInbox(c context.Context, r *http.Request) (vocab.ActivityStreamsOrderedCollectionPage, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetInbox", c, r)
ret0, _ := ret[0].(vocab.ActivityStreamsOrderedCollectionPage)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetInbox indicates an expected call of GetInbox
func (mr *MockDelegateActorMockRecorder) GetInbox(c, r interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetInbox", reflect.TypeOf((*MockDelegateActor)(nil).GetInbox), c, r)
}

292
pub/pub_test.go Normal file
View File

@ -0,0 +1,292 @@
package pub
import (
"bytes"
"context"
"encoding/json"
"github.com/go-fed/activity/streams"
"github.com/go-fed/activity/streams/vocab"
"net/http"
"net/http/httptest"
"net/url"
"testing"
"time"
)
const (
testMyInboxIRI = "https://example.com/addison/inbox"
testMyOutboxIRI = "https://example.com/addison/outbox"
testFederatedActivityIRI = "https://other.example.com/activity/1"
testFederatedActorIRI = "https://other.example.com/dakota"
testNoteId1 = "https://example.com/note/1"
testNoteId2 = "https://example.com/note/2"
testNewActivityIRI = "https://example.com/new/1"
)
// mustParse parses a URL or panics.
func mustParse(s string) *url.URL {
u, err := url.Parse(s)
if err != nil {
panic(err)
}
return u
}
// assertEqual ensures two values are equal.
func assertEqual(t *testing.T, a, b interface{}) {
if a != b {
t.Errorf("expected equal: %v != %v", a, b)
}
}
// assertByteEqual ensures two byte slices are equal.
func assertByteEqual(t *testing.T, a, b []byte) {
if string(a) != string(b) {
t.Errorf("expected equal:\n%s\n\n%s", a, b)
}
}
// assertNotEqual ensures two values are not equal.
func assertNotEqual(t *testing.T, a, b interface{}) {
if a == b {
t.Errorf("expected not equal: %v != %v", a, b)
}
}
var (
// testNote is a test Note from a federated peer.
testFederatedNote vocab.ActivityStreamsNote
// testNote is a test Note owned by this server.
testMyNote vocab.ActivityStreamsNote
// testCreate is a test Create Activity.
testCreate vocab.ActivityStreamsCreate
// testCreateNoId is a test Create Activity without an 'id' set.
testCreateNoId vocab.ActivityStreamsCreate
// testOrderedCollectionUniqueElems is a collection with only unique
// ids.
testOrderedCollectionUniqueElems vocab.ActivityStreamsOrderedCollectionPage
// testOrderedCollectionUniqueElemsString is the JSON-LD version of the
// testOrderedCollectionUniqueElems value
testOrderedCollectionUniqueElemsString string
// testOrderedCollectionDupedElems is a collection with duplicated ids.
testOrderedCollectionDupedElems vocab.ActivityStreamsOrderedCollectionPage
// testOrderedCollectionDedupedElemsString is the JSON-LD version of the
// testOrderedCollectionDedupedElems value with duplicates removed
testOrderedCollectionDedupedElemsString string
)
// The test data cannot be created at init time since that is when the hooks of
// the `streams` package are set up. So initialize the data in this call instead
// of at init time.
func setupData() {
// testFederatedNote
func() {
testFederatedNote = streams.NewActivityStreamsNote()
name := streams.NewActivityStreamsNameProperty()
name.AppendXMLSchemaString("A Federated Note")
testFederatedNote.SetActivityStreamsName(name)
content := streams.NewActivityStreamsContentProperty()
content.AppendXMLSchemaString("This is a simple note being federated.")
testFederatedNote.SetActivityStreamsContent(content)
}()
// testMyNote
func() {
testMyNote = streams.NewActivityStreamsNote()
name := streams.NewActivityStreamsNameProperty()
name.AppendXMLSchemaString("My Note")
testMyNote.SetActivityStreamsName(name)
content := streams.NewActivityStreamsContentProperty()
content.AppendXMLSchemaString("This is a simple note of mine.")
testMyNote.SetActivityStreamsContent(content)
}()
// testCreate
func() {
testCreate = streams.NewActivityStreamsCreate()
id := streams.NewActivityStreamsIdProperty()
id.Set(mustParse(testFederatedActivityIRI))
testCreate.SetActivityStreamsId(id)
actor := streams.NewActivityStreamsActorProperty()
actor.AppendIRI(mustParse(testFederatedActorIRI))
testCreate.SetActivityStreamsActor(actor)
op := streams.NewActivityStreamsObjectProperty()
op.AppendActivityStreamsNote(testFederatedNote)
testCreate.SetActivityStreamsObject(op)
}()
// testCreateNoId
func() {
testCreateNoId = streams.NewActivityStreamsCreate()
actor := streams.NewActivityStreamsActorProperty()
actor.AppendIRI(mustParse(testFederatedActorIRI))
testCreateNoId.SetActivityStreamsActor(actor)
op := streams.NewActivityStreamsObjectProperty()
op.AppendActivityStreamsNote(testFederatedNote)
testCreateNoId.SetActivityStreamsObject(op)
}()
// testOrderedCollectionUniqueElems and
// testOrderedCollectionUniqueElemsString
func() {
testOrderedCollectionUniqueElems = streams.NewActivityStreamsOrderedCollectionPage()
oi := streams.NewActivityStreamsOrderedItemsProperty()
oi.AppendIRI(mustParse(testNoteId1))
oi.AppendIRI(mustParse(testNoteId2))
testOrderedCollectionUniqueElems.SetActivityStreamsOrderedItems(oi)
testOrderedCollectionUniqueElemsString = `{"@context":"https://www.w3.org/TR/activitystreams-vocabulary","orderedItems":["https://example.com/note/1","https://example.com/note/2"],"type":"OrderedCollectionPage"}`
}()
// testOrderedCollectionDupedElems and
// testOrderedCollectionDedupedElemsString
func() {
testOrderedCollectionDupedElems = streams.NewActivityStreamsOrderedCollectionPage()
oi := streams.NewActivityStreamsOrderedItemsProperty()
oi.AppendIRI(mustParse(testNoteId1))
oi.AppendIRI(mustParse(testNoteId1))
testOrderedCollectionDupedElems.SetActivityStreamsOrderedItems(oi)
testOrderedCollectionDedupedElemsString = `{"@context":"https://www.w3.org/TR/activitystreams-vocabulary","orderedItems":"https://example.com/note/1","type":"OrderedCollectionPage"}`
}()
}
// wrappedInCreate returns a Create activity wrapping the given type.
func wrappedInCreate(t vocab.Type) vocab.ActivityStreamsCreate {
create := streams.NewActivityStreamsCreate()
op := streams.NewActivityStreamsObjectProperty()
op.AppendType(t)
create.SetActivityStreamsObject(op)
return create
}
// mustSerialize serializes a type or panics.
func mustSerialize(t vocab.Type) map[string]interface{} {
m, err := serialize(t)
if err != nil {
panic(err)
}
return m
}
// toDeserializedForm serializes and deserializes a type so that it works with
// mock expectations.
func toDeserializedForm(t vocab.Type) vocab.Type {
m := mustSerialize(t)
asValue, err := streams.ToType(context.Background(), m)
if err != nil {
panic(err)
}
return asValue
}
// withNewId sets a new id property on the activity
func withNewId(t vocab.Type) Activity {
a, ok := t.(Activity)
if !ok {
panic("activity streams value is not an Activity")
}
id := streams.NewActivityStreamsIdProperty()
id.Set(mustParse(testNewActivityIRI))
a.SetActivityStreamsId(id)
return a
}
// now returns the "current" time for tests.
func now() time.Time {
l, err := time.LoadLocation("America/New_York")
if err != nil {
panic(err)
}
return time.Date(2000, 2, 3, 4, 5, 6, 7, l)
}
// nowDateHeader returns the "current" time formatted in a form expected by the
// Date header in HTTP responses.
func nowDateHeader() string {
return now().UTC().Format("Mon, 02 Jan 2006 15:04:05") + " GMT"
}
// toAPRequests adds the appropriate Content-Type or Accept headers to indicate
// that the HTTP request is an ActivityPub one. Also sets the Date header with
// the "current" test time.
func toAPRequest(r *http.Request) *http.Request {
if r.Method == "POST" {
existing, ok := r.Header[contentTypeHeader]
if ok {
r.Header[contentTypeHeader] = append(existing, activityStreamsMediaTypes[0])
} else {
r.Header[contentTypeHeader] = []string{activityStreamsMediaTypes[0]}
}
} else if r.Method == "GET" {
existing, ok := r.Header[acceptHeader]
if ok {
r.Header[acceptHeader] = append(existing, activityStreamsMediaTypes[0])
} else {
r.Header[acceptHeader] = []string{activityStreamsMediaTypes[0]}
}
} else {
panic("cannot toAPRequest with method " + r.Method)
}
r.Header[dateHeader] = []string{now().UTC().Format("Mon, 02 Jan 2006 15:04:05") + " GMT"}
return r
}
// toPostInboxRequest creates a new POST HTTP request with the given type as
// the payload.
func toPostInboxRequest(t vocab.Type) *http.Request {
m, err := serialize(t)
if err != nil {
panic(err)
}
b, err := json.MarshalIndent(m, "", " ")
if err != nil {
panic(err)
}
buf := bytes.NewBuffer(b)
return httptest.NewRequest("POST", testMyInboxIRI, buf)
}
// toPostOutboxRequest creates a new POST HTTP request with the given type as
// the payload.
func toPostOutboxRequest(t vocab.Type) *http.Request {
m, err := serialize(t)
if err != nil {
panic(err)
}
b, err := json.MarshalIndent(m, "", " ")
if err != nil {
panic(err)
}
buf := bytes.NewBuffer(b)
return httptest.NewRequest("POST", testMyOutboxIRI, buf)
}
// toPostOutboxUnknownRequest creates a new POST HTTP request with an unknown
// type in the payload.
func toPostOutboxUnknownRequest() *http.Request {
s := `{
"@context": "https://www.w3.org/ns/activitystreams",
"type": "http://www.types.example/ProductOffer",
"id": "http://www.example.com/spam"
}`
b := []byte(s)
buf := bytes.NewBuffer(b)
return httptest.NewRequest("POST", testMyOutboxIRI, buf)
}
// toPostInboxUnknownRequest creates a new POST HTTP request with an unknown
// type in the payload.
func toPostInboxUnknownRequest() *http.Request {
s := `{
"@context": "https://www.w3.org/ns/activitystreams",
"type": "http://www.types.example/ProductOffer",
"id": "http://www.example.com/spam"
}`
b := []byte(s)
buf := bytes.NewBuffer(b)
return httptest.NewRequest("POST", testMyInboxIRI, buf)
}
// toGetInboxRequest creates a new GET HTTP request.
func toGetInboxRequest() *http.Request {
return httptest.NewRequest("GET", testMyInboxIRI, nil)
}
// toGetOutboxRequest creates a new GET HTTP request.
func toGetOutboxRequest() *http.Request {
return httptest.NewRequest("GET", testMyOutboxIRI, nil)
}

View File

@ -168,6 +168,8 @@ func serialize(a vocab.Type) (m map[string]interface{}, e error) {
}
const (
// The Location header
locationHeader = "Location"
// Contains the ActivityStreams Content-Type value.
contentTypeHeaderValue = "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\""
// The Date header.

View File

@ -67,8 +67,10 @@ func TestHeaderIsActivityPubMediaType(t *testing.T) {
},
}
for _, test := range tests {
if actual := headerIsActivityPubMediaType(test.input); actual != test.expected {
t.Fatalf("(%q): expected %v, got %v", test.name, test.expected, actual)
}
t.Run(test.name, func(t *testing.T) {
if actual := headerIsActivityPubMediaType(test.input); actual != test.expected {
t.Fatalf("expected %v, got %v", test.expected, actual)
}
})
}
}