Files
owncast/activitypub/resolvers/nil_safety_test.go
T
Gabe KangasandGitHub a82efb0e9a Add a layer of safety around required ActivityPub Actor fields (#4703)
* fix(ap): add safe constructors, getters, and validators to ActivityPub actors to address #4701

* chore: replace nil check with the new Validate() method

* chore(test): added test to verify the values extracted from actors

* fix: return the specific error type + test for it

* fix(ap): add recovery for each AP inbox worker for a worst case scenario

* fix(ap): add additional safe accessor methods to other AP entities other than actors

* chore(tests): add tests for the new safe accessors

* fix(ap): handle empty public keys in AP actors
2026-01-17 14:25:06 -08:00

172 lines
5.5 KiB
Go

package resolvers
import (
"net/url"
"testing"
"github.com/go-fed/activity/streams"
)
func mustParseURL(s string) *url.URL {
u, err := url.Parse(s)
if err != nil {
panic(err)
}
return u
}
// TestGetResolvedActorFromActorPropertyWithNil verifies that the function
// doesn't panic when given a nil actor property.
func TestGetResolvedActorFromActorPropertyWithNil(t *testing.T) {
defer func() {
if r := recover(); r != nil {
t.Errorf("GetResolvedActorFromActorProperty panicked with nil: %v", r)
}
}()
_, err := GetResolvedActorFromActorProperty(nil)
if err == nil {
t.Error("GetResolvedActorFromActorProperty(nil) should return error")
}
}
// TestGetResolvedActorFromActorPropertyWithEmpty verifies that the function
// doesn't panic when given an empty actor property.
func TestGetResolvedActorFromActorPropertyWithEmpty(t *testing.T) {
defer func() {
if r := recover(); r != nil {
t.Errorf("GetResolvedActorFromActorProperty panicked with empty: %v", r)
}
}()
actor := streams.NewActivityStreamsActorProperty()
_, err := GetResolvedActorFromActorProperty(actor)
if err == nil {
t.Error("GetResolvedActorFromActorProperty with empty actor should return error")
}
}
// TestGetResolvedActorFromActorPropertyWithIRI verifies that the function
// handles the case where an IRI needs to be resolved.
// Note: This test involves network calls and config repository access which may
// panic in a test environment. This is expected since we're testing nil safety
// of ActivityPub property handling, not network behavior.
func TestGetResolvedActorFromActorPropertyWithIRI(t *testing.T) {
t.Skip("Skipping IRI resolution test - requires network access and proper config setup")
}
// TestGetResolvedActorFromActorPropertyWithPersonButMissingFields verifies that
// the function handles Person objects that are missing required fields.
func TestGetResolvedActorFromActorPropertyWithPersonMissingFields(t *testing.T) {
defer func() {
if r := recover(); r != nil {
t.Errorf("GetResolvedActorFromActorProperty panicked: %v", r)
}
}()
actor := streams.NewActivityStreamsActorProperty()
person := streams.NewActivityStreamsPerson()
// Person has no ID, inbox, username, or public key
actor.AppendActivityStreamsPerson(person)
_, err := GetResolvedActorFromActorProperty(actor)
if err == nil {
t.Error("GetResolvedActorFromActorProperty with incomplete Person should return error")
}
}
// TestGetResolvedActorFromActorPropertyWithServiceMissingFields verifies that
// the function handles Service objects that are missing required fields.
func TestGetResolvedActorFromActorPropertyWithServiceMissingFields(t *testing.T) {
defer func() {
if r := recover(); r != nil {
t.Errorf("GetResolvedActorFromActorProperty panicked: %v", r)
}
}()
actor := streams.NewActivityStreamsActorProperty()
service := streams.NewActivityStreamsService()
// Service has no ID, inbox, username, or public key
actor.AppendActivityStreamsService(service)
_, err := GetResolvedActorFromActorProperty(actor)
if err == nil {
t.Error("GetResolvedActorFromActorProperty with incomplete Service should return error")
}
}
// TestGetResolvedActorFromActorPropertyWithApplicationMissingFields verifies that
// the function handles Application objects that are missing required fields.
func TestGetResolvedActorFromActorPropertyWithApplicationMissingFields(t *testing.T) {
defer func() {
if r := recover(); r != nil {
t.Errorf("GetResolvedActorFromActorProperty panicked: %v", r)
}
}()
actor := streams.NewActivityStreamsActorProperty()
app := streams.NewActivityStreamsApplication()
// Application has no ID, inbox, username, or public key
actor.AppendActivityStreamsApplication(app)
_, err := GetResolvedActorFromActorProperty(actor)
if err == nil {
t.Error("GetResolvedActorFromActorProperty with incomplete Application should return error")
}
}
// TestNilSafetyNoPanic is a comprehensive test that ensures none of the
// resolver functions panic with nil/empty inputs.
func TestNilSafetyNoPanic(t *testing.T) {
t.Run("GetResolvedActorFromActorProperty with nil", func(t *testing.T) {
defer func() {
if r := recover(); r != nil {
t.Errorf("panicked: %v", r)
}
}()
_, _ = GetResolvedActorFromActorProperty(nil)
})
t.Run("GetResolvedActorFromActorProperty with empty", func(t *testing.T) {
defer func() {
if r := recover(); r != nil {
t.Errorf("panicked: %v", r)
}
}()
_, _ = GetResolvedActorFromActorProperty(streams.NewActivityStreamsActorProperty())
})
t.Run("GetResolvedActorFromActorProperty with Person no fields", func(t *testing.T) {
defer func() {
if r := recover(); r != nil {
t.Errorf("panicked: %v", r)
}
}()
actor := streams.NewActivityStreamsActorProperty()
actor.AppendActivityStreamsPerson(streams.NewActivityStreamsPerson())
_, _ = GetResolvedActorFromActorProperty(actor)
})
t.Run("GetResolvedActorFromActorProperty with Service no fields", func(t *testing.T) {
defer func() {
if r := recover(); r != nil {
t.Errorf("panicked: %v", r)
}
}()
actor := streams.NewActivityStreamsActorProperty()
actor.AppendActivityStreamsService(streams.NewActivityStreamsService())
_, _ = GetResolvedActorFromActorProperty(actor)
})
t.Run("GetResolvedActorFromActorProperty with Application no fields", func(t *testing.T) {
defer func() {
if r := recover(); r != nil {
t.Errorf("panicked: %v", r)
}
}()
actor := streams.NewActivityStreamsActorProperty()
actor.AppendActivityStreamsApplication(streams.NewActivityStreamsApplication())
_, _ = GetResolvedActorFromActorProperty(actor)
})
}