forkjo/tests/integration/api_activitypub_person_test.go
Aravinth Manivannan f9cbea3d6b feat: access ActivityPub client through interfaces to facilitate mocking in unit tests ()
Was facing issues while writing unit tests for federation code. Mocks weren't catching all network calls, because was being out of scope of the mocking infra. Plus, I think we can have more granular tests.

This PR puts the client behind an interface, that can be retrieved from `ctx`. Context doesn't require initialization, as it defaults to the implementation available in-tree. It may be overridden when required (like testing).

## Mechanism

1. Get client factory from `ctx` (factory contains network and crypto parameters that are needed)
2. Initialize client with sender's keys and the receiver's public key
3. Use client as before.

Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/4853
Reviewed-by: Earl Warren <earl-warren@noreply.codeberg.org>
Co-authored-by: Aravinth Manivannan <realaravinth@batsense.net>
Co-committed-by: Aravinth Manivannan <realaravinth@batsense.net>
2024-08-07 05:45:24 +00:00

116 lines
3.4 KiB
Go

// Copyright 2022 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package integration
import (
"context"
"fmt"
"net/http"
"net/http/httptest"
"net/url"
"testing"
"code.gitea.io/gitea/models/db"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/activitypub"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/routers"
ap "github.com/go-ap/activitypub"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestActivityPubPerson(t *testing.T) {
setting.Federation.Enabled = true
testWebRoutes = routers.NormalRoutes()
defer func() {
setting.Federation.Enabled = false
testWebRoutes = routers.NormalRoutes()
}()
onGiteaRun(t, func(*testing.T, *url.URL) {
userID := 2
username := "user2"
req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/activitypub/user-id/%v", userID))
resp := MakeRequest(t, req, http.StatusOK)
body := resp.Body.Bytes()
assert.Contains(t, string(body), "@context")
var person ap.Person
err := person.UnmarshalJSON(body)
require.NoError(t, err)
assert.Equal(t, ap.PersonType, person.Type)
assert.Equal(t, username, person.PreferredUsername.String())
keyID := person.GetID().String()
assert.Regexp(t, fmt.Sprintf("activitypub/user-id/%v$", userID), keyID)
assert.Regexp(t, fmt.Sprintf("activitypub/user-id/%v/outbox$", userID), person.Outbox.GetID().String())
assert.Regexp(t, fmt.Sprintf("activitypub/user-id/%v/inbox$", userID), person.Inbox.GetID().String())
pubKey := person.PublicKey
assert.NotNil(t, pubKey)
publicKeyID := keyID + "#main-key"
assert.Equal(t, pubKey.ID.String(), publicKeyID)
pubKeyPem := pubKey.PublicKeyPem
assert.NotNil(t, pubKeyPem)
assert.Regexp(t, "^-----BEGIN PUBLIC KEY-----", pubKeyPem)
})
}
func TestActivityPubMissingPerson(t *testing.T) {
setting.Federation.Enabled = true
testWebRoutes = routers.NormalRoutes()
defer func() {
setting.Federation.Enabled = false
testWebRoutes = routers.NormalRoutes()
}()
onGiteaRun(t, func(*testing.T, *url.URL) {
req := NewRequest(t, "GET", "/api/v1/activitypub/user-id/999999999")
resp := MakeRequest(t, req, http.StatusNotFound)
assert.Contains(t, resp.Body.String(), "user does not exist")
})
}
func TestActivityPubPersonInbox(t *testing.T) {
setting.Federation.Enabled = true
testWebRoutes = routers.NormalRoutes()
defer func() {
setting.Federation.Enabled = false
testWebRoutes = routers.NormalRoutes()
}()
srv := httptest.NewServer(testWebRoutes)
defer srv.Close()
onGiteaRun(t, func(*testing.T, *url.URL) {
appURL := setting.AppURL
setting.AppURL = srv.URL + "/"
defer func() {
setting.Database.LogSQL = false
setting.AppURL = appURL
}()
username1 := "user1"
ctx := context.Background()
user1, err := user_model.GetUserByName(ctx, username1)
require.NoError(t, err)
user1url := fmt.Sprintf("%s/api/v1/activitypub/user-id/1#main-key", srv.URL)
cf, err := activitypub.GetClientFactory(ctx)
require.NoError(t, err)
c, err := cf.WithKeys(db.DefaultContext, user1, user1url)
require.NoError(t, err)
user2inboxurl := fmt.Sprintf("%s/api/v1/activitypub/user-id/2/inbox", srv.URL)
// Signed request succeeds
resp, err := c.Post([]byte{}, user2inboxurl)
require.NoError(t, err)
assert.Equal(t, http.StatusNoContent, resp.StatusCode)
// Unsigned request fails
req := NewRequest(t, "POST", user2inboxurl)
MakeRequest(t, req, http.StatusBadRequest)
})
}