From 52bc5fb9a5028cbd421bdf490506efc296227b0f Mon Sep 17 00:00:00 2001 From: Cory Slep Date: Sat, 16 Feb 2019 20:30:18 +0100 Subject: [PATCH] Add tests for the base actor. Removed old pub tests. --- pub/base_actor.go | 7 +- pub/base_actor_test.go | 724 +++ pub/fed_test.go | 8316 ------------------------ pub/handlers_test.go | 698 -- pub/mock_clock_test.go | 47 + pub/mock_delegate_actor_test.go | 227 + pub/pub_test.go | 292 + pub/util.go | 2 + pub/{internal_test.go => util_test.go} | 8 +- 9 files changed, 1303 insertions(+), 9018 deletions(-) create mode 100644 pub/base_actor_test.go delete mode 100644 pub/fed_test.go delete mode 100644 pub/handlers_test.go create mode 100644 pub/mock_clock_test.go create mode 100644 pub/mock_delegate_actor_test.go create mode 100644 pub/pub_test.go rename pub/{internal_test.go => util_test.go} (88%) diff --git a/pub/base_actor.go b/pub/base_actor.go index 0daf8ec..d7333b2 100644 --- a/pub/base_actor.go +++ b/pub/base_actor.go @@ -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. diff --git a/pub/base_actor_test.go b/pub/base_actor_test.go new file mode 100644 index 0000000..dbf3def --- /dev/null +++ b/pub/base_actor_test.go @@ -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) + }) +} diff --git a/pub/fed_test.go b/pub/fed_test.go deleted file mode 100644 index 1e6e140..0000000 --- a/pub/fed_test.go +++ /dev/null @@ -1,8316 +0,0 @@ -package pub - -import ( - "bytes" - "context" - "crypto" - "crypto/rand" - "crypto/rsa" - "encoding/json" - "errors" - "fmt" - "github.com/go-fed/activity/streams_old" - "github.com/go-fed/activity/vocab" - "github.com/go-fed/httpsig" - "io/ioutil" - "net/http" - "net/http/httptest" - "net/url" - "strings" - "testing" - "time" -) - -const ( - iriString = "https://example.com/something" - noteURIString = "https://example.com/note/123" - updateURIString = "https://example.com/note/update/123" - noteActivityURIString = "https://example.com/activity/987" - testAgent = "test agent string" - testInboxURI = "https://example.com/sally/inbox" - testOutboxURI = "https://example.com/sally/outbox" - testNewIRIString = "https://example.com/test/new/iri/1" - testNewIRIString2 = "https://example.com/test/new/iri/2" - sallyIRIString = "https://example.com/sally" - sallyFollowingIRIString = "https://example.com/sally/following" - samIRIString = "https://example.com/sam" - samIRIInboxString = "https://example.com/sam/inbox" - samIRIFollowersString = "https://example.com/sam/followers" - sallyIRIInboxString = "https://example.com/sally/inbox" - noteName = "A Note" - otherOriginIRIString = "https://foo.net/activity/112358" - otherOriginActorIRIString = "https://foo.net/peyton" - - testPublicKeyId = "publicKeyId" -) - -var ( - iri *url.URL - noteIRI *url.URL - noteActivityIRI *url.URL - updateActivityIRI *url.URL - testNewIRI *url.URL - testNewIRI2 *url.URL - sallyIRI *url.URL - sallyIRIInbox *url.URL - sallyFollowingIRI *url.URL - sallyActor *vocab.Person - sallyActorJSON []byte - samIRI *url.URL - samIRIInbox *url.URL - samIRIFollowers *url.URL - otherOriginIRI *url.URL - otherOriginActorIRI *url.URL - samActor *vocab.Person - samActorJSON []byte - testNote *vocab.Note - testSingleOrderedCollection *vocab.OrderedCollection - testCreateNote *vocab.Create - testUpdateNote *vocab.Update - testDeleteNote *vocab.Delete - testTombstoneNote *vocab.Tombstone - testFollow *vocab.Follow - testAcceptNote *vocab.Accept - testAcceptFollow *vocab.Accept - testRejectFollow *vocab.Reject - testAddNote *vocab.Add - testRemoveNote *vocab.Remove - testLikeNote *vocab.Like - testUndoLike *vocab.Undo - testAnnounceNote *vocab.Announce - testBlock *vocab.Block - testClientExpectedNote *vocab.Note - testClientExpectedCreateNote *vocab.Create - testDeleteSubFields string - testDeleteFields string - testDeleteFieldsDifferentObjects string - testClientUpdateNote *vocab.Update - testClientExpectedUpdateNote *vocab.Update - testClientExpectedDeleteNote *vocab.Delete - testClientExpectedFollow *vocab.Follow - testClientExpectedAcceptFollow *vocab.Accept - testClientExpectedRejectFollow *vocab.Reject - testClientExpectedAdd *vocab.Add - testClientExpectedRemove *vocab.Remove - testClientExpectedLike *vocab.Like - testClientExpectedUndo *vocab.Undo - testClientExpectedBlock *vocab.Block - - testPrivateKey *rsa.PrivateKey - testOtherPrivateKey *rsa.PrivateKey -) - -func init() { - var err error - iri, err = url.Parse(iriString) - if err != nil { - panic(err) - } - noteIRI, err = url.Parse(noteURIString) - if err != nil { - panic(err) - } - noteActivityIRI, err = url.Parse(noteActivityURIString) - if err != nil { - panic(err) - } - updateActivityIRI, err = url.Parse(updateURIString) - if err != nil { - panic(err) - } - testNewIRI, err = url.Parse(testNewIRIString) - if err != nil { - panic(err) - } - testNewIRI2, err = url.Parse(testNewIRIString2) - if err != nil { - panic(err) - } - sallyIRI, err = url.Parse(sallyIRIString) - if err != nil { - panic(err) - } - sallyIRIInbox, err = url.Parse(sallyIRIInboxString) - if err != nil { - panic(err) - } - sallyFollowingIRI, err = url.Parse(sallyFollowingIRIString) - if err != nil { - panic(err) - } - samIRI, err = url.Parse(samIRIString) - if err != nil { - panic(err) - } - samIRIInbox, err = url.Parse(samIRIInboxString) - if err != nil { - panic(err) - } - samIRIFollowers, err = url.Parse(samIRIFollowersString) - if err != nil { - panic(err) - } - otherOriginIRI, err = url.Parse(otherOriginIRIString) - if err != nil { - panic(err) - } - otherOriginActorIRI, err = url.Parse(otherOriginActorIRIString) - if err != nil { - panic(err) - } - samActor = &vocab.Person{} - samActor.SetInboxAnyURI(samIRIInbox) - samActor.SetId(samIRI) - samActor.AppendNameString("Sam") - m, err := samActor.Serialize() - if err != nil { - panic(err) - } - samActorJSON, err = json.Marshal(m) - if err != nil { - panic(err) - } - sallyInbox, err := url.Parse(testInboxURI) - if err != nil { - panic(err) - } - sallyOutbox, err := url.Parse(testOutboxURI) - if err != nil { - panic(err) - } - sallyActor = &vocab.Person{} - sallyActor.AppendNameString("Sally") - sallyActor.SetId(sallyIRI) - sallyActor.SetInboxAnyURI(sallyInbox) - sallyActor.SetOutboxAnyURI(sallyOutbox) - m, err = sallyActor.Serialize() - if err != nil { - panic(err) - } - sallyActorJSON, err = json.Marshal(m) - if err != nil { - panic(err) - } - testNote = &vocab.Note{} - testNote.SetId(noteIRI) - testNote.AppendNameString(noteName) - testNote.AppendContentString("This is a simple note") - testSingleOrderedCollection = &vocab.OrderedCollection{} - testSingleOrderedCollection.AppendItemsObject(testNote) - testCreateNote = &vocab.Create{} - testCreateNote.SetId(noteActivityIRI) - testCreateNote.AppendSummaryString("Sally created a note") - testCreateNote.AppendActorObject(sallyActor) - testCreateNote.AppendObject(testNote) - testCreateNote.AppendToObject(samActor) - testUpdateNote = &vocab.Update{} - testUpdateNote.SetId(updateActivityIRI) - testUpdateNote.AppendSummaryString("Sally updated a note") - testUpdateNote.AppendActorObject(sallyActor) - testUpdateNote.AppendObject(testNote) - testUpdateNote.AppendToObject(samActor) - testDeleteNote = &vocab.Delete{} - testDeleteNote.SetId(noteActivityIRI) - testDeleteNote.AppendActorObject(sallyActor) - testDeleteNote.AppendObject(testNote) - testDeleteNote.AppendToObject(samActor) - testTombstoneNote = &vocab.Tombstone{} - testTombstoneNote.SetId(noteIRI) - testTombstoneNote.AppendFormerTypeString("Note") - testTombstoneNote.SetDeleted(now) - testFollow = &vocab.Follow{} - testFollow.SetId(noteActivityIRI) - testFollow.AppendActorObject(sallyActor) - testFollow.AppendObject(samActor) - testFollow.AppendToObject(samActor) - testAcceptNote = &vocab.Accept{} - testAcceptNote.SetId(noteActivityIRI) - testAcceptNote.AppendActorObject(sallyActor) - testAcceptNote.AppendObject(&vocab.Offer{}) - testAcceptNote.AppendToObject(samActor) - testAcceptFollow = &vocab.Accept{} - testAcceptFollow.SetId(noteActivityIRI) - testAcceptFollow.AppendActorObject(samActor) - testAcceptFollow.AppendObject(testFollow) - testAcceptFollow.AppendToObject(sallyActor) - testRejectFollow = &vocab.Reject{} - testRejectFollow.SetId(noteActivityIRI) - testRejectFollow.AppendActorObject(samActor) - testRejectFollow.AppendObject(testFollow) - testRejectFollow.AppendToObject(sallyActor) - testAddNote = &vocab.Add{} - testAddNote.SetId(noteActivityIRI) - testAddNote.AppendActorObject(sallyActor) - testAddNote.AppendObject(testNote) - testAddNote.AppendTargetIRI(iri) - testAddNote.AppendToObject(samActor) - testRemoveNote = &vocab.Remove{} - testRemoveNote.SetId(noteActivityIRI) - testRemoveNote.AppendActorObject(sallyActor) - testRemoveNote.AppendObject(testNote) - testRemoveNote.AppendTargetIRI(iri) - testRemoveNote.AppendToObject(samActor) - testLikeNote = &vocab.Like{} - testLikeNote.SetId(noteActivityIRI) - testLikeNote.AppendActorObject(sallyActor) - testLikeNote.AppendObject(testNote) - testLikeNote.AppendToObject(samActor) - testUndoLike = &vocab.Undo{} - testUndoLike.SetId(noteActivityIRI) - testUndoLike.AppendActorObject(sallyActor) - testUndoLike.AppendObject(testLikeNote) - testUndoLike.AppendToObject(samActor) - testBlock = &vocab.Block{} - testBlock.SetId(noteActivityIRI) - testBlock.AppendActorObject(sallyActor) - testBlock.AppendObject(samActor) - testAnnounceNote = &vocab.Announce{} - testAnnounceNote.SetId(noteActivityIRI) - testAnnounceNote.AppendActorObject(sallyActor) - testAnnounceNote.AppendObject(testNote) - testAnnounceNote.AppendToObject(samActor) - - testClientExpectedNote = &vocab.Note{} - testClientExpectedNote.SetId(testNewIRI2) - testClientExpectedNote.AppendNameString(noteName) - testClientExpectedNote.AppendContentString("This is a simple note") - testClientExpectedNote.AppendAttributedToIRI(sallyIRI) - testClientExpectedNote.AppendToIRI(samIRI) - testClientExpectedCreateNote = &vocab.Create{} - testClientExpectedCreateNote.SetId(testNewIRI) - testClientExpectedCreateNote.AppendSummaryString("Sally created a note") - testClientExpectedCreateNote.AppendActorObject(sallyActor) - testClientExpectedCreateNote.AppendObject(testClientExpectedNote) - testClientExpectedCreateNote.AppendToObject(samActor) - testDeleteSubFields = ` - { - "@context": "https://www.w3.org/ns/activitystreams", - "summary": "Sally updated her note", - "type": "Update", - "actor": "https://example.com/sally", - "id": "https://example.com/test/new/iri", - "object": { - "id": "https://example.com/note/123", - "type": "Note", - "to": { - "id": "https://example.com/sam", - "inbox": "https://example.com/sam/inbox", - "type": "Person", - "name": null - } - } - } - ` - testDeleteFields = ` - { - "@context": "https://www.w3.org/ns/activitystreams", - "summary": "Sally updated her note", - "type": "Update", - "actor": "https://example.com/sally", - "id": "https://example.com/test/new/iri", - "object": { - "id": "https://example.com/note/123", - "type": "Note", - "to": null - } - } - ` - testDeleteFieldsDifferentObjects = ` - { - "@context": "https://www.w3.org/ns/activitystreams", - "summary": "Sally updated her notes", - "type": "Update", - "actor": "https://example.com/sally", - "id": "https://example.com/test/new/iri", - "object": [ - { - "id": "https://example.com/note/123", - "type": "Note", - "to": { - "id": "https://example.com/sam", - "inbox": "https://example.com/sam/inbox", - "type": "Person", - "name": null - } - }, - { - "id": "https://example.com/note/update/123", - "type": "Note", - "to": { - "id": "https://example.com/sam", - "inbox": "https://example.com/sam/inbox", - "type": "Person", - "name": null - } - } - ] - } - ` - sammActor := &vocab.Person{} - sammActor.SetInboxAnyURI(samIRIInbox) - sammActor.SetId(samIRI) - sammActor.AppendNameString("Samm") - testUpdateNote := &vocab.Note{} - testUpdateNote.SetId(noteIRI) - testUpdateNote.AppendNameString(noteName) - testUpdateNote.AppendContentString("This is a simple note") - testUpdateNote.AppendToObject(sammActor) - testClientUpdateNote = &vocab.Update{} - testClientUpdateNote.SetId(updateActivityIRI) - testClientUpdateNote.AppendSummaryString("Sally updated a note") - testClientUpdateNote.AppendActorObject(sallyActor) - testClientUpdateNote.AppendObject(testUpdateNote) - testClientUpdateNote.AppendToObject(samActor) - testClientExpectedUpdateNote = &vocab.Update{} - testClientExpectedUpdateNote.SetId(testNewIRI) - testClientExpectedUpdateNote.AppendSummaryString("Sally updated a note") - testClientExpectedUpdateNote.AppendActorObject(sallyActor) - testClientExpectedUpdateNote.AppendObject(testNote) - testClientExpectedUpdateNote.AppendToObject(samActor) - testClientExpectedDeleteNote = &vocab.Delete{} - testClientExpectedDeleteNote.SetId(testNewIRI) - testClientExpectedDeleteNote.AppendActorObject(sallyActor) - testClientExpectedDeleteNote.AppendObject(testNote) - testClientExpectedDeleteNote.AppendToObject(samActor) - testClientExpectedFollow = &vocab.Follow{} - testClientExpectedFollow.SetId(testNewIRI) - testClientExpectedFollow.AppendActorObject(sallyActor) - testClientExpectedFollow.AppendObject(samActor) - testClientExpectedFollow.AppendToObject(samActor) - testClientExpectedAcceptFollow = &vocab.Accept{} - testClientExpectedAcceptFollow.SetId(testNewIRI) - testClientExpectedAcceptFollow.AppendActorObject(samActor) - testClientExpectedAcceptFollow.AppendObject(testFollow) - testClientExpectedAcceptFollow.AppendToObject(sallyActor) - testClientExpectedRejectFollow = &vocab.Reject{} - testClientExpectedRejectFollow.SetId(testNewIRI) - testClientExpectedRejectFollow.AppendActorObject(samActor) - testClientExpectedRejectFollow.AppendObject(testFollow) - testClientExpectedRejectFollow.AppendToObject(sallyActor) - testClientExpectedAdd = &vocab.Add{} - testClientExpectedAdd.SetId(testNewIRI) - testClientExpectedAdd.AppendActorObject(sallyActor) - testClientExpectedAdd.AppendObject(testNote) - testClientExpectedAdd.AppendTargetIRI(iri) - testClientExpectedAdd.AppendToObject(samActor) - testClientExpectedRemove = &vocab.Remove{} - testClientExpectedRemove.SetId(testNewIRI) - testClientExpectedRemove.AppendActorObject(sallyActor) - testClientExpectedRemove.AppendObject(testNote) - testClientExpectedRemove.AppendTargetIRI(iri) - testClientExpectedRemove.AppendToObject(samActor) - testClientExpectedLike = &vocab.Like{} - testClientExpectedLike.SetId(testNewIRI) - testClientExpectedLike.AppendActorObject(sallyActor) - testClientExpectedLike.AppendObject(testNote) - testClientExpectedLike.AppendToObject(samActor) - testClientExpectedUndo = &vocab.Undo{} - testClientExpectedUndo.SetId(testNewIRI) - testClientExpectedUndo.AppendActorObject(sallyActor) - testClientExpectedUndo.AppendObject(testLikeNote) - testClientExpectedUndo.AppendToObject(samActor) - testClientExpectedBlock = &vocab.Block{} - testClientExpectedBlock.SetId(testNewIRI) - testClientExpectedBlock.AppendActorObject(sallyActor) - testClientExpectedBlock.AppendObject(samActor) - - testPrivateKey, err = rsa.GenerateKey(rand.Reader, 2048) - if err != nil { - panic(err) - } - testOtherPrivateKey, err = rsa.GenerateKey(rand.Reader, 2048) - if err != nil { - panic(err) - } -} - -func Must(l *time.Location, e error) *time.Location { - if e != nil { - panic(e) - } - return l -} - -func MustSerialize(s vocab.Serializer) []byte { - m, err := s.Serialize() - if err != nil { - panic(err) - } - addJSONLDContext(m) - b, err := json.Marshal(m) - if err != nil { - panic(err) - } - return b -} - -func BadSignature(r *http.Request) *http.Request { - s, _, err := httpsig.NewSigner([]httpsig.Algorithm{httpsig.RSA_SHA256}, nil, httpsig.Signature) - if err != nil { - panic(err) - } - err = s.SignRequest(testOtherPrivateKey, testPublicKeyId, r) - if err != nil { - panic(err) - } - return r -} - -func Sign(r *http.Request) *http.Request { - s, _, err := httpsig.NewSigner([]httpsig.Algorithm{httpsig.RSA_SHA256}, nil, httpsig.Signature) - if err != nil { - panic(err) - } - err = s.SignRequest(testPrivateKey, testPublicKeyId, r) - if err != nil { - panic(err) - } - return r -} - -func ActivityPubRequest(r *http.Request) *http.Request { - if r.Method == "POST" { - existing, ok := r.Header["Content-Type"] - if ok { - r.Header["Content-Type"] = append(existing, "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"") - } else { - r.Header["Content-Type"] = []string{"application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\""} - } - } else { - existing, ok := r.Header["Accept"] - if ok { - r.Header["Accept"] = append(existing, "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"") - } else { - r.Header["Accept"] = []string{"application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\""} - } - } - r.Header["Date"] = []string{now.UTC().Format("Mon, 02 Jan 2006 15:04:05") + " GMT"} - return r -} - -func PubObjectEquals(p PubObject, s vocab.Serializer) error { - ps, ok := p.(vocab.Serializer) - if !ok { - return fmt.Errorf("PubObject is not Serializer") - } - m, err := ps.Serialize() - if err != nil { - return err - } - b, err := json.Marshal(m) - if err != nil { - return err - } - return VocabEqualsContext(bytes.NewBuffer(b), s, false) -} - -func VocabSerializerEquals(i, j vocab.Serializer) error { - m, err := i.Serialize() - if err != nil { - return err - } - b, err := json.Marshal(m) - if err != nil { - return err - } - return VocabEqualsContext(bytes.NewBuffer(b), j, false) -} - -func VocabEquals(b *bytes.Buffer, s vocab.Serializer) error { - return VocabEqualsContext(b, s, true) -} - -func VocabEqualsContext(b *bytes.Buffer, s vocab.Serializer, requireContext bool) error { - m, err := s.Serialize() - if err != nil { - return err - } - if requireContext { - m["@context"] = "https://www.w3.org/ns/activitystreams" - } - expected, err := json.Marshal(m) - if err != nil { - return err - } - actual := b.Bytes() - if len(actual) != len(expected) { - return fmt.Errorf("expected len %d, actual len %d:\nexpected value %s\nactual value %s", len(expected), len(actual), expected, actual) - } - var diffs []string - for i := range actual { - if actual[i] != expected[i] { - diffs = append(diffs, fmt.Sprintf("at %d expected %d but got %d", i, expected[i], actual[i])) - } - } - if len(diffs) == 0 { - return nil - } - return fmt.Errorf(strings.Join(diffs, "; ")) -} - -var ( - now = time.Date(2000, 2, 3, 4, 5, 6, 7, Must(time.LoadLocation("America/New_York"))) - testPublishedTime = time.Date(2001, 2, 3, 4, 5, 6, 7, Must(time.LoadLocation("America/New_York"))) - testUpdateTime = time.Date(2002, 2, 3, 4, 5, 6, 7, Must(time.LoadLocation("America/New_York"))) -) - -var _ Clock = &MockClock{} - -type MockClock struct { - now time.Time -} - -func (m *MockClock) Now() time.Time { - return m.now -} - -var _ Application = &MockApplication{} - -type MockApplication struct { - t *testing.T - owns func(c context.Context, id *url.URL) bool - get func(c context.Context, id *url.URL, rw RWType) (PubObject, error) - getAsVerifiedUser func(c context.Context, id, authdUser *url.URL, rw RWType) (PubObject, error) - has func(c context.Context, id *url.URL) (bool, error) - set func(c context.Context, o PubObject) error - getInbox func(c context.Context, r *http.Request, rw RWType) (vocab.OrderedCollectionType, error) - getOutbox func(c context.Context, r *http.Request, rw RWType) (vocab.OrderedCollectionType, error) - newId func(c context.Context, t Typer) *url.URL - getPublicKey func(c context.Context, publicKeyId string) (crypto.PublicKey, httpsig.Algorithm, *url.URL, error) - canAdd func(c context.Context, o vocab.ObjectType, t vocab.ObjectType) bool - canRemove func(c context.Context, o vocab.ObjectType, t vocab.ObjectType) bool -} - -func (m *MockApplication) Owns(c context.Context, id *url.URL) bool { - if m.owns == nil { - m.t.Fatal("unexpected call to MockApplication Owns") - } - return m.owns(c, id) -} - -func (m *MockApplication) Get(c context.Context, id *url.URL, rw RWType) (PubObject, error) { - if m.get == nil { - m.t.Fatal("unexpected call to MockApplication Get") - } - return m.get(c, id, rw) -} - -func (m *MockApplication) GetAsVerifiedUser(c context.Context, id, authdUser *url.URL, rw RWType) (PubObject, error) { - if m.getAsVerifiedUser == nil { - m.t.Fatal("unexpected call to MockApplication GetAsVerifiedUser") - } - return m.getAsVerifiedUser(c, id, authdUser, rw) -} - -func (m *MockApplication) Has(c context.Context, id *url.URL) (bool, error) { - if m.has == nil { - m.t.Fatal("unexpected call to MockApplication Has") - } - return m.has(c, id) -} - -func (m *MockApplication) Set(c context.Context, o PubObject) error { - if m.set == nil { - m.t.Fatal("unexpected call to MockApplication Set") - } - return m.set(c, o) -} - -func (m *MockApplication) GetInbox(c context.Context, r *http.Request, rw RWType) (vocab.OrderedCollectionType, error) { - if m.getInbox == nil { - m.t.Fatal("unexpected call to MockApplication GetInbox") - } - return m.getInbox(c, r, rw) -} - -func (m *MockApplication) GetOutbox(c context.Context, r *http.Request, rw RWType) (vocab.OrderedCollectionType, error) { - if m.getOutbox == nil { - m.t.Fatal("unexpected call to MockApplication GetOutbox") - } - return m.getOutbox(c, r, rw) -} - -func (m *MockApplication) NewId(c context.Context, t Typer) *url.URL { - if m.newId == nil { - m.t.Fatal("unexpected call to MockApplication NewId") - } - return m.newId(c, t) -} - -func (m *MockApplication) GetPublicKey(c context.Context, publicKeyId string) (crypto.PublicKey, httpsig.Algorithm, *url.URL, error) { - if m.getPublicKey == nil { - m.t.Fatal("unexpected call to MockApplication GetPublicKey") - } - return m.getPublicKey(c, publicKeyId) -} - -func (m *MockApplication) CanAdd(c context.Context, o vocab.ObjectType, t vocab.ObjectType) bool { - if m.canAdd == nil { - m.t.Fatal("unexpected call to MockApplication CanAdd") - } - return m.canAdd(c, o, t) -} - -func (m *MockApplication) CanRemove(c context.Context, o vocab.ObjectType, t vocab.ObjectType) bool { - if m.canRemove == nil { - m.t.Fatal("unexpected call to MockApplication CanRemove") - } - return m.canRemove(c, o, t) -} - -var _ SocialApplication = &MockSocialApp{} - -type MockSocialApp struct { - *MockApplication - t *testing.T - actorIRI func(c context.Context, r *http.Request) (*url.URL, error) - getPublicKeyForOutbox func(c context.Context, publicKeyId string, boxIRI *url.URL) (crypto.PublicKey, httpsig.Algorithm, error) - getSocialAPIVerifier func(c context.Context) SocialAPIVerifier -} - -func (m *MockSocialApp) ActorIRI(c context.Context, r *http.Request) (*url.URL, error) { - if m.actorIRI == nil { - m.t.Fatal("unexpected call to MockSocialApp ActorIRI") - } - return m.actorIRI(c, r) -} - -func (m *MockSocialApp) GetPublicKeyForOutbox(c context.Context, publicKeyId string, boxIRI *url.URL) (crypto.PublicKey, httpsig.Algorithm, error) { - if m.getPublicKeyForOutbox == nil { - m.t.Fatal("unexpected call to MockSocialApp GetPublicKeyForOutbox") - } - return m.getPublicKeyForOutbox(c, publicKeyId, boxIRI) -} - -func (m *MockSocialApp) GetSocialAPIVerifier(c context.Context) SocialAPIVerifier { - if m.getSocialAPIVerifier == nil { - m.t.Fatal("unexpected call to MockSocialApp GetSocialAPIVerifier") - } - return m.getSocialAPIVerifier(c) -} - -var _ Callbacker = &MockCallbacker{} - -type MockCallbacker struct { - t *testing.T - create func(c context.Context, s *streams.Create) error - update func(c context.Context, s *streams.Update) error - delete func(c context.Context, s *streams.Delete) error - add func(c context.Context, s *streams.Add) error - remove func(c context.Context, s *streams.Remove) error - like func(c context.Context, s *streams.Like) error - block func(c context.Context, s *streams.Block) error - follow func(c context.Context, s *streams.Follow) error - undo func(c context.Context, s *streams.Undo) error - accept func(c context.Context, s *streams.Accept) error - reject func(c context.Context, s *streams.Reject) error -} - -func (m *MockCallbacker) Create(c context.Context, s *streams.Create) error { - if m.create == nil { - m.t.Logf("unimplemented MockCallbacker Create called: %v %v", c, s) - return nil - } else { - return m.create(c, s) - } -} - -func (m *MockCallbacker) Update(c context.Context, s *streams.Update) error { - if m.update == nil { - m.t.Logf("unimplemented MockCallbacker Update called: %v %v", c, s) - return nil - } else { - return m.update(c, s) - } -} - -func (m *MockCallbacker) Delete(c context.Context, s *streams.Delete) error { - if m.delete == nil { - m.t.Logf("unimplemented MockCallbacker Delete called: %v %v", c, s) - return nil - } else { - return m.delete(c, s) - } -} - -func (m *MockCallbacker) Add(c context.Context, s *streams.Add) error { - if m.add == nil { - m.t.Logf("unimplemented MockCallbacker Add called: %v %v", c, s) - return nil - } else { - return m.add(c, s) - } -} - -func (m *MockCallbacker) Remove(c context.Context, s *streams.Remove) error { - if m.remove == nil { - m.t.Logf("unimplemented MockCallbacker Remove called: %v %v", c, s) - return nil - } else { - return m.remove(c, s) - } -} - -func (m *MockCallbacker) Like(c context.Context, s *streams.Like) error { - if m.like == nil { - m.t.Logf("unimplemented MockCallbacker Like called: %v %v", c, s) - return nil - } else { - return m.like(c, s) - } -} - -func (m *MockCallbacker) Block(c context.Context, s *streams.Block) error { - if m.block == nil { - m.t.Logf("unimplemented MockCallbacker Block called: %v %v", c, s) - return nil - } else { - return m.block(c, s) - } -} - -func (m *MockCallbacker) Follow(c context.Context, s *streams.Follow) error { - if m.follow == nil { - m.t.Logf("unimplemented MockCallbacker Follow called: %v %v", c, s) - return nil - } else { - return m.follow(c, s) - } -} - -func (m *MockCallbacker) Undo(c context.Context, s *streams.Undo) error { - if m.undo == nil { - m.t.Logf("unimplemented MockCallbacker Undo called: %v %v", c, s) - return nil - } else { - return m.undo(c, s) - } -} - -func (m *MockCallbacker) Accept(c context.Context, s *streams.Accept) error { - if m.accept == nil { - m.t.Logf("unimplemented MockCallbacker Accept called: %v %v", c, s) - return nil - } else { - return m.accept(c, s) - } -} - -func (m *MockCallbacker) Reject(c context.Context, s *streams.Reject) error { - if m.reject == nil { - m.t.Logf("unimplemented MockCallbacker Reject called: %v %v", c, s) - return nil - } else { - return m.reject(c, s) - } -} - -var _ FederateApplication = &MockFederateApp{} - -type MockFederateApp struct { - *MockApplication - t *testing.T - onFollow func(c context.Context, s *streams.Follow) FollowResponse - unblocked func(c context.Context, actorIRIs []*url.URL) error - filterForwarding func(c context.Context, activity vocab.ActivityType, iris []*url.URL) ([]*url.URL, error) - newSigner func() (httpsig.Signer, error) - privateKey func(boxIRI *url.URL) (crypto.PrivateKey, string, error) -} - -func (m *MockFederateApp) OnFollow(c context.Context, s *streams.Follow) FollowResponse { - if m.onFollow == nil { - m.t.Fatal("unexpected call to MockFederateApp OnFollow") - } - return m.onFollow(c, s) -} - -func (m *MockFederateApp) Unblocked(c context.Context, actorIRIs []*url.URL) error { - if m.unblocked == nil { - m.t.Fatal("unexpected call to MockFederateApp Unblocked") - } - return m.unblocked(c, actorIRIs) -} - -func (m *MockFederateApp) FilterForwarding(c context.Context, activity vocab.ActivityType, iris []*url.URL) ([]*url.URL, error) { - if m.filterForwarding == nil { - m.t.Fatal("unexpected call to MockFederateApp FilterForwarding") - } - return m.filterForwarding(c, activity, iris) -} - -func (m *MockFederateApp) NewSigner() (httpsig.Signer, error) { - if m.newSigner == nil { - m.t.Fatal("unexpected call to MockFederateApp NewSigner") - } - return m.newSigner() -} - -func (m *MockFederateApp) PrivateKey(boxIRI *url.URL) (privKey crypto.PrivateKey, pubKeyId string, err error) { - if m.privateKey == nil { - m.t.Fatal("unexpected call to MockFederateApp PrivateKey") - } - return m.privateKey(boxIRI) -} - -var _ SocialFederateApplication = &MockSocialFederateApp{} - -type MockSocialFederateApp struct { - *MockFederateApp - *MockSocialApp -} - -func (m *MockSocialFederateApp) Owns(c context.Context, id *url.URL) bool { - return m.MockFederateApp.Owns(c, id) -} -func (m *MockSocialFederateApp) Get(c context.Context, id *url.URL, rw RWType) (PubObject, error) { - return m.MockFederateApp.Get(c, id, rw) -} -func (m *MockSocialFederateApp) GetAsVerifiedUser(c context.Context, id, authdUser *url.URL, rw RWType) (PubObject, error) { - return m.MockFederateApp.GetAsVerifiedUser(c, id, authdUser, rw) -} -func (m *MockSocialFederateApp) Has(c context.Context, id *url.URL) (bool, error) { - return m.MockFederateApp.Has(c, id) -} -func (m *MockSocialFederateApp) Set(c context.Context, o PubObject) error { - return m.MockFederateApp.Set(c, o) -} -func (m *MockSocialFederateApp) GetInbox(c context.Context, r *http.Request, rw RWType) (vocab.OrderedCollectionType, error) { - return m.MockFederateApp.GetInbox(c, r, rw) -} -func (m *MockSocialFederateApp) GetOutbox(c context.Context, r *http.Request, rw RWType) (vocab.OrderedCollectionType, error) { - return m.MockFederateApp.GetOutbox(c, r, rw) -} -func (m *MockSocialFederateApp) NewId(c context.Context, t Typer) *url.URL { - return m.MockFederateApp.NewId(c, t) -} -func (m *MockSocialFederateApp) GetPublicKey(c context.Context, publicKeyId string) (crypto.PublicKey, httpsig.Algorithm, *url.URL, error) { - return m.MockFederateApp.GetPublicKey(c, publicKeyId) -} -func (m *MockSocialFederateApp) CanAdd(c context.Context, o vocab.ObjectType, t vocab.ObjectType) bool { - return m.MockFederateApp.CanAdd(c, o, t) -} -func (m *MockSocialFederateApp) CanRemove(c context.Context, o vocab.ObjectType, t vocab.ObjectType) bool { - return m.MockFederateApp.CanRemove(c, o, t) -} - -var _ Deliverer = &MockDeliverer{} - -type MockDeliverer struct { - t *testing.T - do func(b []byte, to *url.URL, toDo func(b []byte, u *url.URL) error) -} - -func (m *MockDeliverer) Do(b []byte, to *url.URL, toDo func(b []byte, u *url.URL) error) { - if m.do == nil { - m.t.Fatal("unexpected call to MockDeliverer Do") - } - m.do(b, to, toDo) -} - -var _ HttpClient = &MockHttpClient{} - -type MockHttpClient struct { - t *testing.T - do func(req *http.Request) (*http.Response, error) -} - -func (m *MockHttpClient) Do(req *http.Request) (*http.Response, error) { - if m.do == nil { - m.t.Fatal("unexpected call to MockHttpClient Do") - } - return m.do(req) -} - -var _ SocialAPIVerifier = &MockSocialAPIVerifier{} - -type MockSocialAPIVerifier struct { - t *testing.T - verify func(r *http.Request) (authenticatedUser *url.URL, authn, authz bool, err error) - verifyForOutbox func(r *http.Request, outbox *url.URL) (authn, authz bool, err error) -} - -func (m *MockSocialAPIVerifier) Verify(r *http.Request) (authenticatedUser *url.URL, authn, authz bool, err error) { - if m.verify == nil { - m.t.Fatal("unexpected call to MockSocialAPIVerifier Verify") - } - return m.verify(r) -} - -func (m *MockSocialAPIVerifier) VerifyForOutbox(r *http.Request, outbox *url.URL) (authn, authz bool, err error) { - if m.verifyForOutbox == nil { - m.t.Fatal("unexpected call to MockSocialAPIVerifier VerifyForOutbox") - } - return m.verifyForOutbox(r, outbox) -} - -func NewSocialPubberTest(t *testing.T) (app *MockApplication, socialApp *MockSocialApp, cb *MockCallbacker, p Pubber) { - clock := &MockClock{now} - app = &MockApplication{t: t} - socialApp = &MockSocialApp{MockApplication: app, t: t} - cb = &MockCallbacker{t: t} - p = NewSocialPubber(clock, socialApp, cb) - return -} - -func NewFederatingPubberTest(t *testing.T) (app *MockApplication, fedApp *MockFederateApp, cb *MockCallbacker, d *MockDeliverer, h *MockHttpClient, p Pubber) { - clock := &MockClock{now} - app = &MockApplication{t: t} - fedApp = &MockFederateApp{MockApplication: app, t: t} - cb = &MockCallbacker{t: t} - d = &MockDeliverer{t: t} - h = &MockHttpClient{t: t} - p = NewFederatingPubber(clock, fedApp, cb, d, h, testAgent, 1, 1) - return -} - -func NewPubberTest(t *testing.T) (app *MockSocialFederateApp, socialApp *MockSocialApp, fedApp *MockFederateApp, socialCb, fedCb *MockCallbacker, d *MockDeliverer, h *MockHttpClient, p Pubber) { - clock := &MockClock{now} - appl := &MockApplication{t: t} - socialApp = &MockSocialApp{t: t} - fedApp = &MockFederateApp{MockApplication: appl, t: t} - app = &MockSocialFederateApp{MockSocialApp: socialApp, MockFederateApp: fedApp} - socialCb = &MockCallbacker{t: t} - fedCb = &MockCallbacker{t: t} - d = &MockDeliverer{t: t} - h = &MockHttpClient{t: t} - p = NewPubber(clock, app, socialCb, fedCb, d, h, testAgent, 1, 1) - return -} - -func PreparePubberPostInboxTest(t *testing.T, app *MockSocialFederateApp, socialApp *MockSocialApp, fedApp *MockFederateApp, socialCb, fedCb *MockCallbacker, d *MockDeliverer, h *MockHttpClient, p Pubber) { - PreparePostInboxTest(t, app.MockFederateApp.MockApplication, socialApp, fedApp, socialCb, fedCb, d, h, p) -} - -func PreparePostInboxTest(t *testing.T, app *MockApplication, socialApp *MockSocialApp, fedApp *MockFederateApp, socialCb, fedCb *MockCallbacker, d *MockDeliverer, h *MockHttpClient, p Pubber) { - fedApp.unblocked = func(c context.Context, actorIRIs []*url.URL) error { - return nil - } - app.getInbox = func(c context.Context, r *http.Request, rw RWType) (vocab.OrderedCollectionType, error) { - if rw != ReadWrite { - t.Fatalf("expected RWType of %v, got %v", ReadWrite, rw) - } - oc := &vocab.OrderedCollection{} - oc.AppendType("OrderedCollection") - return oc, nil - } - app.set = func(c context.Context, o PubObject) error { - return nil - } - app.has = func(c context.Context, id *url.URL) (bool, error) { - return false, nil - } - return -} - -func PreparePubberPostOutboxTest(t *testing.T, app *MockSocialFederateApp, socialApp *MockSocialApp, fedApp *MockFederateApp, socialCb, fedCb *MockCallbacker, d *MockDeliverer, h *MockHttpClient, p Pubber) { - PreparePostOutboxTest(t, app.MockFederateApp.MockApplication, socialApp, fedApp, socialCb, fedCb, d, h, p) -} - -func PreparePostOutboxTest(t *testing.T, app *MockApplication, socialApp *MockSocialApp, fedApp *MockFederateApp, socialCb, fedCb *MockCallbacker, d *MockDeliverer, h *MockHttpClient, p Pubber) { - socialApp.getPublicKeyForOutbox = func(c context.Context, publicKeyId string, boxIRI *url.URL) (crypto.PublicKey, httpsig.Algorithm, error) { - return testPrivateKey.Public(), httpsig.RSA_SHA256, nil - } - socialApp.getSocialAPIVerifier = func(c context.Context) SocialAPIVerifier { - return nil - } - fedApp.newSigner = func() (httpsig.Signer, error) { - s, _, err := httpsig.NewSigner([]httpsig.Algorithm{httpsig.RSA_SHA256}, nil, httpsig.Signature) - if err != nil { - t.Fatal(err) - } - return s, err - } - fedApp.privateKey = func(boxIRI *url.URL) (crypto.PrivateKey, string, error) { - return testPrivateKey, testPublicKeyId, nil - } - gotNewId := 0 - app.newId = func(c context.Context, t Typer) *url.URL { - gotNewId++ - if gotNewId == 1 { - return testNewIRI - } else { - return testNewIRI2 - } - } - app.getOutbox = func(c context.Context, r *http.Request, rw RWType) (vocab.OrderedCollectionType, error) { - if rw != ReadWrite { - t.Fatalf("expected RWType of %v, got %v", ReadWrite, rw) - } - oc := &vocab.OrderedCollection{} - oc.AppendType("OrderedCollection") - return oc, nil - } - app.set = func(c context.Context, o PubObject) error { - return nil - } - gotHttpDo := 0 - h.do = func(req *http.Request) (*http.Response, error) { - gotHttpDo++ - if gotHttpDo == 1 { - actorResp := &http.Response{ - StatusCode: http.StatusOK, - Body: ioutil.NopCloser(bytes.NewBuffer(samActorJSON)), - } - return actorResp, nil - } else if gotHttpDo == 2 { - actorResp := &http.Response{ - StatusCode: http.StatusOK, - Body: ioutil.NopCloser(bytes.NewBuffer(sallyActorJSON)), - } - return actorResp, nil - } else if gotHttpDo == 3 { - okResp := &http.Response{ - StatusCode: http.StatusOK, - Body: ioutil.NopCloser(bytes.NewBuffer([]byte{})), - } - return okResp, nil - } - return nil, nil - } - d.do = func(b []byte, u *url.URL, toDo func(b []byte, u *url.URL) error) { - if err := toDo(b, u); err != nil { - t.Fatalf("Unexpected error in MockDeliverer.Do: %s", err) - } - } - return -} - -func TestSocialPubber_RejectPostInbox(t *testing.T) { - _, _, _, p := NewSocialPubberTest(t) - resp := httptest.NewRecorder() - req := ActivityPubRequest(httptest.NewRequest("POST", testInboxURI, nil)) - handled, err := p.PostInbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if resp.Code != http.StatusMethodNotAllowed { - t.Fatalf("expected %d, got %d", http.StatusMethodNotAllowed, resp.Code) - } -} - -func TestSocialPubber_GetInbox(t *testing.T) { - app, _, _, p := NewSocialPubberTest(t) - resp := httptest.NewRecorder() - req := ActivityPubRequest(httptest.NewRequest("GET", testInboxURI, nil)) - gotInbox := 0 - app.getInbox = func(c context.Context, r *http.Request, rw RWType) (vocab.OrderedCollectionType, error) { - if rw != Read { - t.Fatalf("expected RWType of %v, got %v", Read, rw) - } - gotInbox++ - return testSingleOrderedCollection, nil - } - handled, err := p.GetInbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotInbox != 1 { - t.Fatalf("expected %d, got %d", 1, gotInbox) - } else if l := len(resp.HeaderMap["Content-Type"]); l != 1 { - t.Fatalf("expected %d, got %d", 1, l) - } else if h := resp.HeaderMap["Content-Type"][0]; h != responseContentTypeHeader { - t.Fatalf("expected %s, got %s", responseContentTypeHeader, h) - } else if resp.Code != http.StatusOK { - t.Fatalf("expected %d, got %d", http.StatusOK, resp.Code) - } else if e := VocabEquals(resp.Body, testSingleOrderedCollection); e != nil { - t.Fatal(e) - } -} - -func TestSocialPubber_PostOutbox(t *testing.T) { - app, socialApp, cb, p := NewSocialPubberTest(t) - resp := httptest.NewRecorder() - req := Sign(ActivityPubRequest(httptest.NewRequest("POST", testOutboxURI, bytes.NewBuffer(MustSerialize(testCreateNote))))) - gotPublicKeyForOutbox := 0 - var gotPublicKeyId string - var gotBoxIRI *url.URL - socialApp.getPublicKeyForOutbox = func(c context.Context, publicKeyId string, boxIRI *url.URL) (crypto.PublicKey, httpsig.Algorithm, error) { - gotPublicKeyForOutbox++ - gotPublicKeyId = publicKeyId - gotBoxIRI = boxIRI - return testPrivateKey.Public(), httpsig.RSA_SHA256, nil - } - gotSocialAPIVerifier := 0 - socialApp.getSocialAPIVerifier = func(c context.Context) SocialAPIVerifier { - gotSocialAPIVerifier++ - return nil - } - gotNewId := 0 - app.newId = func(c context.Context, t Typer) *url.URL { - gotNewId++ - if gotNewId == 1 { - return testNewIRI - } - return testNewIRI2 - } - gotOutbox := 0 - app.getOutbox = func(c context.Context, r *http.Request, rw RWType) (vocab.OrderedCollectionType, error) { - if rw != ReadWrite { - t.Fatalf("expected RWType of %v, got %v", ReadWrite, rw) - } - gotOutbox++ - oc := &vocab.OrderedCollection{} - oc.AppendType("OrderedCollection") - return oc, nil - } - gotSet := 0 - var gotSetOutbox PubObject - var gotSetActivity PubObject - var gotSetCreateObject PubObject - app.set = func(c context.Context, o PubObject) error { - gotSet++ - if gotSet == 1 { - gotSetCreateObject = o - } else if gotSet == 2 { - gotSetActivity = o - } else if gotSet == 3 { - gotSetOutbox = o - } - return nil - } - gotCreate := 0 - var gotCreateCallback *streams.Create - cb.create = func(c context.Context, s *streams.Create) error { - gotCreate++ - gotCreateCallback = s - return nil - } - handled, err := p.PostOutbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if resp.Code != http.StatusCreated { - t.Fatalf("expected %d, got %d", http.StatusCreated, resp.Code) - } else if gotPublicKeyForOutbox != 1 { - t.Fatalf("expected %d, got %d", 1, gotPublicKeyForOutbox) - } else if gotPublicKeyId != testPublicKeyId { - t.Fatalf("expected %s, got %s", testPublicKeyId, gotPublicKeyId) - } else if s := gotBoxIRI.String(); s != testOutboxURI { - t.Fatalf("expected %s, got %s", testOutboxURI, s) - } else if gotSocialAPIVerifier != 1 { - t.Fatalf("expected %d, got %d", 1, gotSocialAPIVerifier) - } else if gotNewId != 2 { - t.Fatalf("expected %d, got %d", 2, gotNewId) - } else if gotOutbox != 1 { - t.Fatalf("expected %d, got %d", 1, gotOutbox) - } else if gotSet != 3 { - t.Fatalf("expected %d, got %d", 3, gotSet) - } else if l := gotSetOutbox.GetType(0).(string); l != "OrderedCollection" { - t.Fatalf("expected %s, got %s", "OrderedCollection", l) - } else if l := gotSetCreateObject.GetType(0).(string); l != "Note" { - t.Fatalf("expected %s, got %s", "Note", l) - } else if l := gotSetActivity.GetType(0).(string); l != "Create" { - t.Fatalf("expected %s, got %s", "Create", l) - } else if gotCreate != 1 { - t.Fatalf("expected %d, got %d", 1, gotCreate) - } else if iri := gotCreateCallback.Raw().GetActorObject(0).GetId(); *iri != *sallyIRI { - t.Fatalf("expected %s, got %s", sallyIRIString, iri.String()) - } else if l := len(resp.HeaderMap["Location"]); l != 1 { - t.Fatalf("expected %d, got %d", 1, l) - } else if h := resp.HeaderMap["Location"][0]; h != testNewIRIString { - t.Fatalf("expected %s, got %s", testNewIRI, h) - } else if resp.Code != http.StatusCreated { - t.Fatalf("expected %d, got %d", http.StatusCreated, resp.Code) - } -} - -func TestSocialPubber_PostOutbox_SocialAPIVerified(t *testing.T) { - app, socialApp, cb, p := NewSocialPubberTest(t) - resp := httptest.NewRecorder() - req := Sign(ActivityPubRequest(httptest.NewRequest("POST", testOutboxURI, bytes.NewBuffer(MustSerialize(testCreateNote))))) - gotVerifyForOutbox := 0 - var gotVerifiedOutbox *url.URL - socialApp.getSocialAPIVerifier = func(c context.Context) SocialAPIVerifier { - mockV := &MockSocialAPIVerifier{ - verifyForOutbox: func(r *http.Request, outbox *url.URL) (bool, bool, error) { - gotVerifyForOutbox++ - gotVerifiedOutbox = outbox - return true, true, nil - }, - } - return mockV - } - gotNewId := 0 - app.newId = func(c context.Context, t Typer) *url.URL { - gotNewId++ - if gotNewId == 1 { - return testNewIRI - } else { - return testNewIRI2 - } - } - gotOutbox := 0 - app.getOutbox = func(c context.Context, r *http.Request, rw RWType) (vocab.OrderedCollectionType, error) { - if rw != ReadWrite { - t.Fatalf("expected RWType of %v, got %v", ReadWrite, rw) - } - gotOutbox++ - oc := &vocab.OrderedCollection{} - oc.AppendType("OrderedCollection") - return oc, nil - } - gotSet := 0 - var gotSetOutbox PubObject - var gotSetActivity PubObject - var gotSetCreateObject PubObject - app.set = func(c context.Context, o PubObject) error { - gotSet++ - if gotSet == 1 { - gotSetCreateObject = o - } else if gotSet == 2 { - gotSetActivity = o - } else if gotSet == 3 { - gotSetOutbox = o - } - return nil - } - gotCreate := 0 - var gotCreateCallback *streams.Create - cb.create = func(c context.Context, s *streams.Create) error { - gotCreate++ - gotCreateCallback = s - return nil - } - handled, err := p.PostOutbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if resp.Code != http.StatusCreated { - t.Fatalf("expected %d, got %d", http.StatusCreated, resp.Code) - } else if gotVerifyForOutbox != 1 { - t.Fatalf("expected %d, got %d", 1, gotVerifyForOutbox) - } else if o := gotVerifiedOutbox.String(); o != testOutboxURI { - t.Fatalf("expected %s, got %s", testOutboxURI, o) - } else if gotNewId != 2 { - t.Fatalf("expected %d, got %d", 2, gotNewId) - } else if gotOutbox != 1 { - t.Fatalf("expected %d, got %d", 1, gotOutbox) - } else if gotSet != 3 { - t.Fatalf("expected %d, got %d", 3, gotSet) - } else if l := gotSetOutbox.GetType(0).(string); l != "OrderedCollection" { - t.Fatalf("expected %s, got %s", "OrderedCollection", l) - } else if l := gotSetCreateObject.GetType(0).(string); l != "Note" { - t.Fatalf("expected %s, got %s", "Note", l) - } else if l := gotSetActivity.GetType(0).(string); l != "Create" { - t.Fatalf("expected %s, got %s", "Create", l) - } else if gotCreate != 1 { - t.Fatalf("expected %d, got %d", 1, gotCreate) - } else if iri := gotCreateCallback.Raw().GetActorObject(0).GetId(); *iri != *sallyIRI { - t.Fatalf("expected %s, got %s", sallyIRIString, iri.String()) - } else if l := len(resp.HeaderMap["Location"]); l != 1 { - t.Fatalf("expected %d, got %d", 1, l) - } else if h := resp.HeaderMap["Location"][0]; h != testNewIRIString { - t.Fatalf("expected %s, got %s", testNewIRI, h) - } else if resp.Code != http.StatusCreated { - t.Fatalf("expected %d, got %d", http.StatusCreated, resp.Code) - } -} - -func TestSocialPubber_GetOutbox(t *testing.T) { - app, _, _, p := NewSocialPubberTest(t) - resp := httptest.NewRecorder() - req := ActivityPubRequest(httptest.NewRequest("GET", testOutboxURI, nil)) - gotOutbox := 0 - app.getOutbox = func(c context.Context, r *http.Request, rw RWType) (vocab.OrderedCollectionType, error) { - if rw != Read { - t.Fatalf("expected RWType of %v, got %v", Read, rw) - } - gotOutbox++ - return testSingleOrderedCollection, nil - } - handled, err := p.GetOutbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotOutbox != 1 { - t.Fatalf("expected %d, got %d", 1, gotOutbox) - } else if l := len(resp.HeaderMap["Content-Type"]); l != 1 { - t.Fatalf("expected %d, got %d", 1, l) - } else if h := resp.HeaderMap["Content-Type"][0]; h != responseContentTypeHeader { - t.Fatalf("expected %s, got %s", responseContentTypeHeader, h) - } else if resp.Code != http.StatusOK { - t.Fatalf("expected %d, got %d", http.StatusOK, resp.Code) - } else if e := VocabEquals(resp.Body, testSingleOrderedCollection); e != nil { - t.Fatal(e) - } -} - -func TestFederatingPubber_PostInbox(t *testing.T) { - app, fedApp, cb, _, _, p := NewFederatingPubberTest(t) - resp := httptest.NewRecorder() - req := ActivityPubRequest(httptest.NewRequest("POST", testInboxURI, bytes.NewBuffer(MustSerialize(testCreateNote)))) - gotUnblocked := 0 - var iri *url.URL - fedApp.unblocked = func(c context.Context, actorIRIs []*url.URL) error { - gotUnblocked++ - iri = actorIRIs[0] - return nil - } - gotInbox := 0 - app.getInbox = func(c context.Context, r *http.Request, rw RWType) (vocab.OrderedCollectionType, error) { - if rw != ReadWrite { - t.Fatalf("expected RWType of %v, got %v", ReadWrite, rw) - } - gotInbox++ - oc := &vocab.OrderedCollection{} - oc.AppendType("OrderedCollection") - return oc, nil - } - gotSet := 0 - var setObject PubObject - var inboxObject PubObject - app.set = func(c context.Context, o PubObject) error { - gotSet++ - if gotSet == 1 { - setObject = o - } else if gotSet == 2 { - inboxObject = o - } - return nil - } - gotHas := 0 - var hasIriActivity *url.URL - var hasIriTo *url.URL - app.has = func(c context.Context, id *url.URL) (bool, error) { - gotHas++ - if gotHas == 1 { - hasIriActivity = id - return false, nil - } else { - hasIriTo = id - return true, nil - } - } - gotGet := 0 - var gotIri *url.URL - app.get = func(c context.Context, iri *url.URL, rw RWType) (PubObject, error) { - if rw != Read { - t.Fatalf("expected RWType of %v, got %v", Read, rw) - } - gotGet++ - gotIri = iri - return samActor, nil - } - gotCreate := 0 - var gotCreateCallback *streams.Create - cb.create = func(c context.Context, s *streams.Create) error { - gotCreate++ - gotCreateCallback = s - return nil - } - handled, err := p.PostInbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotUnblocked != 1 { - t.Fatalf("expected %d, got %d", 1, gotUnblocked) - } else if iri.String() != sallyIRIString { - t.Fatalf("expected %s, got %s", sallyIRIString, iri.String()) - } else if gotInbox != 1 { - t.Fatalf("expected %d, got %d", 1, gotInbox) - } else if gotSet != 2 { - t.Fatalf("expected %d, got %d", 2, gotSet) - } else if l := inboxObject.GetType(0).(string); l != "OrderedCollection" { - t.Fatalf("expected %s, got %s", "OrderedCollection", l) - } else if l := setObject.GetType(0).(string); l != "Note" { - t.Fatalf("expected %s, got %s", "Note", l) - } else if gotHas != 2 { - t.Fatalf("expected %d, got %d", 2, gotHas) - } else if hasIriActivityString := hasIriActivity.String(); hasIriActivityString != noteActivityURIString { - t.Fatalf("expected %s, got %s", noteActivityURIString, hasIriActivityString) - } else if hasIriToString := hasIriTo.String(); hasIriToString != samIRIString { - t.Fatalf("expected %s, got %s", samIRIString, hasIriToString) - } else if gotGet != 1 { - t.Fatalf("expected %d, got %d", 1, gotGet) - } else if gotIriString := gotIri.String(); gotIriString != samIRIString { - t.Fatalf("expected %s, got %s", samIRIString, gotIriString) - } else if gotCreate != 1 { - t.Fatalf("expected %d, got %d", 1, gotCreate) - } else if s := gotCreateCallback.Raw().GetActorObject(0).GetId(); s.String() != sallyIRIString { - t.Fatalf("expected %s, got %s", sallyIRIString, s) - } else if resp.Code != http.StatusOK { - t.Fatalf("expected %d, got %d", http.StatusOK, resp.Code) - } -} - -func TestFederatingPubber_GetInbox(t *testing.T) { - app, _, _, _, _, p := NewFederatingPubberTest(t) - resp := httptest.NewRecorder() - req := ActivityPubRequest(httptest.NewRequest("GET", testInboxURI, nil)) - gotInbox := 0 - app.getInbox = func(c context.Context, r *http.Request, rw RWType) (vocab.OrderedCollectionType, error) { - if rw != Read { - t.Fatalf("expected RWType of %v, got %v", Read, rw) - } - gotInbox++ - return testSingleOrderedCollection, nil - } - handled, err := p.GetInbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotInbox != 1 { - t.Fatalf("expected %d, got %d", 1, gotInbox) - } else if l := len(resp.HeaderMap["Content-Type"]); l != 1 { - t.Fatalf("expected %d, got %d", 1, l) - } else if h := resp.HeaderMap["Content-Type"][0]; h != responseContentTypeHeader { - t.Fatalf("expected %s, got %s", responseContentTypeHeader, h) - } else if resp.Code != http.StatusOK { - t.Fatalf("expected %d, got %d", http.StatusOK, resp.Code) - } else if e := VocabEquals(resp.Body, testSingleOrderedCollection); e != nil { - t.Fatal(e) - } -} - -func TestFederatingPubber_RejectPostOutbox(t *testing.T) { - _, _, _, _, _, p := NewFederatingPubberTest(t) - resp := httptest.NewRecorder() - req := ActivityPubRequest(httptest.NewRequest("POST", testOutboxURI, nil)) - handled, err := p.PostOutbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if resp.Code != http.StatusMethodNotAllowed { - t.Fatalf("expected %d, got %d", http.StatusMethodNotAllowed, resp.Code) - } -} - -func TestFederatingPubber_GetOutbox(t *testing.T) { - app, _, _, _, _, p := NewFederatingPubberTest(t) - resp := httptest.NewRecorder() - req := ActivityPubRequest(httptest.NewRequest("GET", testOutboxURI, nil)) - gotOutbox := 0 - app.getOutbox = func(c context.Context, r *http.Request, rw RWType) (vocab.OrderedCollectionType, error) { - if rw != Read { - t.Fatalf("expected RWType of %v, got %v", Read, rw) - } - gotOutbox++ - return testSingleOrderedCollection, nil - } - handled, err := p.GetOutbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotOutbox != 1 { - t.Fatalf("expected %d, got %d", 1, gotOutbox) - } else if l := len(resp.HeaderMap["Content-Type"]); l != 1 { - t.Fatalf("expected %d, got %d", 1, l) - } else if h := resp.HeaderMap["Content-Type"][0]; h != responseContentTypeHeader { - t.Fatalf("expected %s, got %s", responseContentTypeHeader, h) - } else if resp.Code != http.StatusOK { - t.Fatalf("expected %d, got %d", http.StatusOK, resp.Code) - } else if e := VocabEquals(resp.Body, testSingleOrderedCollection); e != nil { - t.Fatal(e) - } -} - -func TestPubber_PostInbox(t *testing.T) { - app, _, fedApp, _, fedCb, _, _, p := NewPubberTest(t) - resp := httptest.NewRecorder() - req := ActivityPubRequest(httptest.NewRequest("POST", testInboxURI, bytes.NewBuffer(MustSerialize(testCreateNote)))) - gotUnblocked := 0 - var iri *url.URL - fedApp.unblocked = func(c context.Context, actorIRIs []*url.URL) error { - gotUnblocked++ - iri = actorIRIs[0] - return nil - } - gotInbox := 0 - app.MockFederateApp.getInbox = func(c context.Context, r *http.Request, rw RWType) (vocab.OrderedCollectionType, error) { - if rw != ReadWrite { - t.Fatalf("expected RWType of %v, got %v", ReadWrite, rw) - } - gotInbox++ - oc := &vocab.OrderedCollection{} - oc.AppendType("OrderedCollection") - return oc, nil - } - gotSet := 0 - var setObject PubObject - var inboxObject PubObject - app.MockFederateApp.set = func(c context.Context, o PubObject) error { - gotSet++ - if gotSet == 1 { - setObject = o - } else if gotSet == 2 { - inboxObject = o - } - return nil - } - gotHas := 0 - var hasIriActivity *url.URL - var hasIriTo *url.URL - app.MockFederateApp.has = func(c context.Context, id *url.URL) (bool, error) { - gotHas++ - if gotHas == 1 { - hasIriActivity = id - return false, nil - } else { - hasIriTo = id - return true, nil - } - } - gotGet := 0 - var gotIri *url.URL - app.MockFederateApp.get = func(c context.Context, iri *url.URL, rw RWType) (PubObject, error) { - if rw != Read { - t.Fatalf("expected RWType of %v, got %v", Read, rw) - } - gotGet++ - gotIri = iri - return samActor, nil - } - gotCreate := 0 - var gotCreateCallback *streams.Create - fedCb.create = func(c context.Context, s *streams.Create) error { - gotCreate++ - gotCreateCallback = s - return nil - } - handled, err := p.PostInbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotUnblocked != 1 { - t.Fatalf("expected %d, got %d", 1, gotUnblocked) - } else if iri.String() != sallyIRIString { - t.Fatalf("expected %s, got %s", sallyIRIString, iri.String()) - } else if gotInbox != 1 { - t.Fatalf("expected %d, got %d", 1, gotInbox) - } else if gotSet != 2 { - t.Fatalf("expected %d, got %d", 2, gotSet) - } else if l := inboxObject.GetType(0).(string); l != "OrderedCollection" { - t.Fatalf("expected %s, got %s", "OrderedCollection", l) - } else if l := setObject.GetType(0).(string); l != "Note" { - t.Fatalf("expected %s, got %s", "Note", l) - } else if gotHas != 2 { - t.Fatalf("expected %d, got %d", 2, gotHas) - } else if hasIriActivityString := hasIriActivity.String(); hasIriActivityString != noteActivityURIString { - t.Fatalf("expected %s, got %s", noteActivityURIString, hasIriActivityString) - } else if hasIriToString := hasIriTo.String(); hasIriToString != samIRIString { - t.Fatalf("expected %s, got %s", samIRIString, hasIriToString) - } else if gotGet != 1 { - t.Fatalf("expected %d, got %d", 1, gotGet) - } else if gotIriString := gotIri.String(); gotIriString != samIRIString { - t.Fatalf("expected %s, got %s", samIRIString, gotIriString) - } else if gotCreate != 1 { - t.Fatalf("expected %d, got %d", 1, gotCreate) - } else if s := gotCreateCallback.Raw().GetActorObject(0).GetId(); s.String() != sallyIRIString { - t.Fatalf("expected %s, got %s", sallyIRIString, s) - } else if resp.Code != http.StatusOK { - t.Fatalf("expected %d, got %d", http.StatusOK, resp.Code) - } -} - -func TestPubber_GetInbox(t *testing.T) { - app, _, _, _, _, _, _, p := NewPubberTest(t) - resp := httptest.NewRecorder() - req := ActivityPubRequest(httptest.NewRequest("GET", testInboxURI, nil)) - gotInbox := 0 - app.MockFederateApp.getInbox = func(c context.Context, r *http.Request, rw RWType) (vocab.OrderedCollectionType, error) { - if rw != Read { - t.Fatalf("expected RWType of %v, got %v", Read, rw) - } - gotInbox++ - return testSingleOrderedCollection, nil - } - handled, err := p.GetInbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotInbox != 1 { - t.Fatalf("expected %d, got %d", 1, gotInbox) - } else if l := len(resp.HeaderMap["Content-Type"]); l != 1 { - t.Fatalf("expected %d, got %d", 1, l) - } else if h := resp.HeaderMap["Content-Type"][0]; h != responseContentTypeHeader { - t.Fatalf("expected %s, got %s", responseContentTypeHeader, h) - } else if resp.Code != http.StatusOK { - t.Fatalf("expected %d, got %d", http.StatusOK, resp.Code) - } else if e := VocabEquals(resp.Body, testSingleOrderedCollection); e != nil { - t.Fatal(e) - } -} - -func TestPubber_PostOutbox(t *testing.T) { - app, socialApp, fedApp, socialCb, _, d, httpClient, p := NewPubberTest(t) - resp := httptest.NewRecorder() - req := Sign(ActivityPubRequest(httptest.NewRequest("POST", testOutboxURI, bytes.NewBuffer(MustSerialize(testCreateNote))))) - gotPublicKey := 0 - var gotPublicKeyId string - var gotBoxIRI *url.URL - socialApp.getPublicKeyForOutbox = func(c context.Context, publicKeyId string, boxIRI *url.URL) (crypto.PublicKey, httpsig.Algorithm, error) { - gotPublicKey++ - gotPublicKeyId = publicKeyId - gotBoxIRI = boxIRI - return testPrivateKey.Public(), httpsig.RSA_SHA256, nil - } - gotSocialAPIVerifier := 0 - socialApp.getSocialAPIVerifier = func(c context.Context) SocialAPIVerifier { - gotSocialAPIVerifier++ - return nil - } - gotNewSigner := 0 - fedApp.newSigner = func() (httpsig.Signer, error) { - gotNewSigner++ - s, _, err := httpsig.NewSigner([]httpsig.Algorithm{httpsig.RSA_SHA256}, nil, httpsig.Signature) - if err != nil { - t.Fatal(err) - } - return s, err - } - gotPrivateKey := 0 - var gotPrivateKeyIRI *url.URL - fedApp.privateKey = func(boxIRI *url.URL) (crypto.PrivateKey, string, error) { - gotPrivateKey++ - gotPrivateKeyIRI = boxIRI - return testPrivateKey, testPublicKeyId, nil - } - gotNewId := 0 - app.MockFederateApp.newId = func(c context.Context, t Typer) *url.URL { - gotNewId++ - if gotNewId == 1 { - return testNewIRI - } else { - return testNewIRI2 - } - } - gotOutbox := 0 - app.MockFederateApp.getOutbox = func(c context.Context, r *http.Request, rw RWType) (vocab.OrderedCollectionType, error) { - if rw != ReadWrite { - t.Fatalf("expected RWType of %v, got %v", ReadWrite, rw) - } - gotOutbox++ - oc := &vocab.OrderedCollection{} - oc.AppendType("OrderedCollection") - return oc, nil - } - gotSet := 0 - var gotSetOutbox PubObject - var gotSetActivity PubObject - var gotSetCreateObject PubObject - app.MockFederateApp.set = func(c context.Context, o PubObject) error { - gotSet++ - if gotSet == 1 { - gotSetCreateObject = o - } else if gotSet == 2 { - gotSetActivity = o - } else if gotSet == 3 { - gotSetOutbox = o - } - return nil - } - gotCreate := 0 - var gotCreateCallback *streams.Create - socialCb.create = func(c context.Context, s *streams.Create) error { - gotCreate++ - gotCreateCallback = s - return nil - } - gotHttpDo := 0 - var httpActorRequest *http.Request - var httpSenderRequest *http.Request - var httpDeliveryRequest *http.Request - httpClient.do = func(req *http.Request) (*http.Response, error) { - gotHttpDo++ - if gotHttpDo == 1 { - httpActorRequest = req - actorResp := &http.Response{ - StatusCode: http.StatusOK, - Body: ioutil.NopCloser(bytes.NewBuffer(samActorJSON)), - } - return actorResp, nil - } else if gotHttpDo == 2 { - httpSenderRequest = req - actorResp := &http.Response{ - StatusCode: http.StatusOK, - Body: ioutil.NopCloser(bytes.NewBuffer(sallyActorJSON)), - } - return actorResp, nil - } else if gotHttpDo == 3 { - httpDeliveryRequest = req - okResp := &http.Response{ - StatusCode: http.StatusOK, - Body: ioutil.NopCloser(bytes.NewBuffer([]byte{})), - } - return okResp, nil - } - return nil, nil - } - gotDoDelivery := 0 - var doDeliveryURL *url.URL - d.do = func(b []byte, u *url.URL, toDo func(b []byte, u *url.URL) error) { - gotDoDelivery++ - doDeliveryURL = u - if err := toDo(b, u); err != nil { - t.Fatalf("Unexpected error in MockDeliverer.Do: %s", err) - } - } - handled, err := p.PostOutbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotPublicKey != 1 { - t.Fatalf("expected %d, got %d", 1, gotPublicKey) - } else if gotPublicKeyId != testPublicKeyId { - t.Fatalf("expected %s, got %s", testPublicKeyId, gotPublicKeyId) - } else if s := gotBoxIRI.String(); s != testOutboxURI { - t.Fatalf("expected %s, got %s", testOutboxURI, s) - } else if gotSocialAPIVerifier != 1 { - t.Fatalf("expected %d, got %d", 1, gotSocialAPIVerifier) - } else if gotNewId != 2 { - t.Fatalf("expected %d, got %d", 2, gotNewId) - } else if gotNewSigner != 1 { - t.Fatalf("expected %d, got %d", 1, gotNewSigner) - } else if gotPrivateKey != 1 { - t.Fatalf("expected %d, got %d", 1, gotPrivateKey) - } else if s := gotPrivateKeyIRI.String(); s != testOutboxURI { - t.Fatalf("expected %s, got %s", testOutboxURI, s) - } else if gotOutbox != 1 { - t.Fatalf("expected %d, got %d", 1, gotOutbox) - } else if gotSet != 3 { - t.Fatalf("expected %d, got %d", 3, gotSet) - } else if l := gotSetOutbox.GetType(0).(string); l != "OrderedCollection" { - t.Fatalf("expected %s, got %s", "OrderedCollection", l) - } else if l := gotSetCreateObject.GetType(0).(string); l != "Note" { - t.Fatalf("expected %s, got %s", "Note", l) - } else if l := gotSetActivity.GetType(0).(string); l != "Create" { - t.Fatalf("expected %s, got %s", "Create", l) - } else if gotCreate != 1 { - t.Fatalf("expected %d, got %d", 1, gotCreate) - } else if iri := gotCreateCallback.Raw().GetActorObject(0).GetId(); iri.String() != sallyIRIString { - t.Fatalf("expected %s, got %s", sallyIRIString, iri.String()) - } else if gotDoDelivery != 1 { - t.Fatalf("expected %d, got %d", 1, gotDoDelivery) - } else if doDeliveryURL.String() != samIRIInboxString { - t.Fatalf("expected %s, got %s", samIRIInboxString, doDeliveryURL.String()) - } else if gotHttpDo != 3 { - t.Fatalf("expected %d, got %d", 3, gotHttpDo) - } else if h := httpActorRequest.Header.Get("Accept"); h != getAcceptHeader { - t.Fatalf("expected %s, got %s", getAcceptHeader, h) - } else if h := httpSenderRequest.Header.Get("Accept"); h != getAcceptHeader { - t.Fatalf("expected %s, got %s", getAcceptHeader, h) - } else if h := httpDeliveryRequest.Header.Get("Content-Type"); h != postContentTypeHeader { - t.Fatalf("expected %s, got %s", postContentTypeHeader, h) - } else if httpActorRequest.Method != "GET" { - t.Fatalf("expected %s, got %s", "GET", httpActorRequest.Method) - } else if httpSenderRequest.Method != "GET" { - t.Fatalf("expected %s, got %s", "GET", httpSenderRequest.Method) - } else if httpDeliveryRequest.Method != "POST" { - t.Fatalf("expected %s, got %s", "POST", httpDeliveryRequest.Method) - } else if s := httpActorRequest.URL.String(); s != samIRIString { - t.Fatalf("expected %s, got %s", samIRIString, s) - } else if s := httpSenderRequest.URL.String(); s != sallyIRIString { - t.Fatalf("expected %s, got %s", sallyIRIString, s) - } else if s := httpDeliveryRequest.URL.String(); s != samIRIInboxString { - t.Fatalf("expected %s, got %s", samIRIInboxString, s) - } else if l := len(resp.HeaderMap["Location"]); l != 1 { - t.Fatalf("expected %d, got %d", 1, l) - } else if h := resp.HeaderMap["Location"][0]; h != testNewIRIString { - t.Fatalf("expected %s, got %s", testNewIRI, h) - } else if resp.Code != http.StatusCreated { - t.Fatalf("expected %d, got %d", http.StatusCreated, resp.Code) - } - verif, err := httpsig.NewVerifier(httpDeliveryRequest) - if err != nil { - t.Fatal(err) - } else if verif.KeyId() != testPublicKeyId { - t.Fatalf("expected %s, got %s", testPublicKeyId, verif.KeyId()) - } else if err := verif.Verify(testPrivateKey.Public(), httpsig.RSA_SHA256); err != nil { - t.Fatal(err) - } -} - -func TestPubber_GetOutbox(t *testing.T) { - app, _, _, _, _, _, _, p := NewPubberTest(t) - resp := httptest.NewRecorder() - req := ActivityPubRequest(httptest.NewRequest("GET", testOutboxURI, nil)) - gotOutbox := 0 - app.MockFederateApp.getOutbox = func(c context.Context, r *http.Request, rw RWType) (vocab.OrderedCollectionType, error) { - if rw != Read { - t.Fatalf("expected RWType of %v, got %v", Read, rw) - } - gotOutbox++ - return testSingleOrderedCollection, nil - } - handled, err := p.GetOutbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotOutbox != 1 { - t.Fatalf("expected %d, got %d", 1, gotOutbox) - } else if l := len(resp.HeaderMap["Content-Type"]); l != 1 { - t.Fatalf("expected %d, got %d", 1, l) - } else if h := resp.HeaderMap["Content-Type"][0]; h != responseContentTypeHeader { - t.Fatalf("expected %s, got %s", responseContentTypeHeader, h) - } else if resp.Code != http.StatusOK { - t.Fatalf("expected %d, got %d", http.StatusOK, resp.Code) - } else if e := VocabEquals(resp.Body, testSingleOrderedCollection); e != nil { - t.Fatal(e) - } -} - -func TestPostInbox_RejectNonActivityPub(t *testing.T) { - _, _, _, _, _, _, _, p := NewPubberTest(t) - resp := httptest.NewRecorder() - req := httptest.NewRequest("POST", testInboxURI, bytes.NewBuffer(MustSerialize(testCreateNote))) - handled, err := p.PostInbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if handled { - t.Fatalf("expected !handled, got handled") - } -} - -func TestPostInbox_HandlesBlocked(t *testing.T) { - _, _, fedApp, _, _, _, _, p := NewPubberTest(t) - resp := httptest.NewRecorder() - req := ActivityPubRequest(httptest.NewRequest("POST", testInboxURI, bytes.NewBuffer(MustSerialize(testCreateNote)))) - blockedErr := fmt.Errorf("blocked") - gotBlocked := 0 - var iri *url.URL - fedApp.unblocked = func(c context.Context, actorIRIs []*url.URL) error { - gotBlocked++ - iri = actorIRIs[0] - return blockedErr - } - handled, err := p.PostInbox(context.Background(), resp, req) - if err != blockedErr { - t.Fatalf("expected %s, got %s", blockedErr, err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if *iri != *sallyIRI { - t.Fatalf("expected %s, got %s", sallyIRIString, iri.String()) - } -} - -func TestPostInbox_RequiresObject(t *testing.T) { - tests := []struct { - name string - input func() vocab.Serializer - }{ - { - name: "create", - input: func() vocab.Serializer { - v := &vocab.Create{} - v.SetId(noteActivityIRI) - v.AppendSummaryString("Sally created a note") - v.AppendActorObject(sallyActor) - v.AppendToObject(samActor) - return v - }, - }, - { - name: "update", - input: func() vocab.Serializer { - v := &vocab.Update{} - v.SetId(noteActivityIRI) - v.AppendSummaryString("Sally updated a note") - v.AppendActorObject(sallyActor) - v.AppendToObject(samActor) - return v - }, - }, - { - name: "delete", - input: func() vocab.Serializer { - v := &vocab.Delete{} - v.SetId(noteActivityIRI) - v.AppendActorObject(sallyActor) - v.AppendToObject(samActor) - return v - }, - }, - { - name: "follow", - input: func() vocab.Serializer { - v := &vocab.Follow{} - v.SetId(noteActivityIRI) - v.AppendActorObject(sallyActor) - v.AppendToObject(samActor) - return v - }, - }, - { - name: "add", - input: func() vocab.Serializer { - v := &vocab.Add{} - v.SetId(noteActivityIRI) - v.AppendActorObject(sallyActor) - v.AppendToObject(samActor) - v.AppendTargetObject(testNote) - return v - }, - }, - { - name: "remove", - input: func() vocab.Serializer { - v := &vocab.Remove{} - v.SetId(noteActivityIRI) - v.AppendActorObject(sallyActor) - v.AppendToObject(samActor) - v.AppendTargetObject(testNote) - return v - }, - }, - { - name: "like", - input: func() vocab.Serializer { - v := &vocab.Like{} - v.SetId(noteActivityIRI) - v.AppendActorObject(sallyActor) - v.AppendToObject(samActor) - return v - }, - }, - { - name: "block", - input: func() vocab.Serializer { - v := &vocab.Block{} - v.SetId(noteActivityIRI) - v.AppendActorObject(sallyActor) - v.AppendToObject(samActor) - return v - }, - }, - { - name: "undo", - input: func() vocab.Serializer { - v := &vocab.Undo{} - v.SetId(noteActivityIRI) - v.AppendActorObject(sallyActor) - v.AppendToObject(samActor) - return v - }, - }, - } - app, _, fedApp, _, _, _, _, p := NewPubberTest(t) - fedApp.unblocked = func(c context.Context, actorIRIs []*url.URL) error { - return nil - } - app.MockFederateApp.getInbox = func(c context.Context, r *http.Request, rw RWType) (vocab.OrderedCollectionType, error) { - inbox := &vocab.OrderedCollection{} - return inbox, nil - } - for _, test := range tests { - t.Logf("Running table test case %q", test.name) - resp := httptest.NewRecorder() - req := ActivityPubRequest(httptest.NewRequest("POST", testInboxURI, bytes.NewBuffer(MustSerialize(test.input())))) - handled, err := p.PostInbox(context.Background(), resp, req) - if resp.Code != http.StatusBadRequest { - t.Fatalf("(%s) expected %d, got %d", test.name, http.StatusBadRequest, resp.Code) - } else if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("(%s) expected handled, got !handled", test.name) - } - } -} - -func TestPostInbox_RequiresTarget(t *testing.T) { - tests := []struct { - name string - input func() vocab.Serializer - }{ - { - name: "add", - input: func() vocab.Serializer { - v := &vocab.Add{} - v.SetId(noteActivityIRI) - v.AppendActorObject(sallyActor) - v.AppendToObject(samActor) - v.AppendObject(testNote) - return v - }, - }, - { - name: "remove", - input: func() vocab.Serializer { - v := &vocab.Remove{} - v.SetId(noteActivityIRI) - v.AppendActorObject(sallyActor) - v.AppendToObject(samActor) - v.AppendObject(testNote) - return v - }, - }, - } - app, _, fedApp, _, _, _, _, p := NewPubberTest(t) - fedApp.unblocked = func(c context.Context, actorIRIs []*url.URL) error { - return nil - } - app.MockFederateApp.getInbox = func(c context.Context, r *http.Request, rw RWType) (vocab.OrderedCollectionType, error) { - inbox := &vocab.OrderedCollection{} - return inbox, nil - } - for _, test := range tests { - t.Logf("Running table test case %q", test.name) - resp := httptest.NewRecorder() - req := ActivityPubRequest(httptest.NewRequest("POST", testInboxURI, bytes.NewBuffer(MustSerialize(test.input())))) - handled, err := p.PostInbox(context.Background(), resp, req) - if resp.Code != http.StatusBadRequest { - t.Fatalf("(%s) expected %d, got %d", test.name, http.StatusBadRequest, resp.Code) - } else if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("(%s) expected handled, got !handled", test.name) - } - } -} - -func TestPostInbox_DoesNotAddToInboxIfDuplicate(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostInboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := ActivityPubRequest(httptest.NewRequest("POST", testInboxURI, bytes.NewBuffer(MustSerialize(testCreateNote)))) - gotSet := 0 - app.MockFederateApp.set = func(c context.Context, o PubObject) error { - gotSet++ - return nil - } - app.MockFederateApp.getInbox = func(c context.Context, r *http.Request, rw RWType) (vocab.OrderedCollectionType, error) { - inbox := &vocab.OrderedCollection{} - inbox.AppendOrderedItemsIRI(noteActivityIRI) - return inbox, nil - } - fedCb.create = func(c context.Context, s *streams.Create) error { - return nil - } - handled, err := p.PostInbox(context.Background(), resp, req) - expectedInbox := &vocab.OrderedCollection{} - expectedInbox.AppendOrderedItemsIRI(noteActivityIRI) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotSet != 0 { - t.Fatalf("expected %d, got %d", 0, gotSet) - } -} - -func TestPostInbox_OriginMustMatch(t *testing.T) { - tests := []struct { - name string - input func() vocab.ActivityType - }{ - { - name: "update", - input: func() vocab.ActivityType { - a := &vocab.Update{} - a.SetId(otherOriginIRI) - a.AppendActorIRI(otherOriginActorIRI) - a.AppendObject(testCreateNote) - return a - }, - }, - { - name: "delete", - input: func() vocab.ActivityType { - a := &vocab.Delete{} - a.SetId(otherOriginIRI) - a.AppendActorIRI(otherOriginActorIRI) - a.AppendObject(testCreateNote) - return a - }, - }, - { - name: "update", - input: func() vocab.ActivityType { - a := &vocab.Update{} - a.SetId(otherOriginIRI) - a.AppendActorIRI(otherOriginActorIRI) - a.AppendObjectIRI(noteIRI) - return a - }, - }, - { - name: "delete", - input: func() vocab.ActivityType { - a := &vocab.Delete{} - a.SetId(otherOriginIRI) - a.AppendActorIRI(otherOriginActorIRI) - a.AppendObjectIRI(noteIRI) - return a - }, - }, - } - for _, test := range tests { - t.Logf("Running table test case %q", test.name) - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostInboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := ActivityPubRequest(httptest.NewRequest("POST", testInboxURI, bytes.NewBuffer(MustSerialize(test.input())))) - handled, err := p.PostInbox(context.Background(), resp, req) - if !handled { - t.Fatalf("%q: expected handled, got !handled", test.name) - } else if err == nil { - t.Fatalf("%q: expected same origin error", test.name) - } - } -} - -func TestPostInbox_ActivityActorsMustCoverObjectActors(t *testing.T) { - tests := []struct { - name string - input func() vocab.ActivityType - }{ - { - name: "undo", - input: func() vocab.ActivityType { - a := &vocab.Undo{} - a.SetId(noteActivityIRI) - a.AppendActorObject(samActor) - a.AppendObject(testLikeNote) - return a - }, - }, - } - for _, test := range tests { - t.Logf("Running table test case %q", test.name) - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostInboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := ActivityPubRequest(httptest.NewRequest("POST", testInboxURI, bytes.NewBuffer(MustSerialize(test.input())))) - handled, err := p.PostInbox(context.Background(), resp, req) - if !handled { - t.Fatalf("%q: expected handled, got !handled", test.name) - } else if err == nil { - t.Fatalf("%q: expected actor mismatch error", test.name) - } - } -} - -func TestPostInbox_Create_SetsObject(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostInboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := ActivityPubRequest(httptest.NewRequest("POST", testInboxURI, bytes.NewBuffer(MustSerialize(testCreateNote)))) - gotSet := 0 - var setObject PubObject - var gotSetInbox PubObject - app.MockFederateApp.set = func(c context.Context, o PubObject) error { - gotSet++ - if gotSet == 1 { - setObject = o - } else if gotSet == 2 { - gotSetInbox = o - } - return nil - } - fedCb.create = func(c context.Context, s *streams.Create) error { - return nil - } - handled, err := p.PostInbox(context.Background(), resp, req) - expectedInbox := &vocab.OrderedCollection{} - expectedInbox.AppendType("OrderedCollection") - expectedInbox.AppendOrderedItemsIRI(testCreateNote.GetId()) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotSet != 2 { - t.Fatalf("expected %d, got %d", 2, gotSet) - } else if err := PubObjectEquals(setObject, testNote); err != nil { - t.Fatalf("unexpected set object: %s", err) - } else if err := PubObjectEquals(gotSetInbox, expectedInbox); err != nil { - t.Fatalf("unexpected callback object: %s", err) - } -} - -func TestPostInbox_Create_CallsCallback(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostInboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := ActivityPubRequest(httptest.NewRequest("POST", testInboxURI, bytes.NewBuffer(MustSerialize(testCreateNote)))) - gotCreate := 0 - var gotCreateCallback *streams.Create - fedCb.create = func(c context.Context, s *streams.Create) error { - gotCreate++ - gotCreateCallback = s - return nil - } - handled, err := p.PostInbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotCreate != 1 { - t.Fatalf("expected %d, got %d", 1, gotCreate) - } else if err := PubObjectEquals(gotCreateCallback.Raw(), testCreateNote); err != nil { - t.Fatalf("unexpected create callback: %s", err) - } -} - -func TestPostInbox_Update_SetsObject(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostInboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := ActivityPubRequest(httptest.NewRequest("POST", testInboxURI, bytes.NewBuffer(MustSerialize(testUpdateNote)))) - gotSet := 0 - var setObject PubObject - app.MockFederateApp.set = func(c context.Context, o PubObject) error { - gotSet++ - if gotSet == 1 { - setObject = o - } - return nil - } - fedCb.update = func(c context.Context, s *streams.Update) error { - return nil - } - handled, err := p.PostInbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotSet != 2 { - t.Fatalf("expected %d, got %d", 2, gotSet) - } else if err := PubObjectEquals(setObject, testNote); err != nil { - t.Fatalf("unexpected set object: %s", err) - } -} - -func TestPostInbox_Update_CallsCallback(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostInboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := ActivityPubRequest(httptest.NewRequest("POST", testInboxURI, bytes.NewBuffer(MustSerialize(testUpdateNote)))) - gotCallback := 0 - var gotStreamCallback *streams.Update - fedCb.update = func(c context.Context, s *streams.Update) error { - gotCallback++ - gotStreamCallback = s - return nil - } - handled, err := p.PostInbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotCallback != 1 { - t.Fatalf("expected %d, got %d", 1, gotCallback) - } else if err := PubObjectEquals(gotStreamCallback.Raw(), testUpdateNote); err != nil { - t.Fatalf("unexpected callback object: %s", err) - } -} - -func TestPostInbox_Delete_FetchesObject(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostInboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := ActivityPubRequest(httptest.NewRequest("POST", testInboxURI, bytes.NewBuffer(MustSerialize(testDeleteNote)))) - app.MockFederateApp.get = func(c context.Context, id *url.URL, rw RWType) (PubObject, error) { - if rw != ReadWrite { - t.Fatalf("expected RWType of %v, got %v", ReadWrite, rw) - } else if *id != *noteIRI { - t.Fatalf("expected %s, got %s", noteIRI, id) - } - return testNote, nil - } - fedCb.delete = func(c context.Context, s *streams.Delete) error { - return nil - } - handled, err := p.PostInbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } -} - -func TestPostInbox_Delete_SetsTombstone(t *testing.T) { - // Table test - tests := []struct { - name string - input func() PubObject - expected func() vocab.Serializer - }{ - { - name: "delete note", - input: func() PubObject { - return testNote - }, - expected: func() vocab.Serializer { - return testTombstoneNote - }, - }, - { - name: "forward published time", - input: func() PubObject { - testNote := &vocab.Note{} - testNote.SetId(noteIRI) - testNote.AppendType("Note") - testNote.AppendNameString(noteName) - testNote.AppendContentString("This is a simple note") - testNote.SetPublished(now) - return testNote - }, - expected: func() vocab.Serializer { - testTombstoneNote := &vocab.Tombstone{} - testTombstoneNote.SetId(noteIRI) - testTombstoneNote.AppendFormerTypeString("Note") - testTombstoneNote.SetDeleted(now) - testTombstoneNote.SetPublished(now) - return testTombstoneNote - }, - }, - { - name: "forward published iri", - input: func() PubObject { - testNote := &vocab.Note{} - testNote.SetId(noteIRI) - testNote.AppendType("Note") - testNote.AppendNameString(noteName) - testNote.AppendContentString("This is a simple note") - testNote.SetPublishedIRI(iri) - return testNote - }, - expected: func() vocab.Serializer { - testTombstoneNote := &vocab.Tombstone{} - testTombstoneNote.SetId(noteIRI) - testTombstoneNote.AppendFormerTypeString("Note") - testTombstoneNote.SetDeleted(now) - testTombstoneNote.SetPublishedIRI(iri) - return testTombstoneNote - }, - }, - { - name: "forward updated time", - input: func() PubObject { - testNote := &vocab.Note{} - testNote.SetId(noteIRI) - testNote.AppendType("Note") - testNote.AppendNameString(noteName) - testNote.AppendContentString("This is a simple note") - testNote.SetUpdated(now) - return testNote - }, - expected: func() vocab.Serializer { - testTombstoneNote := &vocab.Tombstone{} - testTombstoneNote.SetId(noteIRI) - testTombstoneNote.AppendFormerTypeString("Note") - testTombstoneNote.SetDeleted(now) - testTombstoneNote.SetUpdated(now) - return testTombstoneNote - }, - }, - { - name: "forward updated iri", - input: func() PubObject { - testNote := &vocab.Note{} - testNote.SetId(noteIRI) - testNote.AppendType("Note") - testNote.AppendNameString(noteName) - testNote.AppendContentString("This is a simple note") - testNote.SetUpdatedIRI(iri) - return testNote - }, - expected: func() vocab.Serializer { - testTombstoneNote := &vocab.Tombstone{} - testTombstoneNote.SetId(noteIRI) - testTombstoneNote.AppendFormerTypeString("Note") - testTombstoneNote.SetDeleted(now) - testTombstoneNote.SetUpdatedIRI(iri) - return testTombstoneNote - }, - }, - } - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostInboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - gotSet := 0 - var gotSetObject PubObject - app.MockFederateApp.set = func(c context.Context, p PubObject) error { - gotSet++ - if gotSet == 1 { - gotSetObject = p - } - return nil - } - fedCb.delete = func(c context.Context, s *streams.Delete) error { - return nil - } - for _, test := range tests { - t.Logf("Running table test case %q", test.name) - app.MockFederateApp.get = func(c context.Context, id *url.URL, rw RWType) (PubObject, error) { - return test.input(), nil - } - gotSet = 0 - resp := httptest.NewRecorder() - req := ActivityPubRequest(httptest.NewRequest("POST", testInboxURI, bytes.NewBuffer(MustSerialize(testDeleteNote)))) - handled, err := p.PostInbox(context.Background(), resp, req) - if err != nil { - t.Fatalf("(%q) %s", test.name, err) - } else if !handled { - t.Fatalf("(%q) expected handled, got !handled", test.name) - } else if gotSet != 2 { - t.Fatalf("(%q) expected %d, got %d", test.name, 2, gotSet) - } else if err := PubObjectEquals(gotSetObject, test.expected()); err != nil { - t.Fatalf("(%q) unexpected tombstone object: %s", test.name, err) - } - } -} - -func TestPostInbox_Delete_CallsCallback(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostInboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := ActivityPubRequest(httptest.NewRequest("POST", testInboxURI, bytes.NewBuffer(MustSerialize(testDeleteNote)))) - app.MockFederateApp.get = func(c context.Context, id *url.URL, rw RWType) (PubObject, error) { - return testNote, nil - } - gotCallback := 0 - var gotStreamCallback *streams.Delete - fedCb.delete = func(c context.Context, s *streams.Delete) error { - gotCallback++ - gotStreamCallback = s - return nil - } - handled, err := p.PostInbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotCallback != 1 { - t.Fatalf("expected %d, got %d", 1, gotCallback) - } else if err := PubObjectEquals(gotStreamCallback.Raw(), testDeleteNote); err != nil { - t.Fatalf("unexpected callback object: %s", err) - } -} - -func TestPostInbox_Follow_DoNothing(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostInboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := ActivityPubRequest(httptest.NewRequest("POST", testInboxURI, bytes.NewBuffer(MustSerialize(testFollow)))) - gotOnFollow := 0 - fedApp.onFollow = func(c context.Context, s *streams.Follow) FollowResponse { - gotOnFollow++ - return DoNothing - } - fedCb.follow = func(c context.Context, s *streams.Follow) error { - return nil - } - handled, err := p.PostInbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotOnFollow != 1 { - t.Fatalf("expected %d, got %d", 1, gotOnFollow) - } -} - -func TestPostInbox_Follow_AutoReject(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostInboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := ActivityPubRequest(httptest.NewRequest("POST", testInboxURI, bytes.NewBuffer(MustSerialize(testFollow)))) - gotOnFollow := 0 - fedApp.onFollow = func(c context.Context, s *streams.Follow) FollowResponse { - gotOnFollow++ - return AutomaticReject - } - gotNewSigner := 0 - fedApp.newSigner = func() (httpsig.Signer, error) { - gotNewSigner++ - s, _, err := httpsig.NewSigner([]httpsig.Algorithm{httpsig.RSA_SHA256}, nil, httpsig.Signature) - if err != nil { - t.Fatal(err) - } - return s, err - } - gotPrivateKey := 0 - var gotPrivateKeyIRI *url.URL - fedApp.privateKey = func(boxIRI *url.URL) (crypto.PrivateKey, string, error) { - gotPrivateKey++ - gotPrivateKeyIRI = boxIRI - return testPrivateKey, testPublicKeyId, nil - } - fedCb.follow = func(c context.Context, s *streams.Follow) error { - return nil - } - gotOwns := 0 - var ownsIRI *url.URL - app.MockFederateApp.owns = func(c context.Context, id *url.URL) bool { - gotOwns++ - ownsIRI = id - return true - } - gotHttpDo := 0 - var httpActorRequest *http.Request - var httpDeliveryRequest *http.Request - httpClient.do = func(req *http.Request) (*http.Response, error) { - gotHttpDo++ - if gotHttpDo == 1 { - httpActorRequest = req - actorResp := &http.Response{ - StatusCode: http.StatusOK, - Body: ioutil.NopCloser(bytes.NewBuffer(sallyActorJSON)), - } - return actorResp, nil - } else if gotHttpDo == 2 { - httpDeliveryRequest = req - okResp := &http.Response{ - StatusCode: http.StatusOK, - Body: ioutil.NopCloser(bytes.NewBuffer([]byte{})), - } - return okResp, nil - } - return nil, nil - } - gotDoDelivery := 0 - var doDeliveryURL *url.URL - var bytesToSend []byte - d.do = func(b []byte, u *url.URL, toDo func(b []byte, u *url.URL) error) { - gotDoDelivery++ - doDeliveryURL = u - bytesToSend = b - if err := toDo(b, u); err != nil { - t.Fatalf("Unexpected error in MockDeliverer.Do: %s", err) - } - } - expected := &vocab.Reject{} - expected.AppendObject(testFollow) - expected.AppendToIRI(sallyIRI) - handled, err := p.PostInbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotNewSigner != 1 { - t.Fatalf("expected %d, got %d", 1, gotNewSigner) - } else if gotPrivateKey != 1 { - t.Fatalf("expected %d, got %d", 1, gotPrivateKey) - } else if s := gotPrivateKeyIRI.String(); s != testInboxURI { - t.Fatalf("expected %s, got %s", testInboxURI, s) - } else if gotOnFollow != 1 { - t.Fatalf("expected %d, got %d", 1, gotOnFollow) - } else if gotHttpDo != 2 { - t.Fatalf("expected %d, got %d", 2, gotHttpDo) - } else if s := httpActorRequest.URL.String(); s != sallyIRIString { - t.Fatalf("expected %s, got %s", sallyIRIString, s) - } else if s := httpDeliveryRequest.URL.String(); s != sallyIRIInboxString { - t.Fatalf("expected %s, got %s", sallyIRIInboxString, s) - } else if gotOwns != 1 { - t.Fatalf("expected %d, got %d", 1, gotOwns) - } else if ownsIRI.String() != samIRIString { - t.Fatalf("expected %s, got %s", samIRIString, ownsIRI.String()) - } else if gotDoDelivery != 1 { - t.Fatalf("expected %d, got %d", 1, gotDoDelivery) - } else if doDeliveryURL.String() != sallyIRIInboxString { - t.Fatalf("expected %s, got %s", sallyIRIInboxString, doDeliveryURL.String()) - } else if err := VocabEquals(bytes.NewBuffer(bytesToSend), expected); err != nil { - t.Fatal(err) - } -} - -func TestPostInbox_Follow_AutoAccept(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostInboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := ActivityPubRequest(httptest.NewRequest("POST", testInboxURI, bytes.NewBuffer(MustSerialize(testFollow)))) - gotOnFollow := 0 - fedApp.onFollow = func(c context.Context, s *streams.Follow) FollowResponse { - gotOnFollow++ - return AutomaticAccept - } - gotNewSigner := 0 - fedApp.newSigner = func() (httpsig.Signer, error) { - gotNewSigner++ - s, _, err := httpsig.NewSigner([]httpsig.Algorithm{httpsig.RSA_SHA256}, nil, httpsig.Signature) - if err != nil { - t.Fatal(err) - } - return s, err - } - gotPrivateKey := 0 - var gotPrivateKeyIRI *url.URL - fedApp.privateKey = func(boxIRI *url.URL) (crypto.PrivateKey, string, error) { - gotPrivateKey++ - gotPrivateKeyIRI = boxIRI - return testPrivateKey, testPublicKeyId, nil - } - fedCb.follow = func(c context.Context, s *streams.Follow) error { - return nil - } - gotHttpDo := 0 - var httpActorRequest *http.Request - var httpDeliveryRequest *http.Request - httpClient.do = func(req *http.Request) (*http.Response, error) { - gotHttpDo++ - if gotHttpDo == 1 { - httpActorRequest = req - actorResp := &http.Response{ - StatusCode: http.StatusOK, - Body: ioutil.NopCloser(bytes.NewBuffer(sallyActorJSON)), - } - return actorResp, nil - } else if gotHttpDo == 2 { - httpDeliveryRequest = req - okResp := &http.Response{ - StatusCode: http.StatusOK, - Body: ioutil.NopCloser(bytes.NewBuffer([]byte{})), - } - return okResp, nil - } - return nil, nil - } - gotDoDelivery := 0 - var doDeliveryURL *url.URL - var bytesToSend []byte - d.do = func(b []byte, u *url.URL, toDo func(b []byte, u *url.URL) error) { - gotDoDelivery++ - doDeliveryURL = u - bytesToSend = b - if err := toDo(b, u); err != nil { - t.Fatalf("Unexpected error in MockDeliverer.Do: %s", err) - } - } - gotOwns := 0 - var ownsIRI *url.URL - app.MockFederateApp.owns = func(c context.Context, id *url.URL) bool { - gotOwns++ - ownsIRI = id - return true - } - gotGet := 0 - var getIRI *url.URL - app.MockFederateApp.get = func(c context.Context, id *url.URL, rw RWType) (PubObject, error) { - if rw != ReadWrite { - t.Fatalf("expected RWType of %v, got %v", ReadWrite, rw) - } - gotGet++ - getIRI = id - samActor := &vocab.Person{} - samActor.SetInboxAnyURI(samIRIInbox) - samActor.SetId(samIRI) - samActor.SetFollowersCollection(&vocab.Collection{}) - return samActor, nil - } - gotSet := 0 - var setObject PubObject - app.MockFederateApp.set = func(c context.Context, o PubObject) error { - gotSet++ - if gotSet == 1 { - setObject = o - } - return nil - } - expected := &vocab.Accept{} - expected.AppendObject(testFollow) - expected.AppendToIRI(sallyIRI) - expectedFollowers := &vocab.Collection{} - expectedFollowers.AppendItemsIRI(sallyIRI) - expectedActor := &vocab.Person{} - expectedActor.SetInboxAnyURI(samIRIInbox) - expectedActor.SetId(samIRI) - expectedActor.SetFollowersCollection(expectedFollowers) - handled, err := p.PostInbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotOnFollow != 1 { - t.Fatalf("expected %d, got %d", 1, gotOnFollow) - } else if gotNewSigner != 1 { - t.Fatalf("expected %d, got %d", 1, gotNewSigner) - } else if gotPrivateKey != 1 { - t.Fatalf("expected %d, got %d", 1, gotPrivateKey) - } else if s := gotPrivateKeyIRI.String(); s != testInboxURI { - t.Fatalf("expected %s, got %s", testInboxURI, s) - } else if gotHttpDo != 2 { - t.Fatalf("expected %d, got %d", 2, gotHttpDo) - } else if s := httpActorRequest.URL.String(); s != sallyIRIString { - t.Fatalf("expected %s, got %s", sallyIRIString, s) - } else if s := httpDeliveryRequest.URL.String(); s != sallyIRIInboxString { - t.Fatalf("expected %s, got %s", sallyIRIInboxString, s) - } else if gotDoDelivery != 1 { - t.Fatalf("expected %d, got %d", 1, gotDoDelivery) - } else if doDeliveryURL.String() != sallyIRIInboxString { - t.Fatalf("expected %s, got %s", sallyIRIInboxString, doDeliveryURL.String()) - } else if err := VocabEquals(bytes.NewBuffer(bytesToSend), expected); err != nil { - t.Fatal(err) - } else if gotOwns != 1 { - t.Fatalf("expected %d, got %d", 1, gotOwns) - } else if ownsIRI.String() != samIRIString { - t.Fatalf("expected %s, got %s", samIRIString, ownsIRI.String()) - } else if gotGet != 1 { - t.Fatalf("expected %d, got %d", 1, gotGet) - } else if getIRI.String() != samIRIString { - t.Fatalf("expected %s, got %s", samIRIString, getIRI.String()) - } else if gotSet != 2 { - t.Fatalf("expected %d, got %d", 2, gotSet) - } else if err := PubObjectEquals(setObject, expectedActor); err != nil { - t.Fatal(err) - } -} - -func TestPostInbox_Follow_AutoAcceptDefaultFollowersOrderedCollection(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostInboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := ActivityPubRequest(httptest.NewRequest("POST", testInboxURI, bytes.NewBuffer(MustSerialize(testFollow)))) - gotOnFollow := 0 - fedApp.onFollow = func(c context.Context, s *streams.Follow) FollowResponse { - gotOnFollow++ - return AutomaticAccept - } - gotNewSigner := 0 - fedApp.newSigner = func() (httpsig.Signer, error) { - gotNewSigner++ - s, _, err := httpsig.NewSigner([]httpsig.Algorithm{httpsig.RSA_SHA256}, nil, httpsig.Signature) - if err != nil { - t.Fatal(err) - } - return s, err - } - gotPrivateKey := 0 - var gotPrivateKeyIRI *url.URL - fedApp.privateKey = func(boxIRI *url.URL) (crypto.PrivateKey, string, error) { - gotPrivateKey++ - gotPrivateKeyIRI = boxIRI - return testPrivateKey, testPublicKeyId, nil - } - fedCb.follow = func(c context.Context, s *streams.Follow) error { - return nil - } - gotHttpDo := 0 - var httpActorRequest *http.Request - var httpDeliveryRequest *http.Request - httpClient.do = func(req *http.Request) (*http.Response, error) { - gotHttpDo++ - if gotHttpDo == 1 { - httpActorRequest = req - actorResp := &http.Response{ - StatusCode: http.StatusOK, - Body: ioutil.NopCloser(bytes.NewBuffer(sallyActorJSON)), - } - return actorResp, nil - } else if gotHttpDo == 2 { - httpDeliveryRequest = req - okResp := &http.Response{ - StatusCode: http.StatusOK, - Body: ioutil.NopCloser(bytes.NewBuffer([]byte{})), - } - return okResp, nil - } - return nil, nil - } - gotDoDelivery := 0 - var doDeliveryURL *url.URL - var bytesToSend []byte - d.do = func(b []byte, u *url.URL, toDo func(b []byte, u *url.URL) error) { - gotDoDelivery++ - doDeliveryURL = u - bytesToSend = b - if err := toDo(b, u); err != nil { - t.Fatalf("Unexpected error in MockDeliverer.Do: %s", err) - } - } - gotOwns := 0 - var ownsIRI *url.URL - app.MockFederateApp.owns = func(c context.Context, id *url.URL) bool { - gotOwns++ - ownsIRI = id - return true - } - gotGet := 0 - var getIRI *url.URL - app.MockFederateApp.get = func(c context.Context, id *url.URL, rw RWType) (PubObject, error) { - if rw != ReadWrite { - t.Fatalf("expected RWType of %v, got %v", ReadWrite, rw) - } - gotGet++ - getIRI = id - samActor := &vocab.Person{} - samActor.SetInboxAnyURI(samIRIInbox) - samActor.SetId(samIRI) - return samActor, nil - } - gotSet := 0 - var setObject PubObject - app.MockFederateApp.set = func(c context.Context, o PubObject) error { - gotSet++ - if gotSet == 1 { - setObject = o - } - return nil - } - expected := &vocab.Accept{} - expected.AppendObject(testFollow) - expected.AppendToIRI(sallyIRI) - expectedFollowers := &vocab.OrderedCollection{} - expectedFollowers.AppendOrderedItemsIRI(sallyIRI) - expectedActor := &vocab.Person{} - expectedActor.SetInboxAnyURI(samIRIInbox) - expectedActor.SetId(samIRI) - expectedActor.SetFollowersOrderedCollection(expectedFollowers) - handled, err := p.PostInbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotOnFollow != 1 { - t.Fatalf("expected %d, got %d", 1, gotOnFollow) - } else if gotNewSigner != 1 { - t.Fatalf("expected %d, got %d", 1, gotNewSigner) - } else if gotPrivateKey != 1 { - t.Fatalf("expected %d, got %d", 1, gotPrivateKey) - } else if s := gotPrivateKeyIRI.String(); s != testInboxURI { - t.Fatalf("expected %s, got %s", testInboxURI, s) - } else if gotHttpDo != 2 { - t.Fatalf("expected %d, got %d", 2, gotHttpDo) - } else if s := httpActorRequest.URL.String(); s != sallyIRIString { - t.Fatalf("expected %s, got %s", sallyIRIString, s) - } else if s := httpDeliveryRequest.URL.String(); s != sallyIRIInboxString { - t.Fatalf("expected %s, got %s", sallyIRIInboxString, s) - } else if gotDoDelivery != 1 { - t.Fatalf("expected %d, got %d", 1, gotDoDelivery) - } else if doDeliveryURL.String() != sallyIRIInboxString { - t.Fatalf("expected %s, got %s", sallyIRIInboxString, doDeliveryURL.String()) - } else if err := VocabEquals(bytes.NewBuffer(bytesToSend), expected); err != nil { - t.Fatal(err) - } else if gotOwns != 1 { - t.Fatalf("expected %d, got %d", 1, gotOwns) - } else if ownsIRI.String() != samIRIString { - t.Fatalf("expected %s, got %s", samIRIString, ownsIRI.String()) - } else if gotGet != 1 { - t.Fatalf("expected %d, got %d", 1, gotGet) - } else if getIRI.String() != samIRIString { - t.Fatalf("expected %s, got %s", samIRIString, getIRI.String()) - } else if gotSet != 2 { - t.Fatalf("expected %d, got %d", 2, gotSet) - } else if err := PubObjectEquals(setObject, expectedActor); err != nil { - t.Fatal(err) - } -} - -func TestPostInbox_Follow_DoesNotAddForAutoAcceptIfAlreadyPresent(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostInboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := ActivityPubRequest(httptest.NewRequest("POST", testInboxURI, bytes.NewBuffer(MustSerialize(testFollow)))) - fedApp.onFollow = func(c context.Context, s *streams.Follow) FollowResponse { - return AutomaticAccept - } - fedApp.newSigner = func() (httpsig.Signer, error) { - s, _, err := httpsig.NewSigner([]httpsig.Algorithm{httpsig.RSA_SHA256}, nil, httpsig.Signature) - if err != nil { - t.Fatal(err) - } - return s, err - } - fedApp.privateKey = func(boxIRI *url.URL) (crypto.PrivateKey, string, error) { - return testPrivateKey, testPublicKeyId, nil - } - fedCb.follow = func(c context.Context, s *streams.Follow) error { - return nil - } - gotHttpDo := 0 - httpClient.do = func(req *http.Request) (*http.Response, error) { - gotHttpDo++ - if gotHttpDo == 1 { - actorResp := &http.Response{ - StatusCode: http.StatusOK, - Body: ioutil.NopCloser(bytes.NewBuffer(sallyActorJSON)), - } - return actorResp, nil - } else if gotHttpDo == 2 { - okResp := &http.Response{ - StatusCode: http.StatusOK, - Body: ioutil.NopCloser(bytes.NewBuffer([]byte{})), - } - return okResp, nil - } - return nil, nil - } - d.do = func(b []byte, u *url.URL, toDo func(b []byte, u *url.URL) error) { - if err := toDo(b, u); err != nil { - t.Fatalf("Unexpected error in MockDeliverer.Do: %s", err) - } - } - app.MockFederateApp.owns = func(c context.Context, id *url.URL) bool { - return true - } - app.MockFederateApp.get = func(c context.Context, id *url.URL, rw RWType) (PubObject, error) { - if rw != ReadWrite { - t.Fatalf("expected RWType of %v, got %v", ReadWrite, rw) - } - followers := &vocab.Collection{} - followers.AppendItemsIRI(sallyIRI) - samActor := &vocab.Person{} - samActor.SetInboxAnyURI(samIRIInbox) - samActor.SetId(samIRI) - samActor.SetFollowersCollection(followers) - return samActor, nil - } - gotSet := 0 - var setObject PubObject - app.MockFederateApp.set = func(c context.Context, o PubObject) error { - gotSet++ - if gotSet == 1 { - setObject = o - } - return nil - } - expectedFollowers := &vocab.Collection{} - expectedFollowers.AppendItemsIRI(sallyIRI) - expectedActor := &vocab.Person{} - expectedActor.SetInboxAnyURI(samIRIInbox) - expectedActor.SetId(samIRI) - expectedActor.SetFollowersCollection(expectedFollowers) - handled, err := p.PostInbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotSet != 2 { - t.Fatalf("expected %d, got %d", 2, gotSet) - } else if err := PubObjectEquals(setObject, expectedActor); err != nil { - t.Fatal(err) - } -} - -func TestPostInbox_Follow_AutoAcceptFollowersIsOrderedCollection(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostInboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := ActivityPubRequest(httptest.NewRequest("POST", testInboxURI, bytes.NewBuffer(MustSerialize(testFollow)))) - fedApp.onFollow = func(c context.Context, s *streams.Follow) FollowResponse { - return AutomaticAccept - } - fedApp.newSigner = func() (httpsig.Signer, error) { - s, _, err := httpsig.NewSigner([]httpsig.Algorithm{httpsig.RSA_SHA256}, nil, httpsig.Signature) - if err != nil { - t.Fatal(err) - } - return s, err - } - fedApp.privateKey = func(boxIRI *url.URL) (crypto.PrivateKey, string, error) { - return testPrivateKey, testPublicKeyId, nil - } - fedCb.follow = func(c context.Context, s *streams.Follow) error { - return nil - } - gotHttpDo := 0 - httpClient.do = func(req *http.Request) (*http.Response, error) { - gotHttpDo++ - if gotHttpDo == 1 { - actorResp := &http.Response{ - StatusCode: http.StatusOK, - Body: ioutil.NopCloser(bytes.NewBuffer(sallyActorJSON)), - } - return actorResp, nil - } else if gotHttpDo == 2 { - okResp := &http.Response{ - StatusCode: http.StatusOK, - Body: ioutil.NopCloser(bytes.NewBuffer([]byte{})), - } - return okResp, nil - } - return nil, nil - } - d.do = func(b []byte, u *url.URL, toDo func(b []byte, u *url.URL) error) { - if err := toDo(b, u); err != nil { - t.Fatalf("Unexpected error in MockDeliverer.Do: %s", err) - } - } - app.MockFederateApp.owns = func(c context.Context, id *url.URL) bool { - return true - } - app.MockFederateApp.get = func(c context.Context, id *url.URL, rw RWType) (PubObject, error) { - if rw != ReadWrite { - t.Fatalf("expected RWType of %v, got %v", ReadWrite, rw) - } - samActor := &vocab.Person{} - samActor.SetInboxAnyURI(samIRIInbox) - samActor.SetId(samIRI) - samActor.SetFollowersOrderedCollection(&vocab.OrderedCollection{}) - return samActor, nil - } - gotSet := 0 - var setObject PubObject - app.MockFederateApp.set = func(c context.Context, o PubObject) error { - gotSet++ - if gotSet == 1 { - setObject = o - } - return nil - } - handled, err := p.PostInbox(context.Background(), resp, req) - expectedFollowers := &vocab.OrderedCollection{} - expectedFollowers.AppendOrderedItemsIRI(sallyIRI) - expectedActor := &vocab.Person{} - expectedActor.SetInboxAnyURI(samIRIInbox) - expectedActor.SetId(samIRI) - expectedActor.SetFollowersOrderedCollection(expectedFollowers) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if err := PubObjectEquals(setObject, expectedActor); err != nil { - t.Fatal(err) - } -} - -func TestPostInbox_Follow_AutoAcceptFollowersIsIRI(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostInboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := ActivityPubRequest(httptest.NewRequest("POST", testInboxURI, bytes.NewBuffer(MustSerialize(testFollow)))) - fedApp.onFollow = func(c context.Context, s *streams.Follow) FollowResponse { - return AutomaticAccept - } - fedApp.newSigner = func() (httpsig.Signer, error) { - s, _, err := httpsig.NewSigner([]httpsig.Algorithm{httpsig.RSA_SHA256}, nil, httpsig.Signature) - if err != nil { - t.Fatal(err) - } - return s, err - } - fedApp.privateKey = func(boxIRI *url.URL) (crypto.PrivateKey, string, error) { - return testPrivateKey, testPublicKeyId, nil - } - fedCb.follow = func(c context.Context, s *streams.Follow) error { - return nil - } - gotHttpDo := 0 - httpClient.do = func(req *http.Request) (*http.Response, error) { - gotHttpDo++ - if gotHttpDo == 1 { - actorResp := &http.Response{ - StatusCode: http.StatusOK, - Body: ioutil.NopCloser(bytes.NewBuffer(sallyActorJSON)), - } - return actorResp, nil - } else if gotHttpDo == 2 { - okResp := &http.Response{ - StatusCode: http.StatusOK, - Body: ioutil.NopCloser(bytes.NewBuffer([]byte{})), - } - return okResp, nil - } - return nil, nil - } - d.do = func(b []byte, u *url.URL, toDo func(b []byte, u *url.URL) error) { - if err := toDo(b, u); err != nil { - t.Fatalf("Unexpected error in MockDeliverer.Do: %s", err) - } - } - app.MockFederateApp.owns = func(c context.Context, id *url.URL) bool { - return true - } - app.MockFederateApp.get = func(c context.Context, id *url.URL, rw RWType) (PubObject, error) { - if rw != ReadWrite { - t.Fatalf("expected RWType of %v, got %v", ReadWrite, rw) - } - if *id == *samIRI { - samActor := &vocab.Person{} - samActor.SetInboxAnyURI(samIRIInbox) - samActor.SetId(samIRI) - samActor.SetFollowersAnyURI(testNewIRI) - return samActor, nil - } else if *id == *testNewIRI { - return &vocab.Collection{}, nil - } - t.Fatalf("unexpected get(%s)", id) - return nil, nil - } - gotSet := 0 - var setObject PubObject - app.MockFederateApp.set = func(c context.Context, o PubObject) error { - gotSet++ - if gotSet == 1 { - setObject = o - } - return nil - } - handled, err := p.PostInbox(context.Background(), resp, req) - expectedFollowers := &vocab.Collection{} - expectedFollowers.AppendItemsIRI(sallyIRI) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if err := PubObjectEquals(setObject, expectedFollowers); err != nil { - t.Fatal(err) - } -} - -func TestPostInbox_Follow_DoesNotAutoAcceptIfNotOwned(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostInboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := ActivityPubRequest(httptest.NewRequest("POST", testInboxURI, bytes.NewBuffer(MustSerialize(testFollow)))) - fedApp.onFollow = func(c context.Context, s *streams.Follow) FollowResponse { - return AutomaticAccept - } - fedCb.follow = func(c context.Context, s *streams.Follow) error { - return nil - } - app.MockFederateApp.owns = func(c context.Context, id *url.URL) bool { - return false - } - handled, err := p.PostInbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } -} - -func TestPostInbox_Follow_DoesNotAutoRejectIfNotOwned(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostInboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := ActivityPubRequest(httptest.NewRequest("POST", testInboxURI, bytes.NewBuffer(MustSerialize(testFollow)))) - fedApp.onFollow = func(c context.Context, s *streams.Follow) FollowResponse { - return AutomaticReject - } - fedCb.follow = func(c context.Context, s *streams.Follow) error { - return nil - } - app.MockFederateApp.owns = func(c context.Context, id *url.URL) bool { - return false - } - handled, err := p.PostInbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } -} - -func TestPostInbox_Follow_CallsCallback(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostInboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := ActivityPubRequest(httptest.NewRequest("POST", testInboxURI, bytes.NewBuffer(MustSerialize(testFollow)))) - fedApp.onFollow = func(c context.Context, s *streams.Follow) FollowResponse { - return DoNothing - } - gotCallback := 0 - var gotCallbackObject *streams.Follow - fedCb.follow = func(c context.Context, s *streams.Follow) error { - gotCallback++ - gotCallbackObject = s - return nil - } - handled, err := p.PostInbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotCallback != 1 { - t.Fatalf("expected %d, got %d", 1, gotCallback) - } else if err := PubObjectEquals(gotCallbackObject.Raw(), testFollow); err != nil { - t.Fatalf("unexpected callback object: %s", err) - } -} - -func TestPostInbox_Accept_DoesNothingIfNotAcceptingFollow(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostInboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := ActivityPubRequest(httptest.NewRequest("POST", testInboxURI, bytes.NewBuffer(MustSerialize(testAcceptNote)))) - fedCb.accept = func(c context.Context, s *streams.Accept) error { - return nil - } - handled, err := p.PostInbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } -} - -func TestPostInbox_Accept_AcceptFollowAddsToFollowersIfOwned(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostInboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := ActivityPubRequest(httptest.NewRequest("POST", testInboxURI, bytes.NewBuffer(MustSerialize(testAcceptFollow)))) - gotOwns := 0 - var ownsIRI *url.URL - app.MockFederateApp.owns = func(c context.Context, id *url.URL) bool { - gotOwns++ - ownsIRI = id - return true - } - gotGet := 0 - var getIRI *url.URL - app.MockFederateApp.get = func(c context.Context, id *url.URL, rw RWType) (PubObject, error) { - if rw != ReadWrite { - t.Fatalf("expected RWType of %v, got %v", ReadWrite, rw) - } - gotGet++ - getIRI = id - sallyActor := &vocab.Person{} - sallyActor.SetInboxAnyURI(sallyIRIInbox) - sallyActor.SetId(sallyIRI) - sallyActor.SetFollowingCollection(&vocab.Collection{}) - return sallyActor, nil - } - gotSet := 0 - var setObject PubObject - app.MockFederateApp.set = func(c context.Context, o PubObject) error { - gotSet++ - if gotSet == 1 { - setObject = o - } - return nil - } - fedCb.accept = func(c context.Context, s *streams.Accept) error { - return nil - } - expectedFollowing := &vocab.Collection{} - expectedFollowing.AppendItemsIRI(samIRI) - expectedActor := &vocab.Person{} - expectedActor.SetInboxAnyURI(sallyIRIInbox) - expectedActor.SetId(sallyIRI) - expectedActor.SetFollowingCollection(expectedFollowing) - handled, err := p.PostInbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotOwns != 1 { - t.Fatalf("expected %d, got %d", 1, gotOwns) - } else if ownsIRI.String() != sallyIRIString { - t.Fatalf("expected %s, got %s", sallyIRIString, ownsIRI.String()) - } else if gotGet != 1 { - t.Fatalf("expected %d, got %d", 1, gotGet) - } else if getIRI.String() != sallyIRIString { - t.Fatalf("expected %s, got %s", sallyIRIString, getIRI.String()) - } else if gotSet != 2 { - t.Fatalf("expected %d, got %d", 2, gotSet) - } else if err := PubObjectEquals(setObject, expectedActor); err != nil { - t.Fatal(err) - } -} - -func TestPostInbox_Accept_AcceptFollowAddsToDefaultFollowersOrderedCollection(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostInboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := ActivityPubRequest(httptest.NewRequest("POST", testInboxURI, bytes.NewBuffer(MustSerialize(testAcceptFollow)))) - gotOwns := 0 - var ownsIRI *url.URL - app.MockFederateApp.owns = func(c context.Context, id *url.URL) bool { - gotOwns++ - ownsIRI = id - return true - } - gotGet := 0 - var getIRI *url.URL - app.MockFederateApp.get = func(c context.Context, id *url.URL, rw RWType) (PubObject, error) { - if rw != ReadWrite { - t.Fatalf("expected RWType of %v, got %v", ReadWrite, rw) - } - gotGet++ - getIRI = id - sallyActor := &vocab.Person{} - sallyActor.SetInboxAnyURI(sallyIRIInbox) - sallyActor.SetId(sallyIRI) - return sallyActor, nil - } - gotSet := 0 - var setObject PubObject - app.MockFederateApp.set = func(c context.Context, o PubObject) error { - gotSet++ - if gotSet == 1 { - setObject = o - } - return nil - } - fedCb.accept = func(c context.Context, s *streams.Accept) error { - return nil - } - expectedFollowing := &vocab.OrderedCollection{} - expectedFollowing.AppendOrderedItemsIRI(samIRI) - expectedActor := &vocab.Person{} - expectedActor.SetInboxAnyURI(sallyIRIInbox) - expectedActor.SetId(sallyIRI) - expectedActor.SetFollowingOrderedCollection(expectedFollowing) - handled, err := p.PostInbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotOwns != 1 { - t.Fatalf("expected %d, got %d", 1, gotOwns) - } else if ownsIRI.String() != sallyIRIString { - t.Fatalf("expected %s, got %s", sallyIRIString, ownsIRI.String()) - } else if gotGet != 1 { - t.Fatalf("expected %d, got %d", 1, gotGet) - } else if getIRI.String() != sallyIRIString { - t.Fatalf("expected %s, got %s", sallyIRIString, getIRI.String()) - } else if gotSet != 2 { - t.Fatalf("expected %d, got %d", 2, gotSet) - } else if err := PubObjectEquals(setObject, expectedActor); err != nil { - t.Fatal(err) - } -} - -func TestPostInbox_Accept_AcceptFollowDoesNotAddIfAlreadyInCollection(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostInboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := ActivityPubRequest(httptest.NewRequest("POST", testInboxURI, bytes.NewBuffer(MustSerialize(testAcceptFollow)))) - app.MockFederateApp.owns = func(c context.Context, id *url.URL) bool { - return true - } - app.MockFederateApp.get = func(c context.Context, id *url.URL, rw RWType) (PubObject, error) { - following := &vocab.Collection{} - following.AppendItemsIRI(samIRI) - sallyActor := &vocab.Person{} - sallyActor.SetInboxAnyURI(sallyIRIInbox) - sallyActor.SetId(sallyIRI) - sallyActor.SetFollowingCollection(following) - return sallyActor, nil - } - gotSet := 0 - var setObject PubObject - app.MockFederateApp.set = func(c context.Context, o PubObject) error { - gotSet++ - if gotSet == 1 { - setObject = o - } - return nil - } - fedCb.accept = func(c context.Context, s *streams.Accept) error { - return nil - } - expectedFollowing := &vocab.Collection{} - expectedFollowing.AppendItemsIRI(samIRI) - expectedActor := &vocab.Person{} - expectedActor.SetInboxAnyURI(sallyIRIInbox) - expectedActor.SetId(sallyIRI) - expectedActor.SetFollowingCollection(expectedFollowing) - handled, err := p.PostInbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotSet != 2 { - t.Fatalf("expected %d, got %d", 2, gotSet) - } else if err := PubObjectEquals(setObject, expectedActor); err != nil { - t.Fatal(err) - } -} - -func TestPostInbox_Accept_AcceptFollowAddsToFollowersOrderedCollection(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostInboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := ActivityPubRequest(httptest.NewRequest("POST", testInboxURI, bytes.NewBuffer(MustSerialize(testAcceptFollow)))) - app.MockFederateApp.owns = func(c context.Context, id *url.URL) bool { - return true - } - app.MockFederateApp.get = func(c context.Context, id *url.URL, rw RWType) (PubObject, error) { - if rw != ReadWrite { - t.Fatalf("expected RWType of %v, got %v", ReadWrite, rw) - } - sallyActor := &vocab.Person{} - sallyActor.SetInboxAnyURI(sallyIRIInbox) - sallyActor.SetId(sallyIRI) - sallyActor.SetFollowingOrderedCollection(&vocab.OrderedCollection{}) - return sallyActor, nil - } - gotSet := 0 - var setObject PubObject - app.MockFederateApp.set = func(c context.Context, o PubObject) error { - gotSet++ - if gotSet == 1 { - setObject = o - } - return nil - } - fedCb.accept = func(c context.Context, s *streams.Accept) error { - return nil - } - expectedFollowing := &vocab.OrderedCollection{} - expectedFollowing.AppendOrderedItemsIRI(samIRI) - expectedActor := &vocab.Person{} - expectedActor.SetInboxAnyURI(sallyIRIInbox) - expectedActor.SetId(sallyIRI) - expectedActor.SetFollowingOrderedCollection(expectedFollowing) - handled, err := p.PostInbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if err := PubObjectEquals(setObject, expectedActor); err != nil { - t.Fatal(err) - } -} - -func TestPostInbox_Accept_AcceptFollowAddsToFollowersIRI(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostInboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := ActivityPubRequest(httptest.NewRequest("POST", testInboxURI, bytes.NewBuffer(MustSerialize(testAcceptFollow)))) - app.MockFederateApp.owns = func(c context.Context, id *url.URL) bool { - return true - } - app.MockFederateApp.get = func(c context.Context, id *url.URL, rw RWType) (PubObject, error) { - if rw != ReadWrite { - t.Fatalf("expected RWType of %v, got %v", ReadWrite, rw) - } - if *id == *sallyIRI { - sallyActor := &vocab.Person{} - sallyActor.SetInboxAnyURI(sallyIRIInbox) - sallyActor.SetId(sallyIRI) - sallyActor.SetFollowingAnyURI(sallyFollowingIRI) - return sallyActor, nil - } else if *id == *sallyFollowingIRI { - return &vocab.OrderedCollection{}, nil - } - t.Fatalf("unexpected get(%s)", id.String()) - return nil, nil - } - gotSet := 0 - var setObject PubObject - app.MockFederateApp.set = func(c context.Context, o PubObject) error { - gotSet++ - if gotSet == 1 { - setObject = o - } - return nil - } - fedCb.accept = func(c context.Context, s *streams.Accept) error { - return nil - } - expectedFollowing := &vocab.OrderedCollection{} - expectedFollowing.AppendOrderedItemsIRI(samIRI) - handled, err := p.PostInbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if err := PubObjectEquals(setObject, expectedFollowing); err != nil { - t.Fatal(err) - } -} - -func TestPostInbox_Accept_DoesNothingIfNotOwned(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostInboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := ActivityPubRequest(httptest.NewRequest("POST", testInboxURI, bytes.NewBuffer(MustSerialize(testAcceptFollow)))) - gotOwns := 0 - var ownsIRI *url.URL - app.MockFederateApp.owns = func(c context.Context, id *url.URL) bool { - gotOwns++ - ownsIRI = id - return false - } - fedCb.accept = func(c context.Context, s *streams.Accept) error { - return nil - } - handled, err := p.PostInbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotOwns != 1 { - t.Fatalf("expected %d, got %d", 1, gotOwns) - } else if ownsIRI.String() != sallyIRIString { - t.Fatalf("expected %s, got %s", sallyIRIString, ownsIRI.String()) - } -} - -func TestPostInbox_Accept_CallsCallback(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostInboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := ActivityPubRequest(httptest.NewRequest("POST", testInboxURI, bytes.NewBuffer(MustSerialize(testAcceptFollow)))) - app.MockFederateApp.owns = func(c context.Context, id *url.URL) bool { - return true - } - app.MockFederateApp.get = func(c context.Context, id *url.URL, rw RWType) (PubObject, error) { - sallyActor := &vocab.Person{} - sallyActor.SetInboxAnyURI(sallyIRIInbox) - sallyActor.SetId(sallyIRI) - sallyActor.SetFollowingCollection(&vocab.Collection{}) - return sallyActor, nil - } - gotCallback := 0 - var gotCallbackObject *streams.Accept - fedCb.accept = func(c context.Context, s *streams.Accept) error { - gotCallback++ - gotCallbackObject = s - return nil - } - expectedFollowing := &vocab.Collection{} - expectedFollowing.AppendItemsObject(samActor) - handled, err := p.PostInbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotCallback != 1 { - t.Fatalf("expected %d, got %d", 1, gotCallback) - } else if err := PubObjectEquals(gotCallbackObject.Raw(), testAcceptFollow); err != nil { - t.Fatalf("unexpected callback object: %s", err) - } -} - -func TestPostInbox_Reject_CallsCallback(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostInboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := ActivityPubRequest(httptest.NewRequest("POST", testInboxURI, bytes.NewBuffer(MustSerialize(testRejectFollow)))) - gotCallback := 0 - var gotCallbackObject *streams.Reject - fedCb.reject = func(c context.Context, s *streams.Reject) error { - gotCallback++ - gotCallbackObject = s - return nil - } - handled, err := p.PostInbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotCallback != 1 { - t.Fatalf("expected %d, got %d", 1, gotCallback) - } else if err := PubObjectEquals(gotCallbackObject.Raw(), testRejectFollow); err != nil { - t.Fatalf("unexpected callback object: %s", err) - } -} - -func TestPostInbox_Add_DoesNotAddIfTargetNotOwned(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostInboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := ActivityPubRequest(httptest.NewRequest("POST", testInboxURI, bytes.NewBuffer(MustSerialize(testAddNote)))) - gotOwns := 0 - var gotOwnsId *url.URL - app.MockFederateApp.owns = func(c context.Context, id *url.URL) bool { - gotOwns++ - gotOwnsId = id - return false - } - fedCb.add = func(c context.Context, s *streams.Add) error { - return nil - } - handled, err := p.PostInbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotOwns != 1 { - t.Fatalf("expected %d, got %d", 1, gotOwns) - } else if gotOwnsId.String() != iriString { - t.Fatalf("expected %s, got %s", iriString, gotOwnsId.String()) - } -} - -func TestPostInbox_Add_AddIfTargetOwnedAndAppCanAdd(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostInboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := ActivityPubRequest(httptest.NewRequest("POST", testInboxURI, bytes.NewBuffer(MustSerialize(testAddNote)))) - gotOwns := 0 - var gotOwnsId *url.URL - app.MockFederateApp.owns = func(c context.Context, id *url.URL) bool { - gotOwns++ - gotOwnsId = id - return true - } - gotGet := 0 - var gotGetId *url.URL - app.MockFederateApp.get = func(c context.Context, id *url.URL, rw RWType) (PubObject, error) { - if rw != ReadWrite { - t.Fatalf("expected RWType of %v, got %v", ReadWrite, rw) - } - gotGet++ - gotGetId = id - v := &vocab.Collection{} - return v, nil - } - gotCanAdd := 0 - var gotCanAddObject vocab.ObjectType - var gotCanAddTarget vocab.ObjectType - app.MockFederateApp.canAdd = func(c context.Context, o vocab.ObjectType, t vocab.ObjectType) bool { - gotCanAdd++ - gotCanAddObject = o - gotCanAddTarget = t - return true - } - gotSet := 0 - var gotSetTarget PubObject - app.MockFederateApp.set = func(c context.Context, target PubObject) error { - gotSet++ - if gotSet == 1 { - gotSetTarget = target - } - return nil - } - fedCb.add = func(c context.Context, s *streams.Add) error { - return nil - } - handled, err := p.PostInbox(context.Background(), resp, req) - expected := &vocab.Collection{} - expected.AppendItemsIRI(noteIRI) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotOwns != 1 { - t.Fatalf("expected %d, got %d", 1, gotOwns) - } else if gotOwnsId.String() != iriString { - t.Fatalf("expected %s, got %s", iriString, gotOwnsId.String()) - } else if gotGet != 1 { - t.Fatalf("expected %d, got %d", 1, gotGet) - } else if gotGetId.String() != iriString { - t.Fatalf("expected %s, got %s", iriString, gotGetId.String()) - } else if gotCanAdd != 1 { - t.Fatalf("expected %d, got %d", 1, gotCanAdd) - } else if err := VocabSerializerEquals(gotCanAddObject, testNote); err != nil { - t.Fatal(err) - } else if err := VocabSerializerEquals(gotCanAddTarget, expected); err != nil { - t.Fatal(err) - } else if gotSet != 2 { - t.Fatalf("expected %d, got %d", 2, gotSet) - } else if err := PubObjectEquals(gotSetTarget, expected); err != nil { - t.Fatal(err) - } -} - -func TestPostInbox_Add_DoesNotAddIfAppCannotAdd(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostInboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := ActivityPubRequest(httptest.NewRequest("POST", testInboxURI, bytes.NewBuffer(MustSerialize(testAddNote)))) - gotOwns := 0 - var gotOwnsId *url.URL - app.MockFederateApp.owns = func(c context.Context, id *url.URL) bool { - gotOwns++ - gotOwnsId = id - return true - } - gotGet := 0 - var gotGetId *url.URL - app.MockFederateApp.get = func(c context.Context, id *url.URL, rw RWType) (PubObject, error) { - gotGet++ - gotGetId = id - v := &vocab.Collection{} - return v, nil - } - gotCanAdd := 0 - var gotCanAddObject vocab.ObjectType - var gotCanAddTarget vocab.ObjectType - app.MockFederateApp.canAdd = func(c context.Context, o vocab.ObjectType, t vocab.ObjectType) bool { - gotCanAdd++ - gotCanAddObject = o - gotCanAddTarget = t - return false - } - fedCb.add = func(c context.Context, s *streams.Add) error { - return nil - } - handled, err := p.PostInbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotOwns != 1 { - t.Fatalf("expected %d, got %d", 1, gotOwns) - } else if gotOwnsId.String() != iriString { - t.Fatalf("expected %s, got %s", iriString, gotOwnsId.String()) - } else if gotGet != 1 { - t.Fatalf("expected %d, got %d", 1, gotGet) - } else if gotGetId.String() != iriString { - t.Fatalf("expected %s, got %s", iriString, gotGetId.String()) - } else if gotCanAdd != 1 { - t.Fatalf("expected %d, got %d", 1, gotCanAdd) - } else if err := VocabSerializerEquals(gotCanAddObject, testNote); err != nil { - t.Fatal(err) - } else if err := VocabSerializerEquals(gotCanAddTarget, &vocab.Collection{}); err != nil { - t.Fatal(err) - } -} - -func TestPostInbox_Add_CallsCallback(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostInboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := ActivityPubRequest(httptest.NewRequest("POST", testInboxURI, bytes.NewBuffer(MustSerialize(testAddNote)))) - app.MockFederateApp.owns = func(c context.Context, id *url.URL) bool { - return true - } - app.MockFederateApp.get = func(c context.Context, id *url.URL, rw RWType) (PubObject, error) { - v := &vocab.Collection{} - return v, nil - } - app.MockFederateApp.canAdd = func(c context.Context, o vocab.ObjectType, t vocab.ObjectType) bool { - return true - } - gotCallback := 0 - var gotCallbackObject *streams.Add - fedCb.add = func(c context.Context, s *streams.Add) error { - gotCallback++ - gotCallbackObject = s - return nil - } - handled, err := p.PostInbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotCallback != 1 { - t.Fatalf("expected %d, got %d", 1, gotCallback) - } else if err := PubObjectEquals(gotCallbackObject.Raw(), testAddNote); err != nil { - t.Fatalf("unexpected callback object: %s", err) - } -} - -func TestPostInbox_Remove_DoesNotRemoveIfTargetNotOwned(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostInboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := ActivityPubRequest(httptest.NewRequest("POST", testInboxURI, bytes.NewBuffer(MustSerialize(testRemoveNote)))) - gotOwns := 0 - var gotOwnsId *url.URL - app.MockFederateApp.owns = func(c context.Context, id *url.URL) bool { - gotOwns++ - gotOwnsId = id - return false - } - fedCb.remove = func(c context.Context, s *streams.Remove) error { - return nil - } - handled, err := p.PostInbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotOwns != 1 { - t.Fatalf("expected %d, got %d", 1, gotOwns) - } else if gotOwnsId.String() != iriString { - t.Fatalf("expected %s, got %s", iriString, gotOwnsId.String()) - } -} - -func TestPostInbox_Remove_RemoveIfTargetOwnedAndCanRemove(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostInboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := ActivityPubRequest(httptest.NewRequest("POST", testInboxURI, bytes.NewBuffer(MustSerialize(testRemoveNote)))) - gotOwns := 0 - var gotOwnsId *url.URL - app.MockFederateApp.owns = func(c context.Context, id *url.URL) bool { - gotOwns++ - gotOwnsId = id - return true - } - gotGet := 0 - var gotGetId *url.URL - app.MockFederateApp.get = func(c context.Context, id *url.URL, rw RWType) (PubObject, error) { - if rw != ReadWrite { - t.Fatalf("expected RWType of %v, got %v", ReadWrite, rw) - } - gotGet++ - gotGetId = id - v := &vocab.Collection{} - v.AppendItemsObject(testNote) - return v, nil - } - gotCanRemove := 0 - var gotCanRemoveObject vocab.ObjectType - var gotCanRemoveTarget vocab.ObjectType - app.MockFederateApp.canRemove = func(c context.Context, o vocab.ObjectType, t vocab.ObjectType) bool { - gotCanRemove++ - gotCanRemoveObject = o - gotCanRemoveTarget = t - return true - } - gotSet := 0 - var gotSetTarget PubObject - app.MockFederateApp.set = func(c context.Context, target PubObject) error { - gotSet++ - if gotSet == 1 { - gotSetTarget = target - } - return nil - } - fedCb.remove = func(c context.Context, s *streams.Remove) error { - return nil - } - handled, err := p.PostInbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotOwns != 1 { - t.Fatalf("expected %d, got %d", 1, gotOwns) - } else if gotOwnsId.String() != iriString { - t.Fatalf("expected %s, got %s", iriString, gotOwnsId.String()) - } else if gotGet != 1 { - t.Fatalf("expected %d, got %d", 1, gotGet) - } else if gotGetId.String() != iriString { - t.Fatalf("expected %s, got %s", iriString, gotGetId.String()) - } else if gotCanRemove != 1 { - t.Fatalf("expected %d, got %d", 1, gotCanRemove) - } else if err := VocabSerializerEquals(gotCanRemoveObject, testNote); err != nil { - t.Fatal(err) - } else if err := VocabSerializerEquals(gotCanRemoveTarget, &vocab.Collection{}); err != nil { - t.Fatal(err) - } else if gotSet != 2 { - t.Fatalf("expected %d, got %d", 2, gotSet) - } else if err := PubObjectEquals(gotSetTarget, &vocab.Collection{}); err != nil { - t.Fatal(err) - } -} - -func TestPostInbox_Remove_DoesNotRemoveIfAppCannotRemove(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostInboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := ActivityPubRequest(httptest.NewRequest("POST", testInboxURI, bytes.NewBuffer(MustSerialize(testRemoveNote)))) - gotOwns := 0 - var gotOwnsId *url.URL - app.MockFederateApp.owns = func(c context.Context, id *url.URL) bool { - gotOwns++ - gotOwnsId = id - return true - } - gotGet := 0 - var gotGetId *url.URL - app.MockFederateApp.get = func(c context.Context, id *url.URL, rw RWType) (PubObject, error) { - gotGet++ - gotGetId = id - v := &vocab.Collection{} - v.AppendItemsObject(testNote) - return v, nil - } - gotCanRemove := 0 - var gotCanRemoveObject vocab.ObjectType - var gotCanRemoveTarget vocab.ObjectType - app.MockFederateApp.canRemove = func(c context.Context, o vocab.ObjectType, t vocab.ObjectType) bool { - gotCanRemove++ - gotCanRemoveObject = o - gotCanRemoveTarget = t - return false - } - fedCb.remove = func(c context.Context, s *streams.Remove) error { - return nil - } - handled, err := p.PostInbox(context.Background(), resp, req) - expected := &vocab.Collection{} - expected.AppendItemsObject(testNote) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotOwns != 1 { - t.Fatalf("expected %d, got %d", 1, gotOwns) - } else if gotOwnsId.String() != iriString { - t.Fatalf("expected %s, got %s", iriString, gotOwnsId.String()) - } else if gotGet != 1 { - t.Fatalf("expected %d, got %d", 1, gotGet) - } else if gotGetId.String() != iriString { - t.Fatalf("expected %s, got %s", iriString, gotGetId.String()) - } else if gotCanRemove != 1 { - t.Fatalf("expected %d, got %d", 1, gotCanRemove) - } else if err := VocabSerializerEquals(gotCanRemoveObject, testNote); err != nil { - t.Fatal(err) - } else if err := VocabSerializerEquals(gotCanRemoveTarget, expected); err != nil { - t.Fatal(err) - } -} - -func TestPostInbox_Remove_CallsCallback(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostInboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := ActivityPubRequest(httptest.NewRequest("POST", testInboxURI, bytes.NewBuffer(MustSerialize(testRemoveNote)))) - app.MockFederateApp.owns = func(c context.Context, id *url.URL) bool { - return true - } - app.MockFederateApp.get = func(c context.Context, id *url.URL, rw RWType) (PubObject, error) { - v := &vocab.Collection{} - return v, nil - } - app.MockFederateApp.canRemove = func(c context.Context, o vocab.ObjectType, t vocab.ObjectType) bool { - return true - } - gotCallback := 0 - var gotCallbackObject *streams.Remove - fedCb.remove = func(c context.Context, s *streams.Remove) error { - gotCallback++ - gotCallbackObject = s - return nil - } - handled, err := p.PostInbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotCallback != 1 { - t.Fatalf("expected %d, got %d", 1, gotCallback) - } else if err := PubObjectEquals(gotCallbackObject.Raw(), testRemoveNote); err != nil { - t.Fatalf("unexpected callback object: %s", err) - } -} - -func TestPostInbox_Like_AddsToLikeCollection(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostInboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := ActivityPubRequest(httptest.NewRequest("POST", testInboxURI, bytes.NewBuffer(MustSerialize(testLikeNote)))) - gotOwns := 0 - var gotOwnsId *url.URL - app.MockFederateApp.owns = func(c context.Context, id *url.URL) bool { - gotOwns++ - gotOwnsId = id - return true - } - gotGet := 0 - var gotGetId *url.URL - app.MockFederateApp.get = func(c context.Context, id *url.URL, rw RWType) (PubObject, error) { - if rw != ReadWrite { - t.Fatalf("expected RWType of %v, got %v", ReadWrite, rw) - } - gotGet++ - gotGetId = id - v := &vocab.Note{} - v.SetId(noteIRI) - v.AppendNameString(noteName) - v.AppendContentString("This is a simple note") - v.SetLikesCollection(&vocab.Collection{}) - return v, nil - } - gotSet := 0 - var gotSetObject PubObject - app.MockFederateApp.set = func(c context.Context, target PubObject) error { - gotSet++ - if gotSet == 1 { - gotSetObject = target - } - return nil - } - fedCb.like = func(c context.Context, s *streams.Like) error { - return nil - } - handled, err := p.PostInbox(context.Background(), resp, req) - expected := &vocab.Collection{} - expected.AppendItemsIRI(noteActivityIRI) - expectedNote := &vocab.Note{} - expectedNote.SetId(noteIRI) - expectedNote.AppendNameString(noteName) - expectedNote.AppendContentString("This is a simple note") - expectedNote.SetLikesCollection(expected) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotOwns != 1 { - t.Fatalf("expected %d, got %d", 1, gotOwns) - } else if gotOwnsId.String() != noteURIString { - t.Fatalf("expected %s, got %s", noteURIString, gotOwnsId.String()) - } else if gotGet != 1 { - t.Fatalf("expected %d, got %d", 1, gotGet) - } else if gotGetId.String() != noteURIString { - t.Fatalf("expected %s, got %s", noteURIString, gotGetId.String()) - } else if gotSet != 2 { - t.Fatalf("expected %d, got %d", 2, gotSet) - } else if err := PubObjectEquals(gotSetObject, expectedNote); err != nil { - t.Fatalf("unexpected callback object: %s", err) - } -} - -func TestPostInbox_Like_AddsToDefaultOrderedCollection(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostInboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := ActivityPubRequest(httptest.NewRequest("POST", testInboxURI, bytes.NewBuffer(MustSerialize(testLikeNote)))) - gotOwns := 0 - var gotOwnsId *url.URL - app.MockFederateApp.owns = func(c context.Context, id *url.URL) bool { - gotOwns++ - gotOwnsId = id - return true - } - gotGet := 0 - var gotGetId *url.URL - app.MockFederateApp.get = func(c context.Context, id *url.URL, rw RWType) (PubObject, error) { - if rw != ReadWrite { - t.Fatalf("expected RWType of %v, got %v", ReadWrite, rw) - } - gotGet++ - gotGetId = id - v := &vocab.Note{} - v.SetId(noteIRI) - v.AppendNameString(noteName) - v.AppendContentString("This is a simple note") - return v, nil - } - gotSet := 0 - var gotSetObject PubObject - app.MockFederateApp.set = func(c context.Context, target PubObject) error { - gotSet++ - if gotSet == 1 { - gotSetObject = target - } - return nil - } - fedCb.like = func(c context.Context, s *streams.Like) error { - return nil - } - handled, err := p.PostInbox(context.Background(), resp, req) - expected := &vocab.OrderedCollection{} - expected.AppendOrderedItemsIRI(noteActivityIRI) - expectedNote := &vocab.Note{} - expectedNote.SetId(noteIRI) - expectedNote.AppendNameString(noteName) - expectedNote.AppendContentString("This is a simple note") - expectedNote.SetLikesOrderedCollection(expected) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotOwns != 1 { - t.Fatalf("expected %d, got %d", 1, gotOwns) - } else if gotOwnsId.String() != noteURIString { - t.Fatalf("expected %s, got %s", noteURIString, gotOwnsId.String()) - } else if gotGet != 1 { - t.Fatalf("expected %d, got %d", 1, gotGet) - } else if gotGetId.String() != noteURIString { - t.Fatalf("expected %s, got %s", noteURIString, gotGetId.String()) - } else if gotSet != 2 { - t.Fatalf("expected %d, got %d", 2, gotSet) - } else if err := PubObjectEquals(gotSetObject, expectedNote); err != nil { - t.Fatalf("unexpected callback object: %s", err) - } -} - -func TestPostInbox_Like_DoesNotAddLikeToCollectionIfAlreadyPresent(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostInboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := ActivityPubRequest(httptest.NewRequest("POST", testInboxURI, bytes.NewBuffer(MustSerialize(testLikeNote)))) - app.MockFederateApp.owns = func(c context.Context, id *url.URL) bool { - return true - } - app.MockFederateApp.get = func(c context.Context, id *url.URL, rw RWType) (PubObject, error) { - likes := &vocab.Collection{} - likes.AppendItemsIRI(noteActivityIRI) - v := &vocab.Note{} - v.SetId(noteIRI) - v.AppendNameString(noteName) - v.AppendContentString("This is a simple note") - v.SetLikesCollection(likes) - return v, nil - } - gotSet := 0 - var gotSetObject PubObject - app.MockFederateApp.set = func(c context.Context, target PubObject) error { - gotSet++ - if gotSet == 1 { - gotSetObject = target - } - return nil - } - fedCb.like = func(c context.Context, s *streams.Like) error { - return nil - } - handled, err := p.PostInbox(context.Background(), resp, req) - expected := &vocab.OrderedCollection{} - expected.AppendOrderedItemsIRI(noteActivityIRI) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotSet != 1 { - t.Fatalf("expected %d, got %d", 1, gotSet) - } else if err := PubObjectEquals(gotSetObject, expected); err != nil { - t.Fatalf("unexpected callback object: %s", err) - } -} - -func TestPostInbox_Like_AddsToLikeOrderedCollection(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostInboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := ActivityPubRequest(httptest.NewRequest("POST", testInboxURI, bytes.NewBuffer(MustSerialize(testLikeNote)))) - app.MockFederateApp.owns = func(c context.Context, id *url.URL) bool { - return true - } - app.MockFederateApp.get = func(c context.Context, id *url.URL, rw RWType) (PubObject, error) { - v := &vocab.Note{} - v.SetId(noteIRI) - v.AppendNameString(noteName) - v.AppendContentString("This is a simple note") - v.SetLikesOrderedCollection(&vocab.OrderedCollection{}) - return v, nil - } - gotSet := 0 - var gotSetObject PubObject - app.MockFederateApp.set = func(c context.Context, target PubObject) error { - gotSet++ - if gotSet == 1 { - gotSetObject = target - } - return nil - } - fedCb.like = func(c context.Context, s *streams.Like) error { - return nil - } - handled, err := p.PostInbox(context.Background(), resp, req) - expected := &vocab.OrderedCollection{} - expected.AppendOrderedItemsIRI(noteActivityIRI) - expectedNote := &vocab.Note{} - expectedNote.SetId(noteIRI) - expectedNote.AppendNameString(noteName) - expectedNote.AppendContentString("This is a simple note") - expectedNote.SetLikesOrderedCollection(expected) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if err := PubObjectEquals(gotSetObject, expectedNote); err != nil { - t.Fatalf("unexpected callback object: %s", err) - } -} - -func TestPostInbox_Like_AddsToLikeIRI(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostInboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := ActivityPubRequest(httptest.NewRequest("POST", testInboxURI, bytes.NewBuffer(MustSerialize(testLikeNote)))) - app.MockFederateApp.owns = func(c context.Context, id *url.URL) bool { - return true - } - app.MockFederateApp.get = func(c context.Context, id *url.URL, rw RWType) (PubObject, error) { - if *id == *noteIRI { - v := &vocab.Note{} - v.SetId(noteIRI) - v.AppendNameString(noteName) - v.AppendContentString("This is a simple note") - v.SetLikesAnyURI(testNewIRI) - return v, nil - } else if *id == *testNewIRI { - return &vocab.OrderedCollection{}, nil - } - t.Fatalf("unexpected get(%s)", id) - return nil, nil - } - gotSet := 0 - var gotSetObject PubObject - app.MockFederateApp.set = func(c context.Context, target PubObject) error { - gotSet++ - if gotSet == 1 { - gotSetObject = target - } - return nil - } - fedCb.like = func(c context.Context, s *streams.Like) error { - return nil - } - handled, err := p.PostInbox(context.Background(), resp, req) - expected := &vocab.OrderedCollection{} - expected.AppendOrderedItemsIRI(noteActivityIRI) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if err := PubObjectEquals(gotSetObject, expected); err != nil { - t.Fatalf("unexpected callback object: %s", err) - } -} - -func TestPostInbox_Like_CallsCallback(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostInboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := ActivityPubRequest(httptest.NewRequest("POST", testInboxURI, bytes.NewBuffer(MustSerialize(testLikeNote)))) - app.MockFederateApp.owns = func(c context.Context, id *url.URL) bool { - return true - } - app.MockFederateApp.get = func(c context.Context, id *url.URL, rw RWType) (PubObject, error) { - v := &vocab.Note{} - v.SetId(noteIRI) - v.AppendNameString(noteName) - v.AppendContentString("This is a simple note") - v.SetLikesCollection(&vocab.Collection{}) - return v, nil - } - gotCallback := 0 - var gotCallbackObject *streams.Like - fedCb.like = func(c context.Context, s *streams.Like) error { - gotCallback++ - gotCallbackObject = s - return nil - } - handled, err := p.PostInbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotCallback != 1 { - t.Fatalf("expected %d, got %d", 1, gotCallback) - } else if err := PubObjectEquals(gotCallbackObject.Raw(), testLikeNote); err != nil { - t.Fatalf("unexpected callback object: %s", err) - } -} - -func TestPostInbox_Undo_CallsCallback(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostInboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := ActivityPubRequest(httptest.NewRequest("POST", testInboxURI, bytes.NewBuffer(MustSerialize(testUndoLike)))) - gotCallback := 0 - var gotCallbackObject *streams.Undo - fedCb.undo = func(c context.Context, s *streams.Undo) error { - gotCallback++ - gotCallbackObject = s - return nil - } - handled, err := p.PostInbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotCallback != 1 { - t.Fatalf("expected %d, got %d", 1, gotCallback) - } else if err := PubObjectEquals(gotCallbackObject.Raw(), testUndoLike); err != nil { - t.Fatalf("unexpected callback object: %s", err) - } -} - -func TestGetInbox_RejectNonActivityPub(t *testing.T) { - app, _, _, _, _, _, _, p := NewPubberTest(t) - resp := httptest.NewRecorder() - req := httptest.NewRequest("GET", testInboxURI, nil) - app.MockFederateApp.getInbox = func(c context.Context, r *http.Request, rw RWType) (vocab.OrderedCollectionType, error) { - return &vocab.OrderedCollection{}, nil - } - handled, err := p.GetInbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if handled { - t.Fatalf("expected !handled, got handled") - } -} - -func TestGetInbox_SetsContentTypeHeader(t *testing.T) { - app, _, _, _, _, _, _, p := NewPubberTest(t) - resp := httptest.NewRecorder() - req := ActivityPubRequest(httptest.NewRequest("GET", testInboxURI, nil)) - app.MockFederateApp.getInbox = func(c context.Context, r *http.Request, rw RWType) (vocab.OrderedCollectionType, error) { - return &vocab.OrderedCollection{}, nil - } - handled, err := p.GetInbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if l := len(resp.HeaderMap["Content-Type"]); l != 1 { - t.Fatalf("expected %d, got %d", 1, l) - } else if h := resp.HeaderMap["Content-Type"][0]; h != responseContentTypeHeader { - t.Fatalf("expected %s, got %s", responseContentTypeHeader, h) - } -} - -func TestGetInbox_DeduplicateInboxItems(t *testing.T) { - app, _, _, _, _, _, _, p := NewPubberTest(t) - resp := httptest.NewRecorder() - req := ActivityPubRequest(httptest.NewRequest("GET", testInboxURI, nil)) - app.MockFederateApp.getInbox = func(c context.Context, r *http.Request, rw RWType) (vocab.OrderedCollectionType, error) { - v := &vocab.OrderedCollection{} - v.AppendOrderedItemsObject(testCreateNote) - v.AppendOrderedItemsObject(testCreateNote) - v.AppendOrderedItemsObject(testUpdateNote) - return v, nil - } - handled, err := p.GetInbox(context.Background(), resp, req) - expected := &vocab.OrderedCollection{} - expected.AppendOrderedItemsObject(testCreateNote) - expected.AppendOrderedItemsObject(testUpdateNote) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if err := VocabEquals(resp.Body, expected); err != nil { - t.Fatalf("unexpected callback object: %s", err) - } -} - -func TestPostOutbox_RejectNonActivityPub(t *testing.T) { - _, _, _, _, _, _, _, p := NewPubberTest(t) - resp := httptest.NewRecorder() - req := httptest.NewRequest("POST", testOutboxURI, bytes.NewBuffer(MustSerialize(testCreateNote))) - handled, err := p.PostOutbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if handled { - t.Fatalf("expected !handled, got handled") - } -} - -func TestPostOutbox_RejectUnauthorized_NotSigned(t *testing.T) { - _, socialApp, _, _, _, _, _, p := NewPubberTest(t) - resp := httptest.NewRecorder() - req := ActivityPubRequest(httptest.NewRequest("POST", testOutboxURI, bytes.NewBuffer(MustSerialize(testCreateNote)))) - socialApp.getSocialAPIVerifier = func(c context.Context) SocialAPIVerifier { - return nil - } - handled, err := p.PostOutbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if resp.Code != http.StatusBadRequest { - t.Fatalf("expected %d, got %d", http.StatusBadRequest, resp.Code) - } -} - -func TestPostOutbox_RejectUnauthenticatedUnauthorized(t *testing.T) { - _, socialApp, _, _, _, _, _, p := NewPubberTest(t) - resp := httptest.NewRecorder() - req := ActivityPubRequest(httptest.NewRequest("POST", testOutboxURI, bytes.NewBuffer(MustSerialize(testCreateNote)))) - gotVerifyForOutbox := 0 - socialApp.getSocialAPIVerifier = func(c context.Context) SocialAPIVerifier { - mockV := &MockSocialAPIVerifier{ - verifyForOutbox: func(r *http.Request, outbox *url.URL) (bool, bool, error) { - gotVerifyForOutbox++ - return false, false, nil - }, - } - return mockV - } - handled, err := p.PostOutbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotVerifyForOutbox != 1 { - t.Fatalf("expected %d, got %d", 1, gotVerifyForOutbox) - } else if resp.Code != http.StatusBadRequest { - t.Fatalf("expected %d, got %d", http.StatusBadRequest, resp.Code) - } -} - -func TestPostOutbox_RejectAuthenticatedUnauthorized(t *testing.T) { - _, socialApp, _, _, _, _, _, p := NewPubberTest(t) - resp := httptest.NewRecorder() - req := ActivityPubRequest(httptest.NewRequest("POST", testOutboxURI, bytes.NewBuffer(MustSerialize(testCreateNote)))) - gotVerifyForOutbox := 0 - socialApp.getSocialAPIVerifier = func(c context.Context) SocialAPIVerifier { - mockV := &MockSocialAPIVerifier{ - verifyForOutbox: func(r *http.Request, outbox *url.URL) (bool, bool, error) { - gotVerifyForOutbox++ - return true, false, nil - }, - } - return mockV - } - handled, err := p.PostOutbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotVerifyForOutbox != 1 { - t.Fatalf("expected %d, got %d", 1, gotVerifyForOutbox) - } else if resp.Code != http.StatusForbidden { - t.Fatalf("expected %d, got %d", http.StatusForbidden, resp.Code) - } -} - -func TestPostOutbox_RejectFallback_Unauthorized_NotSigned(t *testing.T) { - _, socialApp, _, _, _, _, _, p := NewPubberTest(t) - resp := httptest.NewRecorder() - req := ActivityPubRequest(httptest.NewRequest("POST", testOutboxURI, bytes.NewBuffer(MustSerialize(testCreateNote)))) - gotVerifyForOutbox := 0 - socialApp.getSocialAPIVerifier = func(c context.Context) SocialAPIVerifier { - mockV := &MockSocialAPIVerifier{ - verifyForOutbox: func(r *http.Request, outbox *url.URL) (bool, bool, error) { - gotVerifyForOutbox++ - return false, true, nil - }, - } - return mockV - } - handled, err := p.PostOutbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotVerifyForOutbox != 1 { - t.Fatalf("expected %d, got %d", 1, gotVerifyForOutbox) - } else if resp.Code != http.StatusBadRequest { - t.Fatalf("expected %d, got %d", http.StatusBadRequest, resp.Code) - } -} - -func TestPostOutbox_RejectFallback_Unauthorized_WrongSignature(t *testing.T) { - _, socialApp, _, _, _, _, _, p := NewPubberTest(t) - resp := httptest.NewRecorder() - req := BadSignature(ActivityPubRequest(httptest.NewRequest("POST", testOutboxURI, bytes.NewBuffer(MustSerialize(testCreateNote))))) - gotVerifyForOutbox := 0 - socialApp.getSocialAPIVerifier = func(c context.Context) SocialAPIVerifier { - mockV := &MockSocialAPIVerifier{ - verifyForOutbox: func(r *http.Request, outbox *url.URL) (bool, bool, error) { - gotVerifyForOutbox++ - return false, true, nil - }, - } - return mockV - } - gotPublicKey := 0 - var gotPublicKeyId string - var gotBoxIRI *url.URL - socialApp.getPublicKeyForOutbox = func(c context.Context, publicKeyId string, boxIRI *url.URL) (crypto.PublicKey, httpsig.Algorithm, error) { - gotPublicKey++ - gotPublicKeyId = publicKeyId - gotBoxIRI = boxIRI - return testPrivateKey.Public(), httpsig.RSA_SHA256, nil - } - handled, err := p.PostOutbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotVerifyForOutbox != 1 { - t.Fatalf("expected %d, got %d", 1, gotVerifyForOutbox) - } else if gotPublicKey != 1 { - t.Fatalf("expected %d, got %d", 1, gotPublicKey) - } else if gotPublicKeyId != testPublicKeyId { - t.Fatalf("expected %s, got %s", testPublicKeyId, gotPublicKeyId) - } else if s := gotBoxIRI.String(); s != testOutboxURI { - t.Fatalf("expected %s, got %s", testOutboxURI, s) - } else if resp.Code != http.StatusForbidden { - t.Fatalf("expected %d, got %d", http.StatusForbidden, resp.Code) - } -} - -func TestPostOutbox_RejectUnauthorized_WrongSignature(t *testing.T) { - _, socialApp, _, _, _, _, _, p := NewPubberTest(t) - resp := httptest.NewRecorder() - req := BadSignature(ActivityPubRequest(httptest.NewRequest("POST", testOutboxURI, bytes.NewBuffer(MustSerialize(testCreateNote))))) - gotSocialAPIVerifier := 0 - socialApp.getSocialAPIVerifier = func(c context.Context) SocialAPIVerifier { - gotSocialAPIVerifier++ - return nil - } - gotPublicKey := 0 - var gotPublicKeyId string - var gotBoxIRI *url.URL - socialApp.getPublicKeyForOutbox = func(c context.Context, publicKeyId string, boxIRI *url.URL) (crypto.PublicKey, httpsig.Algorithm, error) { - gotPublicKey++ - gotPublicKeyId = publicKeyId - gotBoxIRI = boxIRI - return testPrivateKey.Public(), httpsig.RSA_SHA256, nil - } - handled, err := p.PostOutbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotSocialAPIVerifier != 1 { - t.Fatalf("expected %d, got %d", 1, gotSocialAPIVerifier) - } else if gotPublicKey != 1 { - t.Fatalf("expected %d, got %d", 1, gotPublicKey) - } else if gotPublicKeyId != testPublicKeyId { - t.Fatalf("expected %s, got %s", testPublicKeyId, gotPublicKeyId) - } else if s := gotBoxIRI.String(); s != testOutboxURI { - t.Fatalf("expected %s, got %s", testOutboxURI, s) - } else if resp.Code != http.StatusForbidden { - t.Fatalf("expected %d, got %d", http.StatusForbidden, resp.Code) - } -} - -func TestPostOutbox_WrapInCreateActivity(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostOutboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - // Raw Note - rawNote := &vocab.Note{} - rawNote.SetId(noteIRI) - rawNote.AppendNameString(noteName) - rawNote.AppendContentString("This is a simple note") - rawNote.AppendToObject(samActor) - // Expected result - expectedNote := &vocab.Note{} - expectedNote.SetId(testNewIRI2) - expectedNote.AppendNameString(noteName) - expectedNote.AppendContentString("This is a simple note") - expectedNote.AppendToObject(samActor) - expectedNote.AppendAttributedToIRI(sallyIRI) - expectedCreate := &vocab.Create{} - expectedCreate.SetId(testNewIRI) - expectedCreate.AppendActorIRI(sallyIRI) - expectedCreate.AppendObject(expectedNote) - expectedCreate.AppendToIRI(samIRI) - resp := httptest.NewRecorder() - req := Sign(ActivityPubRequest(httptest.NewRequest("POST", testOutboxURI, bytes.NewBuffer(MustSerialize(rawNote))))) - gotActorIRI := 0 - socialApp.actorIRI = func(c context.Context, r *http.Request) (*url.URL, error) { - gotActorIRI++ - return sallyIRI, nil - } - gotCallback := 0 - var gotCallbackObject *streams.Create - socialCb.create = func(c context.Context, s *streams.Create) error { - gotCallback++ - gotCallbackObject = s - return nil - } - handled, err := p.PostOutbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotActorIRI != 1 { - t.Fatalf("expected %d, got %d", 1, gotActorIRI) - } else if gotCallback != 1 { - t.Fatalf("expected %d, got %d", 1, gotCallback) - } else if err := PubObjectEquals(gotCallbackObject.Raw(), expectedCreate); err != nil { - t.Fatalf("unexpected callback object: %s", err) - } -} - -func TestPostOutbox_RequiresObject(t *testing.T) { - tests := []struct { - name string - input func() vocab.Serializer - }{ - { - name: "create", - input: func() vocab.Serializer { - v := &vocab.Create{} - v.SetId(noteActivityIRI) - v.AppendSummaryString("Sally created a note") - v.AppendActorObject(sallyActor) - v.AppendToObject(samActor) - return v - }, - }, - { - name: "update", - input: func() vocab.Serializer { - v := &vocab.Update{} - v.SetId(noteActivityIRI) - v.AppendSummaryString("Sally updated a note") - v.AppendActorObject(sallyActor) - v.AppendToObject(samActor) - return v - }, - }, - { - name: "delete", - input: func() vocab.Serializer { - v := &vocab.Delete{} - v.SetId(noteActivityIRI) - v.AppendActorObject(sallyActor) - v.AppendToObject(samActor) - return v - }, - }, - { - name: "follow", - input: func() vocab.Serializer { - v := &vocab.Follow{} - v.SetId(noteActivityIRI) - v.AppendActorObject(sallyActor) - v.AppendToObject(samActor) - return v - }, - }, - { - name: "add", - input: func() vocab.Serializer { - v := &vocab.Add{} - v.SetId(noteActivityIRI) - v.AppendActorObject(sallyActor) - v.AppendToObject(samActor) - v.AppendTargetObject(testNote) - return v - }, - }, - { - name: "remove", - input: func() vocab.Serializer { - v := &vocab.Remove{} - v.SetId(noteActivityIRI) - v.AppendActorObject(sallyActor) - v.AppendToObject(samActor) - v.AppendTargetObject(testNote) - return v - }, - }, - { - name: "like", - input: func() vocab.Serializer { - v := &vocab.Like{} - v.SetId(noteActivityIRI) - v.AppendActorObject(sallyActor) - v.AppendToObject(samActor) - return v - }, - }, - { - name: "block", - input: func() vocab.Serializer { - v := &vocab.Block{} - v.SetId(noteActivityIRI) - v.AppendActorObject(sallyActor) - v.AppendToObject(samActor) - return v - }, - }, - { - name: "undo", - input: func() vocab.Serializer { - v := &vocab.Undo{} - v.SetId(noteActivityIRI) - v.AppendActorObject(sallyActor) - v.AppendToObject(samActor) - return v - }, - }, - } - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostOutboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - for _, test := range tests { - t.Logf("Running table test case %q", test.name) - resp := httptest.NewRecorder() - req := Sign(ActivityPubRequest(httptest.NewRequest("POST", testOutboxURI, bytes.NewBuffer(MustSerialize(test.input()))))) - handled, err := p.PostOutbox(context.Background(), resp, req) - if resp.Code != http.StatusBadRequest { - t.Fatalf("(%s) expected %d, got %d", test.name, http.StatusBadRequest, resp.Code) - } else if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("(%s) expected handled, got !handled", test.name) - } - } -} - -func TestPostOutbox_RequiresTarget(t *testing.T) { - tests := []struct { - name string - input func() vocab.Serializer - }{ - { - name: "add", - input: func() vocab.Serializer { - v := &vocab.Add{} - v.SetId(noteActivityIRI) - v.AppendActorObject(sallyActor) - v.AppendToObject(samActor) - v.AppendObject(testNote) - return v - }, - }, - { - name: "remove", - input: func() vocab.Serializer { - v := &vocab.Remove{} - v.SetId(noteActivityIRI) - v.AppendActorObject(sallyActor) - v.AppendToObject(samActor) - v.AppendObject(testNote) - return v - }, - }, - } - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostOutboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - for _, test := range tests { - t.Logf("Running table test case %q", test.name) - resp := httptest.NewRecorder() - req := Sign(ActivityPubRequest(httptest.NewRequest("POST", testOutboxURI, bytes.NewBuffer(MustSerialize(test.input()))))) - handled, err := p.PostOutbox(context.Background(), resp, req) - if resp.Code != http.StatusBadRequest { - t.Fatalf("(%s) expected %d, got %d", test.name, http.StatusBadRequest, resp.Code) - } else if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("(%s) expected handled, got !handled", test.name) - } - } -} - -func TestPostOutbox_Create_CopyToAttributedTo(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostOutboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := Sign(ActivityPubRequest(httptest.NewRequest("POST", testOutboxURI, bytes.NewBuffer(MustSerialize(testCreateNote))))) - gotCallback := 0 - var gotCallbackObject *streams.Create - socialCb.create = func(c context.Context, s *streams.Create) error { - gotCallback++ - gotCallbackObject = s - return nil - } - handled, err := p.PostOutbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotCallback != 1 { - t.Fatalf("expected %d, got %d", 1, gotCallback) - } else if e := PubObjectEquals(gotCallbackObject.Raw(), testClientExpectedCreateNote); e != nil { - t.Fatal(e) - } -} - -func TestPostOutbox_Create_SetCreatedObject(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostOutboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := Sign(ActivityPubRequest(httptest.NewRequest("POST", testOutboxURI, bytes.NewBuffer(MustSerialize(testCreateNote))))) - socialCb.create = func(c context.Context, s *streams.Create) error { - return nil - } - gotSet := 0 - var gotSetOutbox PubObject - var gotSetActivity PubObject - var gotSetCreate PubObject - app.MockFederateApp.set = func(c context.Context, o PubObject) error { - gotSet++ - if gotSet == 1 { - gotSetCreate = o - } else if gotSet == 2 { - gotSetActivity = o - } else if gotSet == 3 { - gotSetOutbox = o - } - return nil - } - handled, err := p.PostOutbox(context.Background(), resp, req) - expectedOutbox := &vocab.OrderedCollection{} - expectedOutbox.AppendType("OrderedCollection") - expectedOutbox.AppendOrderedItemsIRI(testClientExpectedCreateNote.GetId()) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotSet != 3 { - t.Fatalf("expected %d, got %d", 3, gotSet) - } else if err := PubObjectEquals(gotSetCreate, testClientExpectedNote); err != nil { - t.Fatalf("unexpected callback object: %s", err) - } else if err := PubObjectEquals(gotSetActivity, testClientExpectedCreateNote); err != nil { - t.Fatalf("unexpected callback object: %s", err) - } else if err := PubObjectEquals(gotSetOutbox, expectedOutbox); err != nil { - t.Fatalf("unexpected callback object: %s", err) - } -} - -func TestPostOutbox_Create_CallsCallback(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostOutboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := Sign(ActivityPubRequest(httptest.NewRequest("POST", testOutboxURI, bytes.NewBuffer(MustSerialize(testCreateNote))))) - gotCallback := 0 - var gotCallbackObject *streams.Create - socialCb.create = func(c context.Context, s *streams.Create) error { - gotCallback++ - gotCallbackObject = s - return nil - } - handled, err := p.PostOutbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotCallback != 1 { - t.Fatalf("expected %d, got %d", 1, gotCallback) - } else if err := PubObjectEquals(gotCallbackObject.Raw(), testClientExpectedCreateNote); err != nil { - t.Fatalf("unexpected callback object: %s", err) - } -} - -func TestPostOutbox_Create_IsDelivered(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostOutboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := Sign(ActivityPubRequest(httptest.NewRequest("POST", testOutboxURI, bytes.NewBuffer(MustSerialize(testCreateNote))))) - socialCb.create = func(c context.Context, s *streams.Create) error { - return nil - } - gotHttpDo := 0 - var httpDeliveryRequest *http.Request - httpClient.do = func(req *http.Request) (*http.Response, error) { - gotHttpDo++ - if gotHttpDo == 1 { - actorResp := &http.Response{ - StatusCode: http.StatusOK, - Body: ioutil.NopCloser(bytes.NewBuffer(samActorJSON)), - } - return actorResp, nil - } else if gotHttpDo == 2 { - actorResp := &http.Response{ - StatusCode: http.StatusOK, - Body: ioutil.NopCloser(bytes.NewBuffer(sallyActorJSON)), - } - return actorResp, nil - } else if gotHttpDo == 3 { - httpDeliveryRequest = req - okResp := &http.Response{ - StatusCode: http.StatusOK, - Body: ioutil.NopCloser(bytes.NewBuffer([]byte{})), - } - return okResp, nil - } - return nil, nil - } - handled, err := p.PostOutbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotHttpDo != 3 { - t.Fatalf("expected %d, got %d", 3, gotHttpDo) - } else if httpDeliveryRequest.Method != "POST" { - t.Fatalf("expected %s, got %s", "POST", httpDeliveryRequest.Method) - } else if s := httpDeliveryRequest.URL.String(); s != samIRIInboxString { - t.Fatalf("expected %s, got %s", samIRIInboxString, s) - } -} - -func TestPostOutbox_Update_DeleteSubFields(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostOutboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := Sign(ActivityPubRequest(httptest.NewRequest("POST", testOutboxURI, bytes.NewBuffer([]byte(testDeleteSubFields))))) - socialCb.update = func(c context.Context, s *streams.Update) error { - return nil - } - gotGet := 0 - app.MockFederateApp.get = func(c context.Context, id *url.URL, rw RWType) (PubObject, error) { - gotGet++ - if *id != *noteIRI { - t.Fatalf("expected %s, got %s", noteIRI, id) - } - samActor := &vocab.Person{} - samActor.SetInboxAnyURI(samIRIInbox) - samActor.SetId(samIRI) - samActor.AppendNameString("Sam") - v := &vocab.Note{} - v.SetId(noteIRI) - v.AppendNameString(noteName) - v.AppendContentString("This is a simple note") - v.AppendToObject(samActor) - return v, nil - } - gotSet := 0 - var gotSetObject PubObject - app.MockFederateApp.set = func(c context.Context, p PubObject) error { - gotSet++ - if gotSet == 1 { - gotSetObject = p - } - return nil - } - handled, err := p.PostOutbox(context.Background(), resp, req) - expectedSamActor := &vocab.Person{} - expectedSamActor.SetInboxAnyURI(samIRIInbox) - expectedSamActor.SetId(samIRI) - expectedUpdatedNote := &vocab.Note{} - expectedUpdatedNote.SetId(noteIRI) - expectedUpdatedNote.AppendNameString(noteName) - expectedUpdatedNote.AppendContentString("This is a simple note") - expectedUpdatedNote.AppendToObject(expectedSamActor) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotGet != 1 { - t.Fatalf("expected %d, got %d", 1, gotGet) - } else if gotSet != 3 { - t.Fatalf("expected %d, got %d", 3, gotSet) - } else if err := PubObjectEquals(gotSetObject, expectedUpdatedNote); err != nil { - t.Fatalf("unexpected set object: %s", err) - } -} - -func TestPostOutbox_Update_DeleteFields(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostOutboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := Sign(ActivityPubRequest(httptest.NewRequest("POST", testOutboxURI, bytes.NewBuffer([]byte(testDeleteFields))))) - socialCb.update = func(c context.Context, s *streams.Update) error { - return nil - } - gotGet := 0 - app.MockFederateApp.get = func(c context.Context, id *url.URL, rw RWType) (PubObject, error) { - if rw != ReadWrite { - t.Fatalf("expected RWType of %v, got %v", ReadWrite, rw) - } - gotGet++ - if *id != *noteIRI { - t.Fatalf("expected %s, got %s", noteIRI, id) - } - samActor := &vocab.Person{} - samActor.SetInboxAnyURI(samIRIInbox) - samActor.SetId(samIRI) - samActor.AppendNameString("Sam") - v := &vocab.Note{} - v.SetId(noteIRI) - v.AppendNameString(noteName) - v.AppendContentString("This is a simple note") - v.AppendToObject(samActor) - return v, nil - } - gotSet := 0 - var gotSetObject PubObject - app.MockFederateApp.set = func(c context.Context, p PubObject) error { - gotSet++ - if gotSet == 1 { - gotSetObject = p - } - return nil - } - handled, err := p.PostOutbox(context.Background(), resp, req) - expectedUpdatedNote := &vocab.Note{} - expectedUpdatedNote.SetId(noteIRI) - expectedUpdatedNote.AppendNameString(noteName) - expectedUpdatedNote.AppendContentString("This is a simple note") - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotGet != 1 { - t.Fatalf("expected %d, got %d", 1, gotGet) - } else if gotSet != 3 { - t.Fatalf("expected %d, got %d", 3, gotSet) - } else if err := PubObjectEquals(gotSetObject, expectedUpdatedNote); err != nil { - t.Fatalf("unexpected set object: %s", err) - } -} - -func TestPostOutbox_Update_DeleteSubFieldsMultipleObjects(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostOutboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := Sign(ActivityPubRequest(httptest.NewRequest("POST", testOutboxURI, bytes.NewBuffer([]byte(testDeleteFieldsDifferentObjects))))) - socialCb.update = func(c context.Context, s *streams.Update) error { - return nil - } - gotGet := 0 - app.MockFederateApp.get = func(c context.Context, id *url.URL, rw RWType) (PubObject, error) { - gotGet++ - var v *vocab.Note - if *id == *noteIRI { - samActor := &vocab.Person{} - samActor.SetInboxAnyURI(samIRIInbox) - samActor.SetId(samIRI) - samActor.AppendNameString("Sam") - v = &vocab.Note{} - v.SetId(noteIRI) - v.AppendNameString(noteName) - v.AppendContentString("This is a simple note") - v.AppendToObject(samActor) - } else if *id == *updateActivityIRI { - samActor := &vocab.Person{} - samActor.SetInboxAnyURI(samIRIInbox) - samActor.SetId(samIRI) - samActor.AppendNameString("Sam") - v = &vocab.Note{} - v.SetId(updateActivityIRI) - v.AppendNameString(noteName) - v.AppendContentString("This is a simple note") - v.AppendToObject(samActor) - } else { - t.Fatalf("unexpected app.MockFederateApp.Get id: %s", id) - } - return v, nil - } - gotSet := 0 - var gotSetObject PubObject - var gotSetObject2 PubObject - app.MockFederateApp.set = func(c context.Context, p PubObject) error { - gotSet++ - if gotSet == 1 { - gotSetObject = p - } else if gotSet == 2 { - gotSetObject2 = p - } - return nil - } - handled, err := p.PostOutbox(context.Background(), resp, req) - expectedSamActor := &vocab.Person{} - expectedSamActor.SetInboxAnyURI(samIRIInbox) - expectedSamActor.SetId(samIRI) - expectedUpdatedNote := &vocab.Note{} - expectedUpdatedNote.SetId(noteIRI) - expectedUpdatedNote.AppendNameString(noteName) - expectedUpdatedNote.AppendContentString("This is a simple note") - expectedUpdatedNote.AppendToObject(expectedSamActor) - expectedUpdatedNote2 := &vocab.Note{} - expectedUpdatedNote2.SetId(updateActivityIRI) - expectedUpdatedNote2.AppendNameString(noteName) - expectedUpdatedNote2.AppendContentString("This is a simple note") - expectedUpdatedNote2.AppendToObject(expectedSamActor) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotGet != 2 { - t.Fatalf("expected %d, got %d", 2, gotGet) - } else if gotSet != 4 { - t.Fatalf("expected %d, got %d", 4, gotSet) - } else if err := PubObjectEquals(gotSetObject, expectedUpdatedNote); err != nil { - t.Fatalf("unexpected set object: %s", err) - } else if err := PubObjectEquals(gotSetObject2, expectedUpdatedNote2); err != nil { - t.Fatalf("unexpected set object: %s", err) - } -} - -func TestPostOutbox_Update_OverwriteUpdatedFields(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostOutboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := Sign(ActivityPubRequest(httptest.NewRequest("POST", testOutboxURI, bytes.NewBuffer(MustSerialize(testClientUpdateNote))))) - socialCb.update = func(c context.Context, s *streams.Update) error { - return nil - } - gotGet := 0 - app.MockFederateApp.get = func(c context.Context, id *url.URL, rw RWType) (PubObject, error) { - gotGet++ - if *id != *noteIRI { - t.Fatalf("expected %s, got %s", noteIRI, id) - } - samActor := &vocab.Person{} - samActor.SetInboxAnyURI(samIRIInbox) - samActor.SetId(samIRI) - samActor.AppendNameString("Sam") - v := &vocab.Note{} - v.SetId(noteIRI) - v.AppendNameString(noteName) - v.AppendContentString("This is a simple note") - v.AppendToObject(samActor) - return v, nil - } - gotSet := 0 - var gotSetObject PubObject - app.MockFederateApp.set = func(c context.Context, p PubObject) error { - gotSet++ - if gotSet == 1 { - gotSetObject = p - } - return nil - } - handled, err := p.PostOutbox(context.Background(), resp, req) - samActor := &vocab.Person{} - samActor.SetInboxAnyURI(samIRIInbox) - samActor.SetId(samIRI) - samActor.AppendNameString("Samm") - expectedUpdatedNote := &vocab.Note{} - expectedUpdatedNote.SetId(noteIRI) - expectedUpdatedNote.AppendNameString(noteName) - expectedUpdatedNote.AppendContentString("This is a simple note") - expectedUpdatedNote.AppendToObject(samActor) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotGet != 1 { - t.Fatalf("expected %d, got %d", 1, gotGet) - } else if gotSet != 3 { - t.Fatalf("expected %d, got %d", 3, gotSet) - } else if err := PubObjectEquals(gotSetObject, expectedUpdatedNote); err != nil { - t.Fatalf("unexpected set object: %s", err) - } -} - -func TestPostOutbox_Update_CallsCallback(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostOutboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := Sign(ActivityPubRequest(httptest.NewRequest("POST", testOutboxURI, bytes.NewBuffer(MustSerialize(testUpdateNote))))) - gotCallback := 0 - var gotCallbackObject *streams.Update - socialCb.update = func(c context.Context, s *streams.Update) error { - gotCallback++ - gotCallbackObject = s - return nil - } - app.MockFederateApp.get = func(c context.Context, id *url.URL, rw RWType) (PubObject, error) { - samActor := &vocab.Person{} - samActor.SetInboxAnyURI(samIRIInbox) - samActor.SetId(samIRI) - samActor.AppendNameString("Sam") - v := &vocab.Note{} - v.SetId(noteIRI) - v.AppendNameString(noteName) - v.AppendContentString("This is a simple note") - v.AppendToObject(samActor) - return v, nil - } - app.MockFederateApp.set = func(c context.Context, p PubObject) error { - return nil - } - handled, err := p.PostOutbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotCallback != 1 { - t.Fatalf("expected %d, got %d", 1, gotCallback) - } else if err := PubObjectEquals(gotCallbackObject.Raw(), testClientExpectedUpdateNote); err != nil { - t.Fatalf("unexpected callback object: %s", err) - } -} - -func TestPostOutbox_Update_IsDelivered(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostOutboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := Sign(ActivityPubRequest(httptest.NewRequest("POST", testOutboxURI, bytes.NewBuffer(MustSerialize(testUpdateNote))))) - socialCb.update = func(c context.Context, s *streams.Update) error { - return nil - } - gotHttpDo := 0 - var httpDeliveryRequest *http.Request - httpClient.do = func(req *http.Request) (*http.Response, error) { - gotHttpDo++ - if gotHttpDo == 1 { - actorResp := &http.Response{ - StatusCode: http.StatusOK, - Body: ioutil.NopCloser(bytes.NewBuffer(samActorJSON)), - } - return actorResp, nil - } else if gotHttpDo == 2 { - actorResp := &http.Response{ - StatusCode: http.StatusOK, - Body: ioutil.NopCloser(bytes.NewBuffer(sallyActorJSON)), - } - return actorResp, nil - } else if gotHttpDo == 3 { - httpDeliveryRequest = req - okResp := &http.Response{ - StatusCode: http.StatusOK, - Body: ioutil.NopCloser(bytes.NewBuffer([]byte{})), - } - return okResp, nil - } - return nil, nil - } - app.MockFederateApp.get = func(c context.Context, id *url.URL, rw RWType) (PubObject, error) { - samActor := &vocab.Person{} - samActor.SetInboxAnyURI(samIRIInbox) - samActor.SetId(samIRI) - samActor.AppendNameString("Sam") - v := &vocab.Note{} - v.SetId(noteIRI) - v.AppendNameString(noteName) - v.AppendContentString("This is a simple note") - v.AppendToObject(samActor) - return v, nil - } - app.MockFederateApp.set = func(c context.Context, p PubObject) error { - return nil - } - handled, err := p.PostOutbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotHttpDo != 3 { - t.Fatalf("expected %d, got %d", 3, gotHttpDo) - } else if httpDeliveryRequest.Method != "POST" { - t.Fatalf("expected %s, got %s", "POST", httpDeliveryRequest.Method) - } else if s := httpDeliveryRequest.URL.String(); s != samIRIInboxString { - t.Fatalf("expected %s, got %s", samIRIInboxString, s) - } -} - -func TestPostOutbox_Delete_SetsTombstone(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostOutboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := Sign(ActivityPubRequest(httptest.NewRequest("POST", testOutboxURI, bytes.NewBuffer(MustSerialize(testDeleteNote))))) - socialCb.delete = func(c context.Context, s *streams.Delete) error { - return nil - } - gotGet := 0 - app.MockFederateApp.get = func(c context.Context, id *url.URL, rw RWType) (PubObject, error) { - if rw != ReadWrite { - t.Fatalf("expected RWType of %v, got %v", ReadWrite, rw) - } - gotGet++ - if *id != *noteIRI { - t.Fatalf("expected %s, got %s", noteIRI, id) - } - v := &vocab.Note{} - v.AppendType("Note") - v.SetId(noteIRI) - v.SetPublished(testPublishedTime) - v.SetUpdated(testUpdateTime) - return v, nil - } - gotSet := 0 - var gotSetObject PubObject - app.MockFederateApp.set = func(c context.Context, p PubObject) error { - gotSet++ - if gotSet == 1 { - gotSetObject = p - } - return nil - } - handled, err := p.PostOutbox(context.Background(), resp, req) - expectedTombstone := &vocab.Tombstone{} - expectedTombstone.SetId(noteIRI) - expectedTombstone.SetPublished(testPublishedTime) - expectedTombstone.SetUpdated(testUpdateTime) - expectedTombstone.SetDeleted(now) - expectedTombstone.AppendFormerTypeString("Note") - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotGet != 1 { - t.Fatalf("expected %d, got %d", 1, gotGet) - } else if gotSet != 3 { - t.Fatalf("expected %d, got %d", 3, gotSet) - } else if err := PubObjectEquals(gotSetObject, expectedTombstone); err != nil { - t.Fatalf("unexpected set object: %s", err) - } -} - -func TestPostOutbox_Delete_CallsCallback(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostOutboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := Sign(ActivityPubRequest(httptest.NewRequest("POST", testOutboxURI, bytes.NewBuffer(MustSerialize(testDeleteNote))))) - gotCallback := 0 - var gotCallbackObject *streams.Delete - socialCb.delete = func(c context.Context, s *streams.Delete) error { - gotCallback++ - gotCallbackObject = s - return nil - } - app.MockFederateApp.get = func(c context.Context, id *url.URL, rw RWType) (PubObject, error) { - return testNote, nil - } - app.MockFederateApp.set = func(c context.Context, p PubObject) error { - return nil - } - handled, err := p.PostOutbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotCallback != 1 { - t.Fatalf("expected %d, got %d", 1, gotCallback) - } else if err := PubObjectEquals(gotCallbackObject.Raw(), testClientExpectedDeleteNote); err != nil { - t.Fatalf("unexpected callback object: %s", err) - } -} - -func TestPostOutbox_Delete_IsDelivered(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostOutboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := Sign(ActivityPubRequest(httptest.NewRequest("POST", testOutboxURI, bytes.NewBuffer(MustSerialize(testDeleteNote))))) - socialCb.delete = func(c context.Context, s *streams.Delete) error { - return nil - } - gotHttpDo := 0 - var httpDeliveryRequest *http.Request - httpClient.do = func(req *http.Request) (*http.Response, error) { - gotHttpDo++ - if gotHttpDo == 1 { - actorResp := &http.Response{ - StatusCode: http.StatusOK, - Body: ioutil.NopCloser(bytes.NewBuffer(samActorJSON)), - } - return actorResp, nil - } else if gotHttpDo == 2 { - actorResp := &http.Response{ - StatusCode: http.StatusOK, - Body: ioutil.NopCloser(bytes.NewBuffer(sallyActorJSON)), - } - return actorResp, nil - } else if gotHttpDo == 3 { - httpDeliveryRequest = req - okResp := &http.Response{ - StatusCode: http.StatusOK, - Body: ioutil.NopCloser(bytes.NewBuffer([]byte{})), - } - return okResp, nil - } - return nil, nil - } - app.MockFederateApp.get = func(c context.Context, id *url.URL, rw RWType) (PubObject, error) { - return testNote, nil - } - app.MockFederateApp.set = func(c context.Context, p PubObject) error { - return nil - } - handled, err := p.PostOutbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotHttpDo != 3 { - t.Fatalf("expected %d, got %d", 3, gotHttpDo) - } else if httpDeliveryRequest.Method != "POST" { - t.Fatalf("expected %s, got %s", "POST", httpDeliveryRequest.Method) - } else if s := httpDeliveryRequest.URL.String(); s != samIRIInboxString { - t.Fatalf("expected %s, got %s", samIRIInboxString, s) - } -} - -func TestPostOutbox_Follow_CallsCallback(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostOutboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := Sign(ActivityPubRequest(httptest.NewRequest("POST", testOutboxURI, bytes.NewBuffer(MustSerialize(testFollow))))) - gotCallback := 0 - var gotCallbackObject *streams.Follow - socialCb.follow = func(c context.Context, s *streams.Follow) error { - gotCallback++ - gotCallbackObject = s - return nil - } - handled, err := p.PostOutbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotCallback != 1 { - t.Fatalf("expected %d, got %d", 1, gotCallback) - } else if err := PubObjectEquals(gotCallbackObject.Raw(), testClientExpectedFollow); err != nil { - t.Fatalf("unexpected callback object: %s", err) - } -} - -func TestPostOutbox_Follow_IsDelivered(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostOutboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := Sign(ActivityPubRequest(httptest.NewRequest("POST", testOutboxURI, bytes.NewBuffer(MustSerialize(testFollow))))) - socialCb.follow = func(c context.Context, s *streams.Follow) error { - return nil - } - gotHttpDo := 0 - var httpDeliveryRequest *http.Request - httpClient.do = func(req *http.Request) (*http.Response, error) { - gotHttpDo++ - if gotHttpDo == 1 { - actorResp := &http.Response{ - StatusCode: http.StatusOK, - Body: ioutil.NopCloser(bytes.NewBuffer(samActorJSON)), - } - return actorResp, nil - } else if gotHttpDo == 2 { - actorResp := &http.Response{ - StatusCode: http.StatusOK, - Body: ioutil.NopCloser(bytes.NewBuffer(sallyActorJSON)), - } - return actorResp, nil - } else if gotHttpDo == 3 { - httpDeliveryRequest = req - okResp := &http.Response{ - StatusCode: http.StatusOK, - Body: ioutil.NopCloser(bytes.NewBuffer([]byte{})), - } - return okResp, nil - } - return nil, nil - } - handled, err := p.PostOutbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotHttpDo != 3 { - t.Fatalf("expected %d, got %d", 3, gotHttpDo) - } else if httpDeliveryRequest.Method != "POST" { - t.Fatalf("expected %s, got %s", "POST", httpDeliveryRequest.Method) - } else if s := httpDeliveryRequest.URL.String(); s != samIRIInboxString { - t.Fatalf("expected %s, got %s", samIRIInboxString, s) - } -} - -func TestPostOutbox_Accept_CallsCallback(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostOutboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := Sign(ActivityPubRequest(httptest.NewRequest("POST", testOutboxURI, bytes.NewBuffer(MustSerialize(testAcceptFollow))))) - gotCallback := 0 - var gotCallbackObject *streams.Accept - socialCb.accept = func(c context.Context, s *streams.Accept) error { - gotCallback++ - gotCallbackObject = s - return nil - } - handled, err := p.PostOutbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotCallback != 1 { - t.Fatalf("expected %d, got %d", 1, gotCallback) - } else if err := PubObjectEquals(gotCallbackObject.Raw(), testClientExpectedAcceptFollow); err != nil { - t.Fatalf("unexpected callback object: %s", err) - } -} - -func TestPostOutbox_Accept_IsDelivered(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostOutboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := Sign(ActivityPubRequest(httptest.NewRequest("POST", testOutboxURI, bytes.NewBuffer(MustSerialize(testAcceptFollow))))) - socialCb.accept = func(c context.Context, s *streams.Accept) error { - return nil - } - gotHttpDo := 0 - var httpDeliveryRequest *http.Request - httpClient.do = func(req *http.Request) (*http.Response, error) { - gotHttpDo++ - if gotHttpDo == 1 { - actorResp := &http.Response{ - StatusCode: http.StatusOK, - Body: ioutil.NopCloser(bytes.NewBuffer(samActorJSON)), - } - return actorResp, nil - } else if gotHttpDo == 2 { - actorResp := &http.Response{ - StatusCode: http.StatusOK, - Body: ioutil.NopCloser(bytes.NewBuffer(sallyActorJSON)), - } - return actorResp, nil - } else if gotHttpDo == 3 { - httpDeliveryRequest = req - okResp := &http.Response{ - StatusCode: http.StatusOK, - Body: ioutil.NopCloser(bytes.NewBuffer([]byte{})), - } - return okResp, nil - } - return nil, nil - } - handled, err := p.PostOutbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotHttpDo != 3 { - t.Fatalf("expected %d, got %d", 3, gotHttpDo) - } else if httpDeliveryRequest.Method != "POST" { - t.Fatalf("expected %s, got %s", "POST", httpDeliveryRequest.Method) - } else if s := httpDeliveryRequest.URL.String(); s != samIRIInboxString { - t.Fatalf("expected %s, got %s", samIRIInboxString, s) - } -} - -func TestPostOutbox_Reject_CallsCallback(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostOutboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := Sign(ActivityPubRequest(httptest.NewRequest("POST", testOutboxURI, bytes.NewBuffer(MustSerialize(testRejectFollow))))) - gotCallback := 0 - var gotCallbackObject *streams.Reject - socialCb.reject = func(c context.Context, s *streams.Reject) error { - gotCallback++ - gotCallbackObject = s - return nil - } - handled, err := p.PostOutbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotCallback != 1 { - t.Fatalf("expected %d, got %d", 1, gotCallback) - } else if err := PubObjectEquals(gotCallbackObject.Raw(), testClientExpectedRejectFollow); err != nil { - t.Fatalf("unexpected callback object: %s", err) - } -} - -func TestPostOutbox_Reject_IsDelivered(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostOutboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := Sign(ActivityPubRequest(httptest.NewRequest("POST", testOutboxURI, bytes.NewBuffer(MustSerialize(testRejectFollow))))) - socialCb.reject = func(c context.Context, s *streams.Reject) error { - return nil - } - gotHttpDo := 0 - var httpDeliveryRequest *http.Request - httpClient.do = func(req *http.Request) (*http.Response, error) { - gotHttpDo++ - if gotHttpDo == 1 { - actorResp := &http.Response{ - StatusCode: http.StatusOK, - Body: ioutil.NopCloser(bytes.NewBuffer(samActorJSON)), - } - return actorResp, nil - } else if gotHttpDo == 2 { - actorResp := &http.Response{ - StatusCode: http.StatusOK, - Body: ioutil.NopCloser(bytes.NewBuffer(sallyActorJSON)), - } - return actorResp, nil - } else if gotHttpDo == 3 { - httpDeliveryRequest = req - okResp := &http.Response{ - StatusCode: http.StatusOK, - Body: ioutil.NopCloser(bytes.NewBuffer([]byte{})), - } - return okResp, nil - } - return nil, nil - } - handled, err := p.PostOutbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotHttpDo != 3 { - t.Fatalf("expected %d, got %d", 3, gotHttpDo) - } else if httpDeliveryRequest.Method != "POST" { - t.Fatalf("expected %s, got %s", "POST", httpDeliveryRequest.Method) - } else if s := httpDeliveryRequest.URL.String(); s != samIRIInboxString { - t.Fatalf("expected %s, got %s", samIRIInboxString, s) - } -} - -func TestPostOutbox_Add_DoesNotAddIfTargetNotOwned(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostOutboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := Sign(ActivityPubRequest(httptest.NewRequest("POST", testOutboxURI, bytes.NewBuffer(MustSerialize(testAddNote))))) - gotOwns := 0 - var gotOwnsIri *url.URL - app.MockFederateApp.owns = func(c context.Context, iri *url.URL) bool { - gotOwns++ - gotOwnsIri = iri - return false - } - socialCb.add = func(c context.Context, s *streams.Add) error { - return nil - } - handled, err := p.PostOutbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotOwns != 1 { - t.Fatalf("expected %d, got %d", 1, gotOwns) - } else if ownsIri := gotOwnsIri.String(); ownsIri != iriString { - t.Fatalf("expected %s, got %s", iriString, ownsIri) - } -} - -func TestPostOutbox_Add_AddsIfTargetOwnedAndAppCanAdd(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostOutboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := Sign(ActivityPubRequest(httptest.NewRequest("POST", testOutboxURI, bytes.NewBuffer(MustSerialize(testAddNote))))) - app.MockFederateApp.owns = func(c context.Context, iri *url.URL) bool { - return true - } - gotGet := 0 - var gotGetIri *url.URL - app.MockFederateApp.get = func(c context.Context, iri *url.URL, rw RWType) (PubObject, error) { - if rw != ReadWrite { - t.Fatalf("expected RWType of %v, got %v", ReadWrite, rw) - } - gotGet++ - gotGetIri = iri - col := &vocab.Collection{} - col.AppendType("Collection") - return col, nil - } - gotCanAdd := 0 - var canAddObj vocab.ObjectType - var canAddTarget vocab.ObjectType - app.MockFederateApp.canAdd = func(c context.Context, obj vocab.ObjectType, t vocab.ObjectType) bool { - gotCanAdd++ - canAddObj = obj - canAddTarget = t - return true - } - gotSet := 0 - var gotSetObj PubObject - app.MockFederateApp.set = func(c context.Context, t PubObject) error { - gotSet++ - if gotSet == 1 { - gotSetObj = t - } - return nil - } - socialCb.add = func(c context.Context, s *streams.Add) error { - return nil - } - handled, err := p.PostOutbox(context.Background(), resp, req) - expectedTarget := &vocab.Collection{} - expectedTarget.AppendType("Collection") - expectedTarget.AppendItemsIRI(noteIRI) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotGet != 1 { - t.Fatalf("expected %d, got %d", 1, gotGet) - } else if getIri := gotGetIri.String(); getIri != iriString { - t.Fatalf("expected %s, got %s", iriString, getIri) - } else if gotCanAdd != 1 { - t.Fatalf("expected %d, got %d", 1, gotCanAdd) - } else if err := VocabSerializerEquals(canAddTarget, expectedTarget); err != nil { - t.Fatal(err) - } else if err := VocabSerializerEquals(canAddObj, testNote); err != nil { - t.Fatal(err) - } else if gotSet != 3 { - t.Fatalf("expected %d, got %d", 3, gotSet) - } else if err := PubObjectEquals(gotSetObj, expectedTarget); err != nil { - t.Fatalf("unexpected set object: %s", err) - } -} - -func TestPostOutbox_Add_DoesNotAddIfAppCannotAdd(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostOutboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := Sign(ActivityPubRequest(httptest.NewRequest("POST", testOutboxURI, bytes.NewBuffer(MustSerialize(testAddNote))))) - app.MockFederateApp.owns = func(c context.Context, iri *url.URL) bool { - return true - } - gotGet := 0 - var gotGetIri *url.URL - app.MockFederateApp.get = func(c context.Context, iri *url.URL, rw RWType) (PubObject, error) { - gotGet++ - gotGetIri = iri - col := &vocab.Collection{} - col.AppendType("Collection") - return col, nil - } - gotCanAdd := 0 - var canAddObj vocab.ObjectType - var canAddTarget vocab.ObjectType - app.MockFederateApp.canAdd = func(c context.Context, obj vocab.ObjectType, t vocab.ObjectType) bool { - gotCanAdd++ - canAddObj = obj - canAddTarget = t - return false - } - socialCb.add = func(c context.Context, s *streams.Add) error { - return nil - } - handled, err := p.PostOutbox(context.Background(), resp, req) - expectedTarget := &vocab.Collection{} - expectedTarget.AppendType("Collection") - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotGet != 1 { - t.Fatalf("expected %d, got %d", 1, gotGet) - } else if getIri := gotGetIri.String(); getIri != iriString { - t.Fatalf("expected %s, got %s", iriString, getIri) - } else if gotCanAdd != 1 { - t.Fatalf("expected %d, got %d", 1, gotCanAdd) - } else if err := VocabSerializerEquals(canAddTarget, expectedTarget); err != nil { - t.Fatal(err) - } else if err := VocabSerializerEquals(canAddObj, testNote); err != nil { - t.Fatal(err) - } -} - -func TestPostOutbox_Add_CallsCallback(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostOutboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := Sign(ActivityPubRequest(httptest.NewRequest("POST", testOutboxURI, bytes.NewBuffer(MustSerialize(testAddNote))))) - app.MockFederateApp.owns = func(c context.Context, iri *url.URL) bool { - return false - } - gotCallback := 0 - var gotCallbackObject *streams.Add - socialCb.add = func(c context.Context, s *streams.Add) error { - gotCallback++ - gotCallbackObject = s - return nil - } - handled, err := p.PostOutbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotCallback != 1 { - t.Fatalf("expected %d, got %d", 1, gotCallback) - } else if err := PubObjectEquals(gotCallbackObject.Raw(), testClientExpectedAdd); err != nil { - t.Fatalf("unexpected callback object: %s", err) - } -} - -func TestPostOutbox_Add_IsDelivered(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostOutboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := Sign(ActivityPubRequest(httptest.NewRequest("POST", testOutboxURI, bytes.NewBuffer(MustSerialize(testAddNote))))) - app.MockFederateApp.owns = func(c context.Context, iri *url.URL) bool { - return false - } - socialCb.add = func(c context.Context, s *streams.Add) error { - return nil - } - gotHttpDo := 0 - var httpDeliveryRequest *http.Request - httpClient.do = func(req *http.Request) (*http.Response, error) { - gotHttpDo++ - if gotHttpDo == 1 { - actorResp := &http.Response{ - StatusCode: http.StatusOK, - Body: ioutil.NopCloser(bytes.NewBuffer(samActorJSON)), - } - return actorResp, nil - } else if gotHttpDo == 2 { - actorResp := &http.Response{ - StatusCode: http.StatusOK, - Body: ioutil.NopCloser(bytes.NewBuffer(sallyActorJSON)), - } - return actorResp, nil - } else if gotHttpDo == 3 { - httpDeliveryRequest = req - okResp := &http.Response{ - StatusCode: http.StatusOK, - Body: ioutil.NopCloser(bytes.NewBuffer([]byte{})), - } - return okResp, nil - } - return nil, nil - } - handled, err := p.PostOutbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotHttpDo != 3 { - t.Fatalf("expected %d, got %d", 3, gotHttpDo) - } else if httpDeliveryRequest.Method != "POST" { - t.Fatalf("expected %s, got %s", "POST", httpDeliveryRequest.Method) - } else if s := httpDeliveryRequest.URL.String(); s != samIRIInboxString { - t.Fatalf("expected %s, got %s", samIRIInboxString, s) - } -} - -func TestPostOutbox_Remove_DoesNotRemoveIfTargetNotOwned(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostOutboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := Sign(ActivityPubRequest(httptest.NewRequest("POST", testOutboxURI, bytes.NewBuffer(MustSerialize(testRemoveNote))))) - gotOwns := 0 - var gotOwnsIri *url.URL - app.MockFederateApp.owns = func(c context.Context, iri *url.URL) bool { - gotOwns++ - gotOwnsIri = iri - return false - } - socialCb.remove = func(c context.Context, s *streams.Remove) error { - return nil - } - handled, err := p.PostOutbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotOwns != 1 { - t.Fatalf("expected %d, got %d", 1, gotOwns) - } else if ownsIri := gotOwnsIri.String(); ownsIri != iriString { - t.Fatalf("expected %s, got %s", iriString, ownsIri) - } -} - -func TestPostOutbox_Remove_RemoveIfTargetOwnedAndCanRemove(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostOutboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := Sign(ActivityPubRequest(httptest.NewRequest("POST", testOutboxURI, bytes.NewBuffer(MustSerialize(testRemoveNote))))) - app.MockFederateApp.owns = func(c context.Context, iri *url.URL) bool { - return true - } - gotGet := 0 - var gotGetIri *url.URL - app.MockFederateApp.get = func(c context.Context, iri *url.URL, rw RWType) (PubObject, error) { - gotGet++ - gotGetIri = iri - col := &vocab.Collection{} - col.AppendType("Collection") - col.AppendItemsObject(testNote) - return col, nil - } - gotCanRemove := 0 - var canRemoveObj vocab.ObjectType - var canRemoveTarget vocab.ObjectType - app.MockFederateApp.canRemove = func(c context.Context, obj vocab.ObjectType, t vocab.ObjectType) bool { - gotCanRemove++ - canRemoveObj = obj - canRemoveTarget = t - return true - } - gotSet := 0 - var gotSetObj PubObject - app.MockFederateApp.set = func(c context.Context, t PubObject) error { - gotSet++ - if gotSet == 1 { - gotSetObj = t - } - return nil - } - socialCb.remove = func(c context.Context, s *streams.Remove) error { - return nil - } - handled, err := p.PostOutbox(context.Background(), resp, req) - expectedTarget := &vocab.Collection{} - expectedTarget.AppendType("Collection") - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotGet != 1 { - t.Fatalf("expected %d, got %d", 1, gotGet) - } else if getIri := gotGetIri.String(); getIri != iriString { - t.Fatalf("expected %s, got %s", iriString, getIri) - } else if gotCanRemove != 1 { - t.Fatalf("expected %d, got %d", 1, gotCanRemove) - } else if err := VocabSerializerEquals(canRemoveTarget, expectedTarget); err != nil { - t.Fatal(err) - } else if err := VocabSerializerEquals(canRemoveObj, testNote); err != nil { - t.Fatal(err) - } else if gotSet != 3 { - t.Fatalf("expected %d, got %d", 3, gotSet) - } else if err := PubObjectEquals(gotSetObj, expectedTarget); err != nil { - t.Fatalf("unexpected set object: %s", err) - } -} - -func TestPostOutbox_Remove_DoesNotRemoveIfAppCannotRemove(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostOutboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := Sign(ActivityPubRequest(httptest.NewRequest("POST", testOutboxURI, bytes.NewBuffer(MustSerialize(testRemoveNote))))) - app.MockFederateApp.owns = func(c context.Context, iri *url.URL) bool { - return true - } - gotGet := 0 - var gotGetIri *url.URL - app.MockFederateApp.get = func(c context.Context, iri *url.URL, rw RWType) (PubObject, error) { - gotGet++ - gotGetIri = iri - col := &vocab.Collection{} - col.AppendType("Collection") - col.AppendItemsObject(testNote) - return col, nil - } - gotCanRemove := 0 - var canRemoveObj vocab.ObjectType - var canRemoveTarget vocab.ObjectType - app.MockFederateApp.canRemove = func(c context.Context, obj vocab.ObjectType, t vocab.ObjectType) bool { - gotCanRemove++ - canRemoveObj = obj - canRemoveTarget = t - return false - } - socialCb.remove = func(c context.Context, s *streams.Remove) error { - return nil - } - handled, err := p.PostOutbox(context.Background(), resp, req) - expectedTarget := &vocab.Collection{} - expectedTarget.AppendType("Collection") - expectedTarget.AppendItemsObject(testNote) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotGet != 1 { - t.Fatalf("expected %d, got %d", 1, gotGet) - } else if getIri := gotGetIri.String(); getIri != iriString { - t.Fatalf("expected %s, got %s", iriString, getIri) - } else if gotCanRemove != 1 { - t.Fatalf("expected %d, got %d", 1, gotCanRemove) - } else if err := VocabSerializerEquals(canRemoveTarget, expectedTarget); err != nil { - t.Fatal(err) - } else if err := VocabSerializerEquals(canRemoveObj, testNote); err != nil { - t.Fatal(err) - } -} - -func TestPostOutbox_Remove_CallsCallback(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostOutboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := Sign(ActivityPubRequest(httptest.NewRequest("POST", testOutboxURI, bytes.NewBuffer(MustSerialize(testRemoveNote))))) - app.MockFederateApp.owns = func(c context.Context, iri *url.URL) bool { - return false - } - gotCallback := 0 - var gotCallbackObject *streams.Remove - socialCb.remove = func(c context.Context, s *streams.Remove) error { - gotCallback++ - gotCallbackObject = s - return nil - } - handled, err := p.PostOutbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotCallback != 1 { - t.Fatalf("expected %d, got %d", 1, gotCallback) - } else if err := PubObjectEquals(gotCallbackObject.Raw(), testClientExpectedRemove); err != nil { - t.Fatalf("unexpected callback object: %s", err) - } -} - -func TestPostOutbox_Remove_IsDelivered(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostOutboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := Sign(ActivityPubRequest(httptest.NewRequest("POST", testOutboxURI, bytes.NewBuffer(MustSerialize(testRemoveNote))))) - app.MockFederateApp.owns = func(c context.Context, iri *url.URL) bool { - return false - } - socialCb.remove = func(c context.Context, s *streams.Remove) error { - return nil - } - gotHttpDo := 0 - var httpDeliveryRequest *http.Request - httpClient.do = func(req *http.Request) (*http.Response, error) { - gotHttpDo++ - if gotHttpDo == 1 { - actorResp := &http.Response{ - StatusCode: http.StatusOK, - Body: ioutil.NopCloser(bytes.NewBuffer(samActorJSON)), - } - return actorResp, nil - } else if gotHttpDo == 2 { - actorResp := &http.Response{ - StatusCode: http.StatusOK, - Body: ioutil.NopCloser(bytes.NewBuffer(sallyActorJSON)), - } - return actorResp, nil - } else if gotHttpDo == 3 { - httpDeliveryRequest = req - okResp := &http.Response{ - StatusCode: http.StatusOK, - Body: ioutil.NopCloser(bytes.NewBuffer([]byte{})), - } - return okResp, nil - } - return nil, nil - } - handled, err := p.PostOutbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotHttpDo != 3 { - t.Fatalf("expected %d, got %d", 3, gotHttpDo) - } else if httpDeliveryRequest.Method != "POST" { - t.Fatalf("expected %s, got %s", "POST", httpDeliveryRequest.Method) - } else if s := httpDeliveryRequest.URL.String(); s != samIRIInboxString { - t.Fatalf("expected %s, got %s", samIRIInboxString, s) - } -} - -func TestPostOutbox_Like_AddsToLikedCollection(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostOutboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := Sign(ActivityPubRequest(httptest.NewRequest("POST", testOutboxURI, bytes.NewBuffer(MustSerialize(testLikeNote))))) - gotOwns := 0 - var gotOwnsIri *url.URL - app.MockFederateApp.owns = func(c context.Context, iri *url.URL) bool { - gotOwns++ - gotOwnsIri = iri - return true - } - gotGet := 0 - var gotGetIri *url.URL - app.MockFederateApp.get = func(c context.Context, iri *url.URL, rw RWType) (PubObject, error) { - if rw != ReadWrite { - t.Fatalf("expected RWType of %v, got %v", ReadWrite, rw) - } - gotGet++ - gotGetIri = iri - v := &vocab.Person{} - v.AppendNameString("Sally") - v.SetId(sallyIRI) - v.SetLikedCollection(&vocab.Collection{}) - return v, nil - } - gotSet := 0 - var gotSetObj PubObject - app.MockFederateApp.set = func(c context.Context, o PubObject) error { - gotSet++ - if gotSet == 1 { - gotSetObj = o - } - return nil - } - socialCb.like = func(c context.Context, s *streams.Like) error { - return nil - } - handled, err := p.PostOutbox(context.Background(), resp, req) - expectedLikes := &vocab.Collection{} - expectedLikes.AppendItemsIRI(noteIRI) - expectedActor := &vocab.Person{} - expectedActor.AppendNameString("Sally") - expectedActor.SetId(sallyIRI) - expectedActor.SetLikedCollection(expectedLikes) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotOwns != 1 { - t.Fatalf("expected %d, got %d", 1, gotOwns) - } else if gotOwnsString := gotOwnsIri.String(); gotOwnsString != sallyIRIString { - t.Fatalf("expected %s, got %s", noteURIString, sallyIRIString) - } else if gotGet != 1 { - t.Fatalf("expected %d, got %d", 1, gotGet) - } else if gotGetString := gotGetIri.String(); gotGetString != sallyIRIString { - t.Fatalf("expected %s, got %s", noteURIString, sallyIRIString) - } else if gotSet != 3 { - t.Fatalf("expected %d, got %d", 3, gotSet) - } else if err := PubObjectEquals(gotSetObj, expectedActor); err != nil { - t.Fatalf("set obj: %s", err) - } -} - -func TestPostOutbox_Like_AddsToDefaultOrderedCollection(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostOutboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := Sign(ActivityPubRequest(httptest.NewRequest("POST", testOutboxURI, bytes.NewBuffer(MustSerialize(testLikeNote))))) - gotOwns := 0 - var gotOwnsIri *url.URL - app.MockFederateApp.owns = func(c context.Context, iri *url.URL) bool { - gotOwns++ - gotOwnsIri = iri - return true - } - gotGet := 0 - var gotGetIri *url.URL - app.MockFederateApp.get = func(c context.Context, iri *url.URL, rw RWType) (PubObject, error) { - if rw != ReadWrite { - t.Fatalf("expected RWType of %v, got %v", ReadWrite, rw) - } - gotGet++ - gotGetIri = iri - v := &vocab.Person{} - v.AppendNameString("Sally") - v.SetId(sallyIRI) - return v, nil - } - gotSet := 0 - var gotSetObj PubObject - app.MockFederateApp.set = func(c context.Context, o PubObject) error { - gotSet++ - if gotSet == 1 { - gotSetObj = o - } - return nil - } - socialCb.like = func(c context.Context, s *streams.Like) error { - return nil - } - handled, err := p.PostOutbox(context.Background(), resp, req) - expectedLikes := &vocab.OrderedCollection{} - expectedLikes.AppendOrderedItemsIRI(noteIRI) - expectedActor := &vocab.Person{} - expectedActor.AppendNameString("Sally") - expectedActor.SetId(sallyIRI) - expectedActor.SetLikedOrderedCollection(expectedLikes) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotOwns != 1 { - t.Fatalf("expected %d, got %d", 1, gotOwns) - } else if gotOwnsString := gotOwnsIri.String(); gotOwnsString != sallyIRIString { - t.Fatalf("expected %s, got %s", noteURIString, sallyIRIString) - } else if gotGet != 1 { - t.Fatalf("expected %d, got %d", 1, gotGet) - } else if gotGetString := gotGetIri.String(); gotGetString != sallyIRIString { - t.Fatalf("expected %s, got %s", noteURIString, sallyIRIString) - } else if gotSet != 3 { - t.Fatalf("expected %d, got %d", 3, gotSet) - } else if err := PubObjectEquals(gotSetObj, expectedActor); err != nil { - t.Fatalf("set obj: %s", err) - } -} - -func TestPostOutbox_Like_DoesNotAddIfAlreadyLiked(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostOutboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := Sign(ActivityPubRequest(httptest.NewRequest("POST", testOutboxURI, bytes.NewBuffer(MustSerialize(testLikeNote))))) - app.MockFederateApp.owns = func(c context.Context, iri *url.URL) bool { - return true - } - app.MockFederateApp.get = func(c context.Context, iri *url.URL, rw RWType) (PubObject, error) { - liked := &vocab.Collection{} - liked.AppendItemsIRI(noteIRI) - v := &vocab.Person{} - v.AppendNameString("Sally") - v.SetId(sallyIRI) - v.SetLikedCollection(liked) - return v, nil - } - gotSet := 0 - var gotSetObj PubObject - app.MockFederateApp.set = func(c context.Context, o PubObject) error { - gotSet++ - if gotSet == 1 { - gotSetObj = o - } - return nil - } - socialCb.like = func(c context.Context, s *streams.Like) error { - return nil - } - handled, err := p.PostOutbox(context.Background(), resp, req) - expectedLikes := &vocab.Collection{} - expectedLikes.AppendItemsIRI(noteIRI) - expectedActor := &vocab.Person{} - expectedActor.AppendNameString("Sally") - expectedActor.SetId(sallyIRI) - expectedActor.SetLikedCollection(expectedLikes) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotSet != 3 { - t.Fatalf("expected %d, got %d", 3, gotSet) - } else if err := PubObjectEquals(gotSetObj, expectedActor); err != nil { - t.Fatalf("set obj: %s", err) - } -} - -func TestPostOutbox_Like_AddsToLikedOrderedCollection(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostOutboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := Sign(ActivityPubRequest(httptest.NewRequest("POST", testOutboxURI, bytes.NewBuffer(MustSerialize(testLikeNote))))) - app.MockFederateApp.owns = func(c context.Context, iri *url.URL) bool { - return true - } - app.MockFederateApp.get = func(c context.Context, iri *url.URL, rw RWType) (PubObject, error) { - v := &vocab.Person{} - v.AppendNameString("Sally") - v.SetId(sallyIRI) - v.SetLikedOrderedCollection(&vocab.OrderedCollection{}) - return v, nil - } - gotSet := 0 - var gotSetObj PubObject - app.MockFederateApp.set = func(c context.Context, o PubObject) error { - gotSet++ - if gotSet == 1 { - gotSetObj = o - } - return nil - } - socialCb.like = func(c context.Context, s *streams.Like) error { - return nil - } - handled, err := p.PostOutbox(context.Background(), resp, req) - expectedLikes := &vocab.OrderedCollection{} - expectedLikes.AppendOrderedItemsIRI(noteIRI) - expectedActor := &vocab.Person{} - expectedActor.AppendNameString("Sally") - expectedActor.SetId(sallyIRI) - expectedActor.SetLikedOrderedCollection(expectedLikes) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if err := PubObjectEquals(gotSetObj, expectedActor); err != nil { - t.Fatalf("set obj: %s", err) - } -} - -func TestPostOutbox_Like_DoesNotAddIfCollectionNotOwned(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostOutboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := Sign(ActivityPubRequest(httptest.NewRequest("POST", testOutboxURI, bytes.NewBuffer(MustSerialize(testLikeNote))))) - gotOwns := 0 - var gotOwnsIri *url.URL - app.MockFederateApp.owns = func(c context.Context, iri *url.URL) bool { - gotOwns++ - gotOwnsIri = iri - return false - } - socialCb.like = func(c context.Context, s *streams.Like) error { - return nil - } - handled, err := p.PostOutbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotOwns != 1 { - t.Fatalf("expected %d, got %d", 1, gotOwns) - } else if gotOwnsString := gotOwnsIri.String(); gotOwnsString != sallyIRIString { - t.Fatalf("expected %s, got %s", noteURIString, sallyIRIString) - } -} - -func TestPostOutbox_Like_CallsCallback(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostOutboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := Sign(ActivityPubRequest(httptest.NewRequest("POST", testOutboxURI, bytes.NewBuffer(MustSerialize(testLikeNote))))) - app.MockFederateApp.owns = func(c context.Context, iri *url.URL) bool { - return true - } - app.MockFederateApp.get = func(c context.Context, iri *url.URL, rw RWType) (PubObject, error) { - v := &vocab.Person{} - v.AppendNameString("Sally") - v.SetId(sallyIRI) - v.SetLikedOrderedCollection(&vocab.OrderedCollection{}) - return v, nil - } - app.MockFederateApp.set = func(c context.Context, o PubObject) error { - return nil - } - gotCallback := 0 - var gotCallbackObject *streams.Like - socialCb.like = func(c context.Context, s *streams.Like) error { - gotCallback++ - gotCallbackObject = s - return nil - } - handled, err := p.PostOutbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotCallback != 1 { - t.Fatalf("expected %d, got %d", 1, gotCallback) - } else if err := PubObjectEquals(gotCallbackObject.Raw(), testClientExpectedLike); err != nil { - t.Fatalf("unexpected callback object: %s", err) - } -} - -func TestPostOutbox_Like_IsDelivered(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostOutboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := Sign(ActivityPubRequest(httptest.NewRequest("POST", testOutboxURI, bytes.NewBuffer(MustSerialize(testLikeNote))))) - app.MockFederateApp.owns = func(c context.Context, iri *url.URL) bool { - return true - } - app.MockFederateApp.get = func(c context.Context, iri *url.URL, rw RWType) (PubObject, error) { - v := &vocab.Person{} - v.AppendNameString("Sally") - v.SetId(sallyIRI) - v.SetLikedOrderedCollection(&vocab.OrderedCollection{}) - return v, nil - } - app.MockFederateApp.set = func(c context.Context, o PubObject) error { - return nil - } - socialCb.like = func(c context.Context, s *streams.Like) error { - return nil - } - gotHttpDo := 0 - var httpDeliveryRequest *http.Request - httpClient.do = func(req *http.Request) (*http.Response, error) { - gotHttpDo++ - if gotHttpDo == 1 { - actorResp := &http.Response{ - StatusCode: http.StatusOK, - Body: ioutil.NopCloser(bytes.NewBuffer(samActorJSON)), - } - return actorResp, nil - } else if gotHttpDo == 2 { - actorResp := &http.Response{ - StatusCode: http.StatusOK, - Body: ioutil.NopCloser(bytes.NewBuffer(sallyActorJSON)), - } - return actorResp, nil - } else if gotHttpDo == 3 { - httpDeliveryRequest = req - okResp := &http.Response{ - StatusCode: http.StatusOK, - Body: ioutil.NopCloser(bytes.NewBuffer([]byte{})), - } - return okResp, nil - } - return nil, nil - } - handled, err := p.PostOutbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotHttpDo != 3 { - t.Fatalf("expected %d, got %d", 3, gotHttpDo) - } else if httpDeliveryRequest.Method != "POST" { - t.Fatalf("expected %s, got %s", "POST", httpDeliveryRequest.Method) - } else if s := httpDeliveryRequest.URL.String(); s != samIRIInboxString { - t.Fatalf("expected %s, got %s", samIRIInboxString, s) - } -} - -func TestPostOutbox_Undo_CallsCallback(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostOutboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := Sign(ActivityPubRequest(httptest.NewRequest("POST", testOutboxURI, bytes.NewBuffer(MustSerialize(testUndoLike))))) - gotCallback := 0 - var gotCallbackObject *streams.Undo - socialCb.undo = func(c context.Context, s *streams.Undo) error { - gotCallback++ - gotCallbackObject = s - return nil - } - handled, err := p.PostOutbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotCallback != 1 { - t.Fatalf("expected %d, got %d", 1, gotCallback) - } else if err := PubObjectEquals(gotCallbackObject.Raw(), testClientExpectedUndo); err != nil { - t.Fatalf("unexpected callback object: %s", err) - } -} - -func TestPostOutbox_Undo_IsDelivered(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostOutboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := Sign(ActivityPubRequest(httptest.NewRequest("POST", testOutboxURI, bytes.NewBuffer(MustSerialize(testUndoLike))))) - socialCb.undo = func(c context.Context, s *streams.Undo) error { - return nil - } - gotHttpDo := 0 - var httpDeliveryRequest *http.Request - httpClient.do = func(req *http.Request) (*http.Response, error) { - gotHttpDo++ - if gotHttpDo == 1 { - actorResp := &http.Response{ - StatusCode: http.StatusOK, - Body: ioutil.NopCloser(bytes.NewBuffer(samActorJSON)), - } - return actorResp, nil - } else if gotHttpDo == 2 { - actorResp := &http.Response{ - StatusCode: http.StatusOK, - Body: ioutil.NopCloser(bytes.NewBuffer(sallyActorJSON)), - } - return actorResp, nil - } else if gotHttpDo == 3 { - httpDeliveryRequest = req - okResp := &http.Response{ - StatusCode: http.StatusOK, - Body: ioutil.NopCloser(bytes.NewBuffer([]byte{})), - } - return okResp, nil - } - return nil, nil - } - handled, err := p.PostOutbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotHttpDo != 3 { - t.Fatalf("expected %d, got %d", 3, gotHttpDo) - } else if httpDeliveryRequest.Method != "POST" { - t.Fatalf("expected %s, got %s", "POST", httpDeliveryRequest.Method) - } else if s := httpDeliveryRequest.URL.String(); s != samIRIInboxString { - t.Fatalf("expected %s, got %s", samIRIInboxString, s) - } -} - -func TestPostOutbox_Block_CallsCallback(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostOutboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := Sign(ActivityPubRequest(httptest.NewRequest("POST", testOutboxURI, bytes.NewBuffer(MustSerialize(testBlock))))) - gotCallback := 0 - var gotCallbackObject *streams.Block - socialCb.block = func(c context.Context, s *streams.Block) error { - gotCallback++ - gotCallbackObject = s - return nil - } - handled, err := p.PostOutbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotCallback != 1 { - t.Fatalf("expected %d, got %d", 1, gotCallback) - } else if err := PubObjectEquals(gotCallbackObject.Raw(), testClientExpectedBlock); err != nil { - t.Fatalf("unexpected callback object: %s", err) - } -} - -func TestPostOutbox_Block_IsNotDelivered(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostOutboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := Sign(ActivityPubRequest(httptest.NewRequest("POST", testOutboxURI, bytes.NewBuffer(MustSerialize(testBlock))))) - socialCb.block = func(c context.Context, s *streams.Block) error { - return nil - } - httpClient.do = func(req *http.Request) (*http.Response, error) { - t.Fatalf("expected no calls to httpClient.Do") - return nil, nil - } - handled, err := p.PostOutbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } -} - -func TestPostOutbox_SetsLocationHeader(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostOutboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := Sign(ActivityPubRequest(httptest.NewRequest("POST", testOutboxURI, bytes.NewBuffer(MustSerialize(testCreateNote))))) - socialCb.create = func(c context.Context, s *streams.Create) error { - return nil - } - handled, err := p.PostOutbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if loc, ok := resp.HeaderMap["Location"]; !ok { - t.Fatalf("expected Location header, got none") - } else if len(loc) != 1 { - t.Fatalf("expected Location header to have length 1, got %d", len(loc)) - } else if loc[0] != testNewIRIString { - t.Fatalf("expected %s, got %s", testNewIRIString, loc[0]) - } -} - -func TestGetOutbox_RejectNonActivityPub(t *testing.T) { - app, _, _, _, _, _, _, p := NewPubberTest(t) - resp := httptest.NewRecorder() - req := httptest.NewRequest("GET", testOutboxURI, nil) - app.MockFederateApp.getOutbox = func(c context.Context, r *http.Request, rw RWType) (vocab.OrderedCollectionType, error) { - return &vocab.OrderedCollection{}, nil - } - handled, err := p.GetOutbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if handled { - t.Fatalf("expected !handled, got handled") - } -} - -func TestGetOutbox_SetsContentTypeHeader(t *testing.T) { - app, _, _, _, _, _, _, p := NewPubberTest(t) - resp := httptest.NewRecorder() - req := ActivityPubRequest(httptest.NewRequest("GET", testOutboxURI, nil)) - app.MockFederateApp.getOutbox = func(c context.Context, r *http.Request, rw RWType) (vocab.OrderedCollectionType, error) { - return &vocab.OrderedCollection{}, nil - } - handled, err := p.GetOutbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if l := len(resp.HeaderMap["Content-Type"]); l != 1 { - t.Fatalf("expected %d, got %d", 1, l) - } else if h := resp.HeaderMap["Content-Type"][0]; h != responseContentTypeHeader { - t.Fatalf("expected %s, got %s", responseContentTypeHeader, h) - } -} - -func TestIssue75(t *testing.T) { - // Root cause: Setting a maxDeliveryDepth to zero means no C2S messages - // will be sent to federate peers. - clock := &MockClock{now} - app := &MockApplication{t: t} - socialApp := &MockSocialApp{t: t} - fedApp := &MockFederateApp{MockApplication: app, t: t} - appl := &MockSocialFederateApp{MockSocialApp: socialApp, MockFederateApp: fedApp} - socialCb := &MockCallbacker{t: t} - fedCb := &MockCallbacker{t: t} - d := &MockDeliverer{t: t} - httpClient := &MockHttpClient{t: t} - p := NewPubber(clock, appl, socialCb, fedCb, d, httpClient, testAgent /*maxDeliveryDepth=*/, 0, 1) - - PreparePubberPostOutboxTest(t, appl, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - - // Data as described in the issue - jamesIRI, err := url.Parse("http://example.com/activity/person/james") - if err != nil { - t.Fatal(err) - } - jamesIRIOutbox, err := url.Parse("http://example.com/activity/person/james/outbox") - if err != nil { - t.Fatal(err) - } - jessIRI, err := url.Parse("http://example.com/activity/person/jess") - if err != nil { - t.Fatal(err) - } - publicIRI, err := url.Parse("https://www.w3.org/ns/activitystreams#Public") - if err != nil { - t.Fatal(err) - } - docIRI, err := url.Parse("https://www.w3.org/TR/activitypub/") - if err != nil { - t.Fatal(err) - } - payload := &vocab.Document{} - payload.AppendCcIRI(jessIRI) - payload.AppendToIRI(publicIRI) - payload.AppendNameString("ActivityPub") - payload.AppendUrlAnyURI(docIRI) - - req := Sign(ActivityPubRequest(httptest.NewRequest("POST", jamesIRIOutbox.String(), bytes.NewBuffer(MustSerialize(payload))))) - gotActorIRI := 0 - socialApp.actorIRI = func(c context.Context, r *http.Request) (*url.URL, error) { - gotActorIRI++ - return jamesIRI, nil - } - gotCallback := 0 - var gotCallbackObject *streams.Create - socialCb.create = func(c context.Context, s *streams.Create) error { - gotCallback++ - gotCallbackObject = s - return nil - } - httpClient.do = nil - - handled, err := p.PostOutbox(context.Background(), resp, req) - expectedPayload := &vocab.Document{} - expectedPayload.AppendCcIRI(jessIRI) - expectedPayload.AppendToIRI(publicIRI) - expectedPayload.AppendNameString("ActivityPub") - expectedPayload.AppendUrlAnyURI(docIRI) - expectedPayload.AppendAttributedToIRI(jamesIRI) - expectedPayload.SetId(testNewIRI2) - expectedCreate := &vocab.Create{} - expectedCreate.AppendActorIRI(jamesIRI) - expectedCreate.AppendObject(expectedPayload) - expectedCreate.AppendType("Create") - expectedCreate.SetId(testNewIRI) - expectedCreate.AppendCcIRI(jessIRI) - expectedCreate.AppendToIRI(publicIRI) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotActorIRI != 1 { - t.Fatalf("expected %d, got %d", 1, gotActorIRI) - } else if gotCallback != 1 { - t.Fatalf("expected %d, got %d", 1, gotCallback) - } else if err := PubObjectEquals(gotCallbackObject.Raw(), expectedCreate); err != nil { - t.Fatalf("unexpected callback object: %s", err) - } -} - -func TestDelivery_Bytes(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostOutboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := Sign(ActivityPubRequest(httptest.NewRequest("POST", testOutboxURI, bytes.NewBuffer(MustSerialize(testCreateNote))))) - socialCb.create = func(c context.Context, s *streams.Create) error { - return nil - } - gotHttpDo := 0 - var httpDeliveryRequest *http.Request - httpClient.do = func(req *http.Request) (*http.Response, error) { - gotHttpDo++ - if gotHttpDo == 1 { - actorResp := &http.Response{ - StatusCode: http.StatusOK, - Body: ioutil.NopCloser(bytes.NewBuffer(samActorJSON)), - } - return actorResp, nil - } else if gotHttpDo == 2 { - actorResp := &http.Response{ - StatusCode: http.StatusOK, - Body: ioutil.NopCloser(bytes.NewBuffer(sallyActorJSON)), - } - return actorResp, nil - } else if gotHttpDo == 3 { - httpDeliveryRequest = req - okResp := &http.Response{ - StatusCode: http.StatusOK, - Body: ioutil.NopCloser(bytes.NewBuffer([]byte{})), - } - return okResp, nil - } - return nil, nil - } - handled, err := p.PostOutbox(context.Background(), resp, req) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotHttpDo != 3 { - t.Fatalf("expected %d, got %d", 3, gotHttpDo) - } else if httpDeliveryRequest.Method != "POST" { - t.Fatalf("expected %s, got %s", "POST", httpDeliveryRequest.Method) - } else if deliveryBody, err := ioutil.ReadAll(httpDeliveryRequest.Body); err != nil { - t.Fatal(err) - } else if len(deliveryBody) == 0 { - t.Fatalf("empty delivery body") - } else if s := httpDeliveryRequest.URL.String(); s != samIRIInboxString { - t.Fatalf("expected %s, got %s", samIRIInboxString, s) - } -} - -var _ callbackerAnnounce = &mockCallbackerAnnounce{} - -type mockCallbackerAnnounce struct { - t *testing.T - announce func(c context.Context, s *streams.Announce) error -} - -func (m *mockCallbackerAnnounce) Announce(c context.Context, s *streams.Announce) error { - if m.announce == nil { - m.t.Logf("unimplemented mockCallbackerAnnounce called: %v %v", c, s) - return nil - } else { - return m.announce(c, s) - } -} - -var _ callbackerArrive = &mockCallbackerArrive{} - -type mockCallbackerArrive struct { - t *testing.T - arrive func(c context.Context, s *streams.Arrive) error -} - -func (m *mockCallbackerArrive) Arrive(c context.Context, s *streams.Arrive) error { - if m.arrive == nil { - m.t.Logf("unimplemented mockCallbackerArrive called: %v %v", c, s) - return nil - } else { - return m.arrive(c, s) - } -} - -var _ callbackerDislike = &mockCallbackerDislike{} - -type mockCallbackerDislike struct { - t *testing.T - dislike func(c context.Context, s *streams.Dislike) error -} - -func (m *mockCallbackerDislike) Dislike(c context.Context, s *streams.Dislike) error { - if m.dislike == nil { - m.t.Logf("unimplemented mockCallbackerDislike called: %v %v", c, s) - return nil - } else { - return m.dislike(c, s) - } -} - -var _ callbackerFlag = &mockCallbackerFlag{} - -type mockCallbackerFlag struct { - t *testing.T - flag func(c context.Context, s *streams.Flag) error -} - -func (m *mockCallbackerFlag) Flag(c context.Context, s *streams.Flag) error { - if m.flag == nil { - m.t.Logf("unimplemented mockCallbackerFlag called: %v %v", c, s) - return nil - } else { - return m.flag(c, s) - } -} - -var _ callbackerIgnore = &mockCallbackerIgnore{} - -type mockCallbackerIgnore struct { - t *testing.T - ignore func(c context.Context, s *streams.Ignore) error -} - -func (m *mockCallbackerIgnore) Ignore(c context.Context, s *streams.Ignore) error { - if m.ignore == nil { - m.t.Logf("unimplemented mockCallbackerIgnore called: %v %v", c, s) - return nil - } else { - return m.ignore(c, s) - } -} - -var _ callbackerInvite = &mockCallbackerInvite{} - -type mockCallbackerInvite struct { - t *testing.T - invite func(c context.Context, s *streams.Invite) error -} - -func (m *mockCallbackerInvite) Invite(c context.Context, s *streams.Invite) error { - if m.invite == nil { - m.t.Logf("unimplemented mockCallbackerInvite called: %v %v", c, s) - return nil - } else { - return m.invite(c, s) - } -} - -var _ callbackerJoin = &mockCallbackerJoin{} - -type mockCallbackerJoin struct { - t *testing.T - join func(c context.Context, s *streams.Join) error -} - -func (m *mockCallbackerJoin) Join(c context.Context, s *streams.Join) error { - if m.join == nil { - m.t.Logf("unimplemented mockCallbackerJoin called: %v %v", c, s) - return nil - } else { - return m.join(c, s) - } -} - -var _ callbackerLeave = &mockCallbackerLeave{} - -type mockCallbackerLeave struct { - t *testing.T - leave func(c context.Context, s *streams.Leave) error -} - -func (m *mockCallbackerLeave) Leave(c context.Context, s *streams.Leave) error { - if m.leave == nil { - m.t.Logf("unimplemented mockCallbackerLeave called: %v %v", c, s) - return nil - } else { - return m.leave(c, s) - } -} - -var _ callbackerListen = &mockCallbackerListen{} - -type mockCallbackerListen struct { - t *testing.T - listen func(c context.Context, s *streams.Listen) error -} - -func (m *mockCallbackerListen) Listen(c context.Context, s *streams.Listen) error { - if m.listen == nil { - m.t.Logf("unimplemented mockCallbackerListen called: %v %v", c, s) - return nil - } else { - return m.listen(c, s) - } -} - -var _ callbackerMove = &mockCallbackerMove{} - -type mockCallbackerMove struct { - t *testing.T - move func(c context.Context, s *streams.Move) error -} - -func (m *mockCallbackerMove) Move(c context.Context, s *streams.Move) error { - if m.move == nil { - m.t.Logf("unimplemented mockCallbackerMove called: %v %v", c, s) - return nil - } else { - return m.move(c, s) - } -} - -var _ callbackerOffer = &mockCallbackerOffer{} - -type mockCallbackerOffer struct { - t *testing.T - offer func(c context.Context, s *streams.Offer) error -} - -func (m *mockCallbackerOffer) Offer(c context.Context, s *streams.Offer) error { - if m.offer == nil { - m.t.Logf("unimplemented mockCallbackerOffer called: %v %v", c, s) - return nil - } else { - return m.offer(c, s) - } -} - -var _ callbackerQuestion = &mockCallbackerQuestion{} - -type mockCallbackerQuestion struct { - t *testing.T - question func(c context.Context, s *streams.Question) error -} - -func (m *mockCallbackerQuestion) Question(c context.Context, s *streams.Question) error { - if m.question == nil { - m.t.Logf("unimplemented mockCallbackerQuestion called: %v %v", c, s) - return nil - } else { - return m.question(c, s) - } -} - -var _ callbackerRead = &mockCallbackerRead{} - -type mockCallbackerRead struct { - t *testing.T - read func(c context.Context, s *streams.Read) error -} - -func (m *mockCallbackerRead) Read(c context.Context, s *streams.Read) error { - if m.read == nil { - m.t.Logf("unimplemented mockCallbackerRead called: %v %v", c, s) - return nil - } else { - return m.read(c, s) - } -} - -var _ callbackerTentativeAccept = &mockCallbackerTentativeAccept{} - -type mockCallbackerTentativeAccept struct { - t *testing.T - tentativeAccept func(c context.Context, s *streams.TentativeAccept) error -} - -func (m *mockCallbackerTentativeAccept) TentativeAccept(c context.Context, s *streams.TentativeAccept) error { - if m.tentativeAccept == nil { - m.t.Logf("unimplemented mockCallbackerTentativeAccept called: %v %v", c, s) - return nil - } else { - return m.tentativeAccept(c, s) - } -} - -var _ callbackerTentativeReject = &mockCallbackerTentativeReject{} - -type mockCallbackerTentativeReject struct { - t *testing.T - tentativeReject func(c context.Context, s *streams.TentativeReject) error -} - -func (m *mockCallbackerTentativeReject) TentativeReject(c context.Context, s *streams.TentativeReject) error { - if m.tentativeReject == nil { - m.t.Logf("unimplemented mockCallbackerTentativeReject called: %v %v", c, s) - return nil - } else { - return m.tentativeReject(c, s) - } -} - -var _ callbackerTravel = &mockCallbackerTravel{} - -type mockCallbackerTravel struct { - t *testing.T - travel func(c context.Context, s *streams.Travel) error -} - -func (m *mockCallbackerTravel) Travel(c context.Context, s *streams.Travel) error { - if m.travel == nil { - m.t.Logf("unimplemented mockCallbackerTravel called: %v %v", c, s) - return nil - } else { - return m.travel(c, s) - } -} - -var _ callbackerView = &mockCallbackerView{} - -type mockCallbackerView struct { - t *testing.T - view func(c context.Context, s *streams.View) error -} - -func (m *mockCallbackerView) View(c context.Context, s *streams.View) error { - if m.view == nil { - m.t.Logf("unimplemented mockCallbackerView called: %v %v", c, s) - return nil - } else { - return m.view(c, s) - } -} - -func TestPostOutbox_CallbackerExtensions(t *testing.T) { - tests := []struct { - name string - cbFn func(t *testing.T) (cb Callbacker, validateFn func() error) - inputFn func() vocab.Serializer - }{ - { - name: "announce", - cbFn: func(t *testing.T) (cb Callbacker, validateFn func() error) { - count := 0 - cb = struct { - *MockCallbacker - *mockCallbackerAnnounce - }{ - MockCallbacker: &MockCallbacker{t: t}, - mockCallbackerAnnounce: &mockCallbackerAnnounce{ - t: t, - announce: func(c context.Context, s *streams.Announce) error { - count++ - return nil - }, - }, - } - validateFn = func() error { - if count != 1 { - return errors.New("expected count == 1") - } - return nil - } - return - }, - inputFn: func() vocab.Serializer { - return &vocab.Announce{} - }, - }, - { - name: "arrive", - cbFn: func(t *testing.T) (cb Callbacker, validateFn func() error) { - count := 0 - cb = struct { - *MockCallbacker - *mockCallbackerArrive - }{ - MockCallbacker: &MockCallbacker{t: t}, - mockCallbackerArrive: &mockCallbackerArrive{ - t: t, - arrive: func(c context.Context, s *streams.Arrive) error { - count++ - return nil - }, - }, - } - validateFn = func() error { - if count != 1 { - return errors.New("expected count == 1") - } - return nil - } - return - }, - inputFn: func() vocab.Serializer { - return &vocab.Arrive{} - }, - }, - { - name: "dislike", - cbFn: func(t *testing.T) (cb Callbacker, validateFn func() error) { - count := 0 - cb = struct { - *MockCallbacker - *mockCallbackerDislike - }{ - MockCallbacker: &MockCallbacker{t: t}, - mockCallbackerDislike: &mockCallbackerDislike{ - t: t, - dislike: func(c context.Context, s *streams.Dislike) error { - count++ - return nil - }, - }, - } - validateFn = func() error { - if count != 1 { - return errors.New("expected count == 1") - } - return nil - } - return - }, - inputFn: func() vocab.Serializer { - return &vocab.Dislike{} - }, - }, - { - name: "flag", - cbFn: func(t *testing.T) (cb Callbacker, validateFn func() error) { - count := 0 - cb = struct { - *MockCallbacker - *mockCallbackerFlag - }{ - MockCallbacker: &MockCallbacker{t: t}, - mockCallbackerFlag: &mockCallbackerFlag{ - t: t, - flag: func(c context.Context, s *streams.Flag) error { - count++ - return nil - }, - }, - } - validateFn = func() error { - if count != 1 { - return errors.New("expected count == 1") - } - return nil - } - return - }, - inputFn: func() vocab.Serializer { - return &vocab.Flag{} - }, - }, - { - name: "ignore", - cbFn: func(t *testing.T) (cb Callbacker, validateFn func() error) { - count := 0 - cb = struct { - *MockCallbacker - *mockCallbackerIgnore - }{ - MockCallbacker: &MockCallbacker{t: t}, - mockCallbackerIgnore: &mockCallbackerIgnore{ - t: t, - ignore: func(c context.Context, s *streams.Ignore) error { - count++ - return nil - }, - }, - } - validateFn = func() error { - if count != 1 { - return errors.New("expected count == 1") - } - return nil - } - return - }, - inputFn: func() vocab.Serializer { - return &vocab.Ignore{} - }, - }, - { - name: "invite", - cbFn: func(t *testing.T) (cb Callbacker, validateFn func() error) { - count := 0 - cb = struct { - *MockCallbacker - *mockCallbackerInvite - }{ - MockCallbacker: &MockCallbacker{t: t}, - mockCallbackerInvite: &mockCallbackerInvite{ - t: t, - invite: func(c context.Context, s *streams.Invite) error { - count++ - return nil - }, - }, - } - validateFn = func() error { - if count != 1 { - return errors.New("expected count == 1") - } - return nil - } - return - }, - inputFn: func() vocab.Serializer { - return &vocab.Invite{} - }, - }, - { - name: "join", - cbFn: func(t *testing.T) (cb Callbacker, validateFn func() error) { - count := 0 - cb = struct { - *MockCallbacker - *mockCallbackerJoin - }{ - MockCallbacker: &MockCallbacker{t: t}, - mockCallbackerJoin: &mockCallbackerJoin{ - t: t, - join: func(c context.Context, s *streams.Join) error { - count++ - return nil - }, - }, - } - validateFn = func() error { - if count != 1 { - return errors.New("expected count == 1") - } - return nil - } - return - }, - inputFn: func() vocab.Serializer { - return &vocab.Join{} - }, - }, - { - name: "leave", - cbFn: func(t *testing.T) (cb Callbacker, validateFn func() error) { - count := 0 - cb = struct { - *MockCallbacker - *mockCallbackerLeave - }{ - MockCallbacker: &MockCallbacker{t: t}, - mockCallbackerLeave: &mockCallbackerLeave{ - t: t, - leave: func(c context.Context, s *streams.Leave) error { - count++ - return nil - }, - }, - } - validateFn = func() error { - if count != 1 { - return errors.New("expected count == 1") - } - return nil - } - return - }, - inputFn: func() vocab.Serializer { - return &vocab.Leave{} - }, - }, - { - name: "listen", - cbFn: func(t *testing.T) (cb Callbacker, validateFn func() error) { - count := 0 - cb = struct { - *MockCallbacker - *mockCallbackerListen - }{ - MockCallbacker: &MockCallbacker{t: t}, - mockCallbackerListen: &mockCallbackerListen{ - t: t, - listen: func(c context.Context, s *streams.Listen) error { - count++ - return nil - }, - }, - } - validateFn = func() error { - if count != 1 { - return errors.New("expected count == 1") - } - return nil - } - return - }, - inputFn: func() vocab.Serializer { - return &vocab.Listen{} - }, - }, - { - name: "move", - cbFn: func(t *testing.T) (cb Callbacker, validateFn func() error) { - count := 0 - cb = struct { - *MockCallbacker - *mockCallbackerMove - }{ - MockCallbacker: &MockCallbacker{t: t}, - mockCallbackerMove: &mockCallbackerMove{ - t: t, - move: func(c context.Context, s *streams.Move) error { - count++ - return nil - }, - }, - } - validateFn = func() error { - if count != 1 { - return errors.New("expected count == 1") - } - return nil - } - return - }, - inputFn: func() vocab.Serializer { - return &vocab.Move{} - }, - }, - { - name: "offer", - cbFn: func(t *testing.T) (cb Callbacker, validateFn func() error) { - count := 0 - cb = struct { - *MockCallbacker - *mockCallbackerOffer - }{ - MockCallbacker: &MockCallbacker{t: t}, - mockCallbackerOffer: &mockCallbackerOffer{ - t: t, - offer: func(c context.Context, s *streams.Offer) error { - count++ - return nil - }, - }, - } - validateFn = func() error { - if count != 1 { - return errors.New("expected count == 1") - } - return nil - } - return - }, - inputFn: func() vocab.Serializer { - return &vocab.Offer{} - }, - }, - { - name: "question", - cbFn: func(t *testing.T) (cb Callbacker, validateFn func() error) { - count := 0 - cb = struct { - *MockCallbacker - *mockCallbackerQuestion - }{ - MockCallbacker: &MockCallbacker{t: t}, - mockCallbackerQuestion: &mockCallbackerQuestion{ - t: t, - question: func(c context.Context, s *streams.Question) error { - count++ - return nil - }, - }, - } - validateFn = func() error { - if count != 1 { - return errors.New("expected count == 1") - } - return nil - } - return - }, - inputFn: func() vocab.Serializer { - return &vocab.Question{} - }, - }, - { - name: "read", - cbFn: func(t *testing.T) (cb Callbacker, validateFn func() error) { - count := 0 - cb = struct { - *MockCallbacker - *mockCallbackerRead - }{ - MockCallbacker: &MockCallbacker{t: t}, - mockCallbackerRead: &mockCallbackerRead{ - t: t, - read: func(c context.Context, s *streams.Read) error { - count++ - return nil - }, - }, - } - validateFn = func() error { - if count != 1 { - return errors.New("expected count == 1") - } - return nil - } - return - }, - inputFn: func() vocab.Serializer { - return &vocab.Read{} - }, - }, - { - name: "tentative accept", - cbFn: func(t *testing.T) (cb Callbacker, validateFn func() error) { - count := 0 - cb = struct { - *MockCallbacker - *mockCallbackerTentativeAccept - }{ - MockCallbacker: &MockCallbacker{t: t}, - mockCallbackerTentativeAccept: &mockCallbackerTentativeAccept{ - t: t, - tentativeAccept: func(c context.Context, s *streams.TentativeAccept) error { - count++ - return nil - }, - }, - } - validateFn = func() error { - if count != 1 { - return errors.New("expected count == 1") - } - return nil - } - return - }, - inputFn: func() vocab.Serializer { - return &vocab.TentativeAccept{} - }, - }, - { - name: "tentative reject", - cbFn: func(t *testing.T) (cb Callbacker, validateFn func() error) { - count := 0 - cb = struct { - *MockCallbacker - *mockCallbackerTentativeReject - }{ - MockCallbacker: &MockCallbacker{t: t}, - mockCallbackerTentativeReject: &mockCallbackerTentativeReject{ - t: t, - tentativeReject: func(c context.Context, s *streams.TentativeReject) error { - count++ - return nil - }, - }, - } - validateFn = func() error { - if count != 1 { - return errors.New("expected count == 1") - } - return nil - } - return - }, - inputFn: func() vocab.Serializer { - return &vocab.TentativeReject{} - }, - }, - { - name: "travel", - cbFn: func(t *testing.T) (cb Callbacker, validateFn func() error) { - count := 0 - cb = struct { - *MockCallbacker - *mockCallbackerTravel - }{ - MockCallbacker: &MockCallbacker{t: t}, - mockCallbackerTravel: &mockCallbackerTravel{ - t: t, - travel: func(c context.Context, s *streams.Travel) error { - count++ - return nil - }, - }, - } - validateFn = func() error { - if count != 1 { - return errors.New("expected count == 1") - } - return nil - } - return - }, - inputFn: func() vocab.Serializer { - return &vocab.Travel{} - }, - }, - { - name: "view", - cbFn: func(t *testing.T) (cb Callbacker, validateFn func() error) { - count := 0 - cb = struct { - *MockCallbacker - *mockCallbackerView - }{ - MockCallbacker: &MockCallbacker{t: t}, - mockCallbackerView: &mockCallbackerView{ - t: t, - view: func(c context.Context, s *streams.View) error { - count++ - return nil - }, - }, - } - validateFn = func() error { - if count != 1 { - return errors.New("expected count == 1") - } - return nil - } - return - }, - inputFn: func() vocab.Serializer { - return &vocab.View{} - }, - }, - } - for _, test := range tests { - t.Logf("Running table test case %q", test.name) - - clock := &MockClock{now} - app := &MockApplication{t: t} - socialApp := &MockSocialApp{MockApplication: app, t: t} - cb, validateFn := test.cbFn(t) - p := NewSocialPubber(clock, socialApp, cb) - input := test.inputFn() - - resp := httptest.NewRecorder() - req := Sign(ActivityPubRequest(httptest.NewRequest("POST", testOutboxURI, bytes.NewBuffer(MustSerialize(input))))) - socialApp.getSocialAPIVerifier = func(c context.Context) SocialAPIVerifier { - return nil - } - socialApp.getPublicKeyForOutbox = func(c context.Context, publicKeyId string, boxIRI *url.URL) (crypto.PublicKey, httpsig.Algorithm, error) { - return testPrivateKey.Public(), httpsig.RSA_SHA256, nil - } - app.newId = func(c context.Context, t Typer) *url.URL { - return testNewIRI - } - app.getOutbox = func(c context.Context, r *http.Request, rw RWType) (vocab.OrderedCollectionType, error) { - oc := &vocab.OrderedCollection{} - oc.AppendType("OrderedCollection") - return oc, nil - } - app.set = func(c context.Context, o PubObject) error { - return nil - } - handled, err := p.PostOutbox(context.Background(), resp, req) - if err != nil { - t.Fatalf("(%s) %s", test.name, err) - } else if !handled { - t.Fatalf("(%s) expected handled, got !handled", test.name) - } else if err := validateFn(); err != nil { - t.Fatalf("(%s) %s", test.name, err) - } - } -} - -func TestPostInbox_CallbackerExtensions(t *testing.T) { - tests := []struct { - name string - cbFn func(t *testing.T) (cb Callbacker, validateFn func() error) - inputFn func() vocab.Serializer - }{ - { - name: "announce", - cbFn: func(t *testing.T) (cb Callbacker, validateFn func() error) { - count := 0 - cb = struct { - *MockCallbacker - *mockCallbackerAnnounce - }{ - MockCallbacker: &MockCallbacker{t: t}, - mockCallbackerAnnounce: &mockCallbackerAnnounce{ - t: t, - announce: func(c context.Context, s *streams.Announce) error { - count++ - return nil - }, - }, - } - validateFn = func() error { - if count != 1 { - return errors.New("expected count == 1") - } - return nil - } - return - }, - inputFn: func() vocab.Serializer { - s := &vocab.Announce{} - s.SetId(noteActivityIRI) - return s - }, - }, - { - name: "arrive", - cbFn: func(t *testing.T) (cb Callbacker, validateFn func() error) { - count := 0 - cb = struct { - *MockCallbacker - *mockCallbackerArrive - }{ - MockCallbacker: &MockCallbacker{t: t}, - mockCallbackerArrive: &mockCallbackerArrive{ - t: t, - arrive: func(c context.Context, s *streams.Arrive) error { - count++ - return nil - }, - }, - } - validateFn = func() error { - if count != 1 { - return errors.New("expected count == 1") - } - return nil - } - return - }, - inputFn: func() vocab.Serializer { - s := &vocab.Arrive{} - s.SetId(noteActivityIRI) - return s - }, - }, - { - name: "dislike", - cbFn: func(t *testing.T) (cb Callbacker, validateFn func() error) { - count := 0 - cb = struct { - *MockCallbacker - *mockCallbackerDislike - }{ - MockCallbacker: &MockCallbacker{t: t}, - mockCallbackerDislike: &mockCallbackerDislike{ - t: t, - dislike: func(c context.Context, s *streams.Dislike) error { - count++ - return nil - }, - }, - } - validateFn = func() error { - if count != 1 { - return errors.New("expected count == 1") - } - return nil - } - return - }, - inputFn: func() vocab.Serializer { - s := &vocab.Dislike{} - s.SetId(noteActivityIRI) - return s - }, - }, - { - name: "flag", - cbFn: func(t *testing.T) (cb Callbacker, validateFn func() error) { - count := 0 - cb = struct { - *MockCallbacker - *mockCallbackerFlag - }{ - MockCallbacker: &MockCallbacker{t: t}, - mockCallbackerFlag: &mockCallbackerFlag{ - t: t, - flag: func(c context.Context, s *streams.Flag) error { - count++ - return nil - }, - }, - } - validateFn = func() error { - if count != 1 { - return errors.New("expected count == 1") - } - return nil - } - return - }, - inputFn: func() vocab.Serializer { - s := &vocab.Flag{} - s.SetId(noteActivityIRI) - return s - }, - }, - { - name: "ignore", - cbFn: func(t *testing.T) (cb Callbacker, validateFn func() error) { - count := 0 - cb = struct { - *MockCallbacker - *mockCallbackerIgnore - }{ - MockCallbacker: &MockCallbacker{t: t}, - mockCallbackerIgnore: &mockCallbackerIgnore{ - t: t, - ignore: func(c context.Context, s *streams.Ignore) error { - count++ - return nil - }, - }, - } - validateFn = func() error { - if count != 1 { - return errors.New("expected count == 1") - } - return nil - } - return - }, - inputFn: func() vocab.Serializer { - s := &vocab.Ignore{} - s.SetId(noteActivityIRI) - return s - }, - }, - { - name: "invite", - cbFn: func(t *testing.T) (cb Callbacker, validateFn func() error) { - count := 0 - cb = struct { - *MockCallbacker - *mockCallbackerInvite - }{ - MockCallbacker: &MockCallbacker{t: t}, - mockCallbackerInvite: &mockCallbackerInvite{ - t: t, - invite: func(c context.Context, s *streams.Invite) error { - count++ - return nil - }, - }, - } - validateFn = func() error { - if count != 1 { - return errors.New("expected count == 1") - } - return nil - } - return - }, - inputFn: func() vocab.Serializer { - s := &vocab.Invite{} - s.SetId(noteActivityIRI) - return s - }, - }, - { - name: "join", - cbFn: func(t *testing.T) (cb Callbacker, validateFn func() error) { - count := 0 - cb = struct { - *MockCallbacker - *mockCallbackerJoin - }{ - MockCallbacker: &MockCallbacker{t: t}, - mockCallbackerJoin: &mockCallbackerJoin{ - t: t, - join: func(c context.Context, s *streams.Join) error { - count++ - return nil - }, - }, - } - validateFn = func() error { - if count != 1 { - return errors.New("expected count == 1") - } - return nil - } - return - }, - inputFn: func() vocab.Serializer { - s := &vocab.Join{} - s.SetId(noteActivityIRI) - return s - }, - }, - { - name: "leave", - cbFn: func(t *testing.T) (cb Callbacker, validateFn func() error) { - count := 0 - cb = struct { - *MockCallbacker - *mockCallbackerLeave - }{ - MockCallbacker: &MockCallbacker{t: t}, - mockCallbackerLeave: &mockCallbackerLeave{ - t: t, - leave: func(c context.Context, s *streams.Leave) error { - count++ - return nil - }, - }, - } - validateFn = func() error { - if count != 1 { - return errors.New("expected count == 1") - } - return nil - } - return - }, - inputFn: func() vocab.Serializer { - s := &vocab.Leave{} - s.SetId(noteActivityIRI) - return s - }, - }, - { - name: "listen", - cbFn: func(t *testing.T) (cb Callbacker, validateFn func() error) { - count := 0 - cb = struct { - *MockCallbacker - *mockCallbackerListen - }{ - MockCallbacker: &MockCallbacker{t: t}, - mockCallbackerListen: &mockCallbackerListen{ - t: t, - listen: func(c context.Context, s *streams.Listen) error { - count++ - return nil - }, - }, - } - validateFn = func() error { - if count != 1 { - return errors.New("expected count == 1") - } - return nil - } - return - }, - inputFn: func() vocab.Serializer { - s := &vocab.Listen{} - s.SetId(noteActivityIRI) - return s - }, - }, - { - name: "move", - cbFn: func(t *testing.T) (cb Callbacker, validateFn func() error) { - count := 0 - cb = struct { - *MockCallbacker - *mockCallbackerMove - }{ - MockCallbacker: &MockCallbacker{t: t}, - mockCallbackerMove: &mockCallbackerMove{ - t: t, - move: func(c context.Context, s *streams.Move) error { - count++ - return nil - }, - }, - } - validateFn = func() error { - if count != 1 { - return errors.New("expected count == 1") - } - return nil - } - return - }, - inputFn: func() vocab.Serializer { - s := &vocab.Move{} - s.SetId(noteActivityIRI) - return s - }, - }, - { - name: "offer", - cbFn: func(t *testing.T) (cb Callbacker, validateFn func() error) { - count := 0 - cb = struct { - *MockCallbacker - *mockCallbackerOffer - }{ - MockCallbacker: &MockCallbacker{t: t}, - mockCallbackerOffer: &mockCallbackerOffer{ - t: t, - offer: func(c context.Context, s *streams.Offer) error { - count++ - return nil - }, - }, - } - validateFn = func() error { - if count != 1 { - return errors.New("expected count == 1") - } - return nil - } - return - }, - inputFn: func() vocab.Serializer { - s := &vocab.Offer{} - s.SetId(noteActivityIRI) - return s - }, - }, - { - name: "question", - cbFn: func(t *testing.T) (cb Callbacker, validateFn func() error) { - count := 0 - cb = struct { - *MockCallbacker - *mockCallbackerQuestion - }{ - MockCallbacker: &MockCallbacker{t: t}, - mockCallbackerQuestion: &mockCallbackerQuestion{ - t: t, - question: func(c context.Context, s *streams.Question) error { - count++ - return nil - }, - }, - } - validateFn = func() error { - if count != 1 { - return errors.New("expected count == 1") - } - return nil - } - return - }, - inputFn: func() vocab.Serializer { - s := &vocab.Question{} - s.SetId(noteActivityIRI) - return s - }, - }, - { - name: "read", - cbFn: func(t *testing.T) (cb Callbacker, validateFn func() error) { - count := 0 - cb = struct { - *MockCallbacker - *mockCallbackerRead - }{ - MockCallbacker: &MockCallbacker{t: t}, - mockCallbackerRead: &mockCallbackerRead{ - t: t, - read: func(c context.Context, s *streams.Read) error { - count++ - return nil - }, - }, - } - validateFn = func() error { - if count != 1 { - return errors.New("expected count == 1") - } - return nil - } - return - }, - inputFn: func() vocab.Serializer { - s := &vocab.Read{} - s.SetId(noteActivityIRI) - return s - }, - }, - { - name: "tentative accept", - cbFn: func(t *testing.T) (cb Callbacker, validateFn func() error) { - count := 0 - cb = struct { - *MockCallbacker - *mockCallbackerTentativeAccept - }{ - MockCallbacker: &MockCallbacker{t: t}, - mockCallbackerTentativeAccept: &mockCallbackerTentativeAccept{ - t: t, - tentativeAccept: func(c context.Context, s *streams.TentativeAccept) error { - count++ - return nil - }, - }, - } - validateFn = func() error { - if count != 1 { - return errors.New("expected count == 1") - } - return nil - } - return - }, - inputFn: func() vocab.Serializer { - s := &vocab.TentativeAccept{} - s.SetId(noteActivityIRI) - return s - }, - }, - { - name: "tentative reject", - cbFn: func(t *testing.T) (cb Callbacker, validateFn func() error) { - count := 0 - cb = struct { - *MockCallbacker - *mockCallbackerTentativeReject - }{ - MockCallbacker: &MockCallbacker{t: t}, - mockCallbackerTentativeReject: &mockCallbackerTentativeReject{ - t: t, - tentativeReject: func(c context.Context, s *streams.TentativeReject) error { - count++ - return nil - }, - }, - } - validateFn = func() error { - if count != 1 { - return errors.New("expected count == 1") - } - return nil - } - return - }, - inputFn: func() vocab.Serializer { - s := &vocab.TentativeReject{} - s.SetId(noteActivityIRI) - return s - }, - }, - { - name: "travel", - cbFn: func(t *testing.T) (cb Callbacker, validateFn func() error) { - count := 0 - cb = struct { - *MockCallbacker - *mockCallbackerTravel - }{ - MockCallbacker: &MockCallbacker{t: t}, - mockCallbackerTravel: &mockCallbackerTravel{ - t: t, - travel: func(c context.Context, s *streams.Travel) error { - count++ - return nil - }, - }, - } - validateFn = func() error { - if count != 1 { - return errors.New("expected count == 1") - } - return nil - } - return - }, - inputFn: func() vocab.Serializer { - s := &vocab.Travel{} - s.SetId(noteActivityIRI) - return s - }, - }, - { - name: "view", - cbFn: func(t *testing.T) (cb Callbacker, validateFn func() error) { - count := 0 - cb = struct { - *MockCallbacker - *mockCallbackerView - }{ - MockCallbacker: &MockCallbacker{t: t}, - mockCallbackerView: &mockCallbackerView{ - t: t, - view: func(c context.Context, s *streams.View) error { - count++ - return nil - }, - }, - } - validateFn = func() error { - if count != 1 { - return errors.New("expected count == 1") - } - return nil - } - return - }, - inputFn: func() vocab.Serializer { - s := &vocab.View{} - s.SetId(noteActivityIRI) - return s - }, - }, - } - for _, test := range tests { - t.Logf("Running table test case %q", test.name) - - clock := &MockClock{now} - app := &MockApplication{t: t} - fedApp := &MockFederateApp{MockApplication: app, t: t} - d := &MockDeliverer{t: t} - h := &MockHttpClient{t: t} - cb, validateFn := test.cbFn(t) - p := NewFederatingPubber(clock, fedApp, cb, d, h, testAgent, 1, 1) - input := test.inputFn() - - resp := httptest.NewRecorder() - req := ActivityPubRequest(httptest.NewRequest("POST", testInboxURI, bytes.NewBuffer(MustSerialize(input)))) - fedApp.unblocked = func(c context.Context, actorIRIs []*url.URL) error { - return nil - } - app.getInbox = func(c context.Context, r *http.Request, rw RWType) (vocab.OrderedCollectionType, error) { - oc := &vocab.OrderedCollection{} - oc.AppendType("OrderedCollection") - return oc, nil - } - app.set = func(c context.Context, o PubObject) error { - return nil - } - app.has = func(c context.Context, id *url.URL) (bool, error) { - return false, nil - } - app.get = func(c context.Context, iri *url.URL, rw RWType) (PubObject, error) { - return samActor, nil - } - handled, err := p.PostInbox(context.Background(), resp, req) - if err != nil { - t.Fatalf("(%s) %s", test.name, err) - } else if !handled { - t.Fatalf("(%s) expected handled, got !handled", test.name) - } else if err := validateFn(); err != nil { - t.Fatalf("(%s) %s", test.name, err) - } - } -} - -func TestPostInbox_Announce_AddsToSharesCollection(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostInboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := ActivityPubRequest(httptest.NewRequest("POST", testInboxURI, bytes.NewBuffer(MustSerialize(testAnnounceNote)))) - gotOwns := 0 - var gotOwnsId *url.URL - app.MockFederateApp.owns = func(c context.Context, id *url.URL) bool { - gotOwns++ - gotOwnsId = id - return true - } - gotGet := 0 - var gotGetId *url.URL - app.MockFederateApp.get = func(c context.Context, id *url.URL, rw RWType) (PubObject, error) { - if rw != ReadWrite { - t.Fatalf("expected RWType of %v, got %v", ReadWrite, rw) - } - gotGet++ - gotGetId = id - v := &vocab.Note{} - v.SetId(noteIRI) - v.AppendNameString(noteName) - v.AppendContentString("This is a simple note") - v.SetSharesCollection(&vocab.Collection{}) - return v, nil - } - gotSet := 0 - var gotSetObject PubObject - app.MockFederateApp.set = func(c context.Context, target PubObject) error { - gotSet++ - if gotSet == 1 { - gotSetObject = target - } - return nil - } - handled, err := p.PostInbox(context.Background(), resp, req) - expected := &vocab.Collection{} - expected.AppendItemsIRI(noteActivityIRI) - expectedNote := &vocab.Note{} - expectedNote.SetId(noteIRI) - expectedNote.AppendNameString(noteName) - expectedNote.AppendContentString("This is a simple note") - expectedNote.SetSharesCollection(expected) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotOwns != 1 { - t.Fatalf("expected %d, got %d", 1, gotOwns) - } else if gotOwnsId.String() != noteURIString { - t.Fatalf("expected %s, got %s", noteURIString, gotOwnsId.String()) - } else if gotGet != 1 { - t.Fatalf("expected %d, got %d", 1, gotGet) - } else if gotGetId.String() != noteURIString { - t.Fatalf("expected %s, got %s", noteURIString, gotGetId.String()) - } else if gotSet != 2 { - t.Fatalf("expected %d, got %d", 2, gotSet) - } else if err := PubObjectEquals(gotSetObject, expectedNote); err != nil { - t.Fatalf("unexpected callback object: %s", err) - } -} - -func TestPostInbox_Announce_AddsToDefaultOrderedCollection(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostInboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := ActivityPubRequest(httptest.NewRequest("POST", testInboxURI, bytes.NewBuffer(MustSerialize(testAnnounceNote)))) - gotOwns := 0 - var gotOwnsId *url.URL - app.MockFederateApp.owns = func(c context.Context, id *url.URL) bool { - gotOwns++ - gotOwnsId = id - return true - } - gotGet := 0 - var gotGetId *url.URL - app.MockFederateApp.get = func(c context.Context, id *url.URL, rw RWType) (PubObject, error) { - if rw != ReadWrite { - t.Fatalf("expected RWType of %v, got %v", ReadWrite, rw) - } - gotGet++ - gotGetId = id - v := &vocab.Note{} - v.SetId(noteIRI) - v.AppendNameString(noteName) - v.AppendContentString("This is a simple note") - return v, nil - } - gotSet := 0 - var gotSetObject PubObject - app.MockFederateApp.set = func(c context.Context, target PubObject) error { - gotSet++ - if gotSet == 1 { - gotSetObject = target - } - return nil - } - handled, err := p.PostInbox(context.Background(), resp, req) - expected := &vocab.OrderedCollection{} - expected.AppendOrderedItemsIRI(noteActivityIRI) - expectedNote := &vocab.Note{} - expectedNote.SetId(noteIRI) - expectedNote.AppendNameString(noteName) - expectedNote.AppendContentString("This is a simple note") - expectedNote.SetSharesOrderedCollection(expected) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotOwns != 1 { - t.Fatalf("expected %d, got %d", 1, gotOwns) - } else if gotOwnsId.String() != noteURIString { - t.Fatalf("expected %s, got %s", noteURIString, gotOwnsId.String()) - } else if gotGet != 1 { - t.Fatalf("expected %d, got %d", 1, gotGet) - } else if gotGetId.String() != noteURIString { - t.Fatalf("expected %s, got %s", noteURIString, gotGetId.String()) - } else if gotSet != 2 { - t.Fatalf("expected %d, got %d", 2, gotSet) - } else if err := PubObjectEquals(gotSetObject, expectedNote); err != nil { - t.Fatalf("unexpected callback object: %s", err) - } -} - -func TestPostInbox_Announce_DoesNotAddSharesToCollectionIfAlreadyPresent(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostInboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := ActivityPubRequest(httptest.NewRequest("POST", testInboxURI, bytes.NewBuffer(MustSerialize(testAnnounceNote)))) - app.MockFederateApp.owns = func(c context.Context, id *url.URL) bool { - return true - } - app.MockFederateApp.get = func(c context.Context, id *url.URL, rw RWType) (PubObject, error) { - shares := &vocab.Collection{} - shares.AppendItemsIRI(noteActivityIRI) - v := &vocab.Note{} - v.SetId(noteIRI) - v.AppendNameString(noteName) - v.AppendContentString("This is a simple note") - v.SetSharesCollection(shares) - return v, nil - } - gotSet := 0 - var gotSetObject PubObject - app.MockFederateApp.set = func(c context.Context, target PubObject) error { - gotSet++ - if gotSet == 1 { - gotSetObject = target - } - return nil - } - handled, err := p.PostInbox(context.Background(), resp, req) - expected := &vocab.OrderedCollection{} - expected.AppendOrderedItemsIRI(noteActivityIRI) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if gotSet != 1 { - t.Fatalf("expected %d, got %d", 1, gotSet) - } else if err := PubObjectEquals(gotSetObject, expected); err != nil { - t.Fatalf("unexpected callback object: %s", err) - } -} - -func TestPostInbox_Announce_AddsToSharesOrderedCollection(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostInboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := ActivityPubRequest(httptest.NewRequest("POST", testInboxURI, bytes.NewBuffer(MustSerialize(testAnnounceNote)))) - app.MockFederateApp.owns = func(c context.Context, id *url.URL) bool { - return true - } - app.MockFederateApp.get = func(c context.Context, id *url.URL, rw RWType) (PubObject, error) { - v := &vocab.Note{} - v.SetId(noteIRI) - v.AppendNameString(noteName) - v.AppendContentString("This is a simple note") - v.SetSharesOrderedCollection(&vocab.OrderedCollection{}) - return v, nil - } - gotSet := 0 - var gotSetObject PubObject - app.MockFederateApp.set = func(c context.Context, target PubObject) error { - gotSet++ - if gotSet == 1 { - gotSetObject = target - } - return nil - } - handled, err := p.PostInbox(context.Background(), resp, req) - expected := &vocab.OrderedCollection{} - expected.AppendOrderedItemsIRI(noteActivityIRI) - expectedNote := &vocab.Note{} - expectedNote.SetId(noteIRI) - expectedNote.AppendNameString(noteName) - expectedNote.AppendContentString("This is a simple note") - expectedNote.SetSharesOrderedCollection(expected) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if err := PubObjectEquals(gotSetObject, expectedNote); err != nil { - t.Fatalf("unexpected callback object: %s", err) - } -} - -func TestPostInbox_Announce_AddsToSharesIRI(t *testing.T) { - app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p := NewPubberTest(t) - PreparePubberPostInboxTest(t, app, socialApp, fedApp, socialCb, fedCb, d, httpClient, p) - resp := httptest.NewRecorder() - req := ActivityPubRequest(httptest.NewRequest("POST", testInboxURI, bytes.NewBuffer(MustSerialize(testAnnounceNote)))) - app.MockFederateApp.owns = func(c context.Context, id *url.URL) bool { - return true - } - app.MockFederateApp.get = func(c context.Context, id *url.URL, rw RWType) (PubObject, error) { - if *id == *noteIRI { - v := &vocab.Note{} - v.SetId(noteIRI) - v.AppendNameString(noteName) - v.AppendContentString("This is a simple note") - v.SetSharesAnyURI(testNewIRI) - return v, nil - } else if *id == *testNewIRI { - return &vocab.OrderedCollection{}, nil - } - t.Fatalf("unexpected get(%s)", id) - return nil, nil - } - gotSet := 0 - var gotSetObject PubObject - app.MockFederateApp.set = func(c context.Context, target PubObject) error { - gotSet++ - if gotSet == 1 { - gotSetObject = target - } - return nil - } - handled, err := p.PostInbox(context.Background(), resp, req) - expected := &vocab.OrderedCollection{} - expected.AppendOrderedItemsIRI(noteActivityIRI) - if err != nil { - t.Fatal(err) - } else if !handled { - t.Fatalf("expected handled, got !handled") - } else if err := PubObjectEquals(gotSetObject, expected); err != nil { - t.Fatalf("unexpected callback object: %s", err) - } -} diff --git a/pub/handlers_test.go b/pub/handlers_test.go deleted file mode 100644 index 29b491e..0000000 --- a/pub/handlers_test.go +++ /dev/null @@ -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) - } - } - } -} diff --git a/pub/mock_clock_test.go b/pub/mock_clock_test.go new file mode 100644 index 0000000..e5a7b71 --- /dev/null +++ b/pub/mock_clock_test.go @@ -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)) +} diff --git a/pub/mock_delegate_actor_test.go b/pub/mock_delegate_actor_test.go new file mode 100644 index 0000000..27523c0 --- /dev/null +++ b/pub/mock_delegate_actor_test.go @@ -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) +} diff --git a/pub/pub_test.go b/pub/pub_test.go new file mode 100644 index 0000000..01be938 --- /dev/null +++ b/pub/pub_test.go @@ -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) +} diff --git a/pub/util.go b/pub/util.go index 61e4424..2cbef20 100644 --- a/pub/util.go +++ b/pub/util.go @@ -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. diff --git a/pub/internal_test.go b/pub/util_test.go similarity index 88% rename from pub/internal_test.go rename to pub/util_test.go index 91b6f39..2a1fec1 100644 --- a/pub/internal_test.go +++ b/pub/util_test.go @@ -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) + } + }) } }