Update tests directory structure to follow plugin structure

This commit is contained in:
André Menrath 2024-12-20 18:39:20 +01:00
parent be0a10dc22
commit 51eb8e2b51
22 changed files with 419 additions and 515 deletions

View file

@ -48,20 +48,20 @@
],
"test": [
"@prepare-test",
"@test-vs-event-list",
"@test-the-events-calendar",
"@test-gatherpress",
"@test-events-manager",
"@test-wp-event-manager",
"@test-eventin",
"@test-modern-events-calendar-lite",
"@test-eventprime",
"@test-event-organiser",
"@test-event-bridge-for-activitypub-event-sources"
"@test-integration-vs-event-list",
"@test-integration-the-events-calendar",
"@test-integration-gatherpress",
"@test-integration- events-manager",
"@test-integration-wp-event-manager",
"@test-integration-eventin",
"@test-integration-modern-events-calendar-lite",
"@test-integration-eventprime",
"@test-integration-event-organiser",
"@test-event-sources"
],
"test-debug": [
"@prepare-test",
"@test-the-events-calendar"
"@test-event-sources"
],
"test-vs-event-list": "phpunit --filter=vs_event_list",
"test-the-events-calendar": "phpunit --filter=the_events_calendar",
@ -72,8 +72,8 @@
"test-modern-events-calendar-lite": "phpunit --filter=modern_events_calendar_lite",
"test-eventprime": "phpunit --filter=eventprime",
"test-event-organiser": "phpunit --filter=event_organiser",
"test-event-bridge-for-activitypub-shortcodes": "phpunit --filter=event_bridge_for_activitypub_shortcodes",
"test-event-bridge-for-activitypub-event-sources": "phpunit --filter=event_bridge_for_activitypub_event_sources",
"test-event-bridge-for-activitypub-shortcodes": "phpunit --filter=shortcodes",
"test-event-sources": "phpunit --filter=event_sources",
"test-all": "phpunit"
}
}

View file

@ -12,9 +12,7 @@ namespace Event_Bridge_For_ActivityPub\ActivityPub;
// Exit if accessed directly.
defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore
use DateTime;
use DateTimeZone;
use Event_Bridge_For_ActivityPub\ActivityPub\Collection\Event_Sources;
use Event_Bridge_For_ActivityPub\Event_Sources;
use Event_Bridge_For_ActivityPub\ActivityPub\Handler\Accept;
use Event_Bridge_For_ActivityPub\ActivityPub\Handler\Update;
use Event_Bridge_For_ActivityPub\ActivityPub\Handler\Create;
@ -34,92 +32,9 @@ class Handler {
Delete::init();
\add_filter(
'activitypub_validate_object',
array( self::class, 'validate_object' ),
array( Event_Sources::class, 'validate_event_object' ),
12,
3
);
}
/**
* Validate the object.
*
* @param bool $valid The validation state.
* @param string $param The object parameter.
* @param \WP_REST_Request $request The request object.
*
* @return bool The validation state: true if valid, false if not.
*/
public static function validate_object( $valid, $param, $request ) {
$json_params = $request->get_json_params();
if ( isset( $json_params['object']['type'] ) && 'Event' === $json_params['object']['type'] ) {
$valid = true;
} else {
return $valid;
}
if ( empty( $json_params['type'] ) ) {
return false;
}
if ( empty( $json_params['actor'] ) ) {
return false;
}
if ( ! in_array( $json_params['type'], array( 'Create', 'Update', 'Delete', 'Announce' ), true ) || is_wp_error( $request ) ) {
return $valid;
}
$object = $json_params['object'];
if ( ! is_array( $object ) ) {
return false;
}
$required = array(
'id',
'startTime',
'name',
);
if ( array_intersect( $required, array_keys( $object ) ) !== $required ) {
return false;
}
return $valid;
}
/**
* Check if a given DateTime is already passed.
*
* @param string $time_string The ActivityPub like time string.
* @return bool
*/
public static function is_time_passed( $time_string ) {
// Create a DateTime object from the ActivityPub time string.
$time = new DateTime( $time_string, new DateTimeZone( 'UTC' ) );
// Get the current time in UTC.
$current_time = new DateTime( 'now', new DateTimeZone( 'UTC' ) );
// Compare the event time with the current time.
return $time < $current_time;
}
/**
* Check that an ActivityPub actor is an event source (i.e. it is followed by the ActivityPub blog actor).
*
* @param string $actor_id The actor ID.
* @return bool True if the ActivityPub actor ID is followed, false otherwise.
*/
public static function actor_is_event_source( $actor_id ) {
$event_sources = Event_Sources::get_event_sources();
foreach ( $event_sources as $event_source ) {
if ( $actor_id === $event_source->get_id() ) {
return true;
}
}
return false;
}
}

View file

@ -236,7 +236,7 @@ class Event_Sources {
/**
* Get all Event-Sources.
*
* @return array The Term list of Event Sources.
* @return Event_Source[] A List of all Event Sources (follows).
*/
public static function get_event_sources() {
return self::get_event_sources_with_count()['actors'];

View file

@ -8,8 +8,8 @@
namespace Event_Bridge_For_ActivityPub\ActivityPub\Handler;
use Activitypub\Collection\Actors;
use Event_Bridge_For_ActivityPub\Event_Sources;
use Event_Bridge_For_ActivityPub\Setup;
use Event_Bridge_For_ActivityPub\ActivityPub\Handler;
use function Activitypub\is_activity_public;
@ -36,12 +36,12 @@ class Create {
* @param int $user_id The id of the local blog-user.
*/
public static function handle_create( $activity, $user_id ) {
// We only process activities that are target to the application user.
// We only process activities that are target to the blog actor.
if ( Actors::BLOG_USER_ID !== $user_id ) {
return;
}
if ( ! Handler::actor_is_event_source( $activity['actor'] ) ) {
if ( ! Event_Sources::actor_is_event_source( $activity['actor'] ) ) {
return;
}
@ -55,8 +55,12 @@ class Create {
return;
}
if ( Handler::is_time_passed( $activity['object']['startTime'] ) ) {
return;
if ( Event_Sources::is_time_passed( $activity['object']['startTime'] ) ) {
return new \WP_Error(
'event_bridge_for_activitypub_not_accepting_events_from_the_past',
__( 'We do not accept this event because it took place in the past.', 'event-bridge-for-activitypub' ),
array( 'status' => 403 )
);
}
$transmogrifier = Setup::get_transmogrifier();

View file

@ -8,8 +8,8 @@
namespace Event_Bridge_For_ActivityPub\ActivityPub\Handler;
use Activitypub\Collection\Actors;
use Event_Bridge_For_ActivityPub\Event_Sources;
use Event_Bridge_For_ActivityPub\Setup;
use Event_Bridge_For_ActivityPub\ActivityPub\Handler;
/**
* Handle Delete requests.
@ -39,7 +39,7 @@ class Delete {
return;
}
if ( ! Handler::actor_is_event_source( $activity['actor'] ) ) {
if ( ! Event_Sources::actor_is_event_source( $activity['actor'] ) ) {
return;
}
@ -48,10 +48,6 @@ class Delete {
return;
}
if ( Handler::is_time_passed( $activity['object']['startTime'] ) ) {
return;
}
$transmogrifier = Setup::get_transmogrifier();
if ( ! $transmogrifier ) {

View file

@ -8,8 +8,8 @@
namespace Event_Bridge_For_ActivityPub\ActivityPub\Handler;
use Activitypub\Collection\Actors;
use Event_Bridge_For_ActivityPub\Event_Sources;
use Event_Bridge_For_ActivityPub\Setup;
use Event_Bridge_For_ActivityPub\ActivityPub\Handler;
use function Activitypub\is_activity_public;
@ -41,7 +41,7 @@ class Update {
return;
}
if ( ! Handler::actor_is_event_source( $activity['actor'] ) ) {
if ( ! Event_Sources::actor_is_event_source( $activity['actor'] ) ) {
return;
}
@ -55,7 +55,7 @@ class Update {
return;
}
if ( Handler::is_time_passed( $activity['object']['startTime'] ) ) {
if ( Event_Sources::is_time_passed( $activity['object']['startTime'] ) ) {
return;
}

View file

@ -74,30 +74,6 @@ abstract class Base {
);
}
/**
* Validate a time string if it is according to the ActivityPub specification.
*
* @param string $time_string The time string.
* @return bool
*/
public static function is_valid_activitypub_time_string( $time_string ) {
// Try to create a DateTime object from the input string.
try {
$date = new DateTime( $time_string );
} catch ( Exception $e ) {
// If parsing fails, it's not valid.
return false;
}
// Ensure the timezone is correctly formatted (e.g., 'Z' or a valid offset).
$timezone = $date->getTimezone();
$formatted_timezone = $timezone->getName();
// Return true only if the time string includes 'Z' or a valid timezone offset.
$valid = 'Z' === $formatted_timezone || preg_match( '/^[+-]\d{2}:\d{2}$/ ', $formatted_timezone );
return $valid;
}
/**
* Get the image URL and alt-text of an ActivityPub object.
*

View file

@ -10,11 +10,14 @@
namespace Event_Bridge_For_ActivityPub;
use Activitypub\Model\Blog;
use DateTime;
use DateTimeZone;
use Event_Bridge_For_ActivityPub\ActivityPub\Collection\Event_Sources as Event_Sources_Collection;
use Event_Bridge_For_ActivityPub\ActivityPub\Handler;
use Event_Bridge_For_ActivityPub\Admin\User_Interface;
use Event_Bridge_For_ActivityPub\Integrations\Event_Plugin_Integration;
use Event_Bridge_For_ActivityPub\Integrations\Feature_Event_Sources;
use Exception;
use function Activitypub\get_remote_metadata_by_actor;
use function Activitypub\is_activitypub_request;
@ -244,7 +247,7 @@ class Event_Sources {
/**
* Get an array will all unique hosts of all Event-Sources.
*
* @return array The Term list of Event Sources.
* @return array A list with all unique hosts of all Event Sources' ActivityPub IDs.
*/
public static function get_event_sources_hosts() {
$hosts = get_transient( 'event_bridge_for_activitypub_event_sources_hosts' );
@ -253,7 +256,7 @@ class Event_Sources {
return $hosts;
}
$actors = Event_Sources_Collection::get_event_sources_with_count()['actors'];
$actors = Event_Sources_Collection::get_event_sources();
$hosts = array();
foreach ( $actors as $actor ) {
@ -273,7 +276,7 @@ class Event_Sources {
/**
* Get add Event Sources ActivityPub IDs.
*
* @return array The Term list of Event Sources.
* @return array A list with the ActivityPub IDs of all Event Sources (follows).
*/
public static function get_event_sources_ids() {
$ids = get_transient( 'event_bridge_for_activitypub_event_sources_ids' );
@ -282,7 +285,7 @@ class Event_Sources {
return $ids;
}
$actors = Event_Sources_Collection::get_event_sources_with_count()['actors'];
$actors = Event_Sources_Collection::get_event_sources();
$ids = array();
foreach ( $actors as $actor ) {
@ -304,4 +307,115 @@ class Event_Sources {
$event_sources_hosts = self::get_event_sources_hosts();
return array_merge( $hosts, $event_sources_hosts );
}
/**
* Validate the event object.
*
* @param bool $valid The validation state.
* @param string $param The object parameter.
* @param \WP_REST_Request $request The request object.
*
* @return bool|WP_Error The validation state: true if valid, false if not.
*/
public static function validate_event_object( $valid, $param, $request ) {
$json_params = $request->get_json_params();
if ( isset( $json_params['object']['type'] ) && 'Event' === $json_params['object']['type'] ) {
$valid = true;
} else {
return $valid;
}
if ( empty( $json_params['type'] ) ) {
return false;
}
if ( empty( $json_params['actor'] ) ) {
return false;
}
if ( ! in_array( $json_params['type'], array( 'Create', 'Update', 'Delete', 'Announce' ), true ) || is_wp_error( $request ) ) {
return $valid;
}
$object = $json_params['object'];
if ( ! is_array( $object ) ) {
return false;
}
$required = array(
'id',
'startTime',
'name',
);
if ( array_intersect( $required, array_keys( $object ) ) !== $required ) {
return false;
}
if ( ! self::is_valid_activitypub_time_string( $object['startTime'] ) ) {
return false;
}
return $valid;
}
/**
* Validate a time string if it is according to the ActivityPub specification.
*
* @param string $time_string The time string.
* @return bool
*/
public static function is_valid_activitypub_time_string( $time_string ) {
// Try to create a DateTime object from the input string.
try {
$date = new DateTime( $time_string );
} catch ( Exception $e ) {
// If parsing fails, it's not valid.
return false;
}
// Ensure the timezone is correctly formatted (e.g., 'Z' or a valid offset).
$timezone = $date->getTimezone();
$formatted_timezone = $timezone->getName();
// Return true only if the time string includes 'Z' or a valid timezone offset.
$valid = 'Z' === $formatted_timezone || preg_match( '/^[+-]\d{2}:\d{2}$/ ', $formatted_timezone );
return $valid;
}
/**
* Check if a given DateTime is already passed.
*
* @param string $time_string The ActivityPub like time string.
* @return bool
*/
public static function is_time_passed( $time_string ) {
// Create a DateTime object from the ActivityPub time string.
$time = new DateTime( $time_string, new DateTimeZone( 'UTC' ) );
// Get the current time in UTC.
$current_time = new DateTime( 'now', new DateTimeZone( 'UTC' ) );
// Compare the event time with the current time.
return $time < $current_time;
}
/**
* Check that an ActivityPub actor is an event source (i.e. it is followed by the ActivityPub blog actor).
*
* @param string $actor_id The actor ID.
* @return bool True if the ActivityPub actor ID is followed, false otherwise.
*/
public static function actor_is_event_source( $actor_id ) {
$event_sources = Event_Sources_Collection::get_event_sources();
foreach ( $event_sources as $event_source ) {
if ( $actor_id === $event_source->get_id() ) {
return true;
}
}
return false;
}
}

View file

@ -9,7 +9,7 @@
>
<testsuites>
<testsuite name="testing">
<directory prefix="test-" suffix=".php">./tests/</directory>
<directory prefix="class-test-" suffix=".php">./tests/</directory>
</testsuite>
</testsuites>
</phpunit>

View file

@ -5,6 +5,11 @@
* @package Event_Bridge_For_ActivityPub
*/
// Defined here because setting them in .wp-env.json doesn't work for some reason.
\define( 'WP_TESTS_DOMAIN', 'example.org' );
\define( 'WP_SITEURL', 'http://example.org' );
\define( 'WP_HOME', 'http://example.org' );
$_tests_dir = getenv( 'WP_TESTS_DIR' );
if ( ! $_tests_dir ) {
@ -96,9 +101,12 @@ function _manually_load_plugin() {
if ( $plugin_file ) {
_manually_load_event_plugin( $plugin_file );
} elseif ( 'event_bridge_for_activitypub_event_sources' === $event_bridge_for_activitypub_integration_filter ) {
} elseif ( 'event_sources' === $event_bridge_for_activitypub_integration_filter ) {
// For the Event Sources feature we currently only test with GatherPress.
_manually_load_event_plugin( 'gatherpress/gatherpress.php' );
\update_option( 'event_bridge_for_activitypub_event_sources_active', true );
\update_option( 'event_bridge_for_activitypub_plugin_used_for_event_source_feature', 'GatherPress' );
\update_option( 'activitypub_actor_mode', ACTIVITYPUB_BLOG_MODE );
} else {
// For all other tests we mainly use the Events Calendar as a reference.
_manually_load_event_plugin( 'the-events-calendar/the-events-calendar.php' );
@ -121,6 +129,9 @@ function _manually_load_plugin() {
// At last manually load our WordPress plugin.
require dirname( __DIR__ ) . '/event-bridge-for-activitypub.php';
// Always manually load the ActivityPub plugin.
require_once $plugin_dir . 'activitypub/activitypub.php';
}
tests_add_filter( 'muplugins_loaded', '_manually_load_plugin' );

View file

@ -5,10 +5,14 @@
* @package Event_Bridge_For_ActivityPub
*/
namespace Event_Bridge_For_ActivityPub\Tests\ActivityPub\Transformer;
use DateTime;
/**
* Sample test case.
*/
class Test_Event_Organiser extends WP_UnitTestCase {
class Test_Event_Organiser extends \WP_UnitTestCase {
/**
* Override the setup function, so that tests don't run if the Events Calendar is not active.
*/

View file

@ -6,14 +6,12 @@
* @license AGPL-3.0-or-later
*/
use Activitypub\Shortcodes;
namespace Event_Bridge_For_ActivityPup\Tests\ActivityPub\Transformer;
/**
* Test class for Activitypub Shortcodes.
*
* @coversDefaultClass \Activitypub\Shortcodes
* Test class for Shortcodes.
*/
class Test_Activitypub_Event_Bridge_Shortcodes extends WP_UnitTestCase {
class Test_Event extends \WP_UnitTestCase {
/**
* Override the setup function, so that tests don't run if the Events Calendar is not active.
*/

View file

@ -5,10 +5,12 @@
* @package Event_Bridge_For_ActivityPub
*/
namespace Event_Bridge_For_ActivityPub\Tests\ActivityPub\Transformer;
/**
* Test cases for WP Event Solution.
*/
class Test_Eventin extends WP_UnitTestCase {
class Test_Eventin extends \WP_UnitTestCase {
/**
* Basic Mock-up event.
*/

View file

@ -5,10 +5,12 @@
* @package Event_Bridge_For_ActivityPub
*/
namespace Event_Bridge_For_ActivityPub\Tests\ActivityPub\Transformer;
/**
* Sample test case.
*/
class Test_EventPrime extends WP_UnitTestCase {
class Test_EventPrime extends \WP_UnitTestCase {
/**
* Mockup venues of certain complexity.
*

View file

@ -5,10 +5,12 @@
* @package Event_Bridge_For_ActivityPub
*/
namespace Event_Bridge_For_ActivityPub\Tests\ActivityPub\Transformer;
/**
* Sample test case.
*/
class Test_Events_Manager extends WP_UnitTestCase {
class Test_Events_Manager extends \WP_UnitTestCase {
/**
* Override the setup function, so that tests don't run if the Events Calendar is not active.
*/

View file

@ -5,10 +5,12 @@
* @package Event_Bridge_For_ActivityPub
*/
namespace Event_Bridge_For_ActivityPub\Tests\ActivityPub\Transformer;
/**
* Sample test case.
*/
class Test_GatherPress extends WP_UnitTestCase {
class Test_GatherPress extends \WP_UnitTestCase {
/**
* Override the setup function, so that tests don't run if the Events Calendar is not active.
*/

View file

@ -5,10 +5,12 @@
* @package Event_Bridge_For_ActivityPub
*/
namespace Event_Bridge_For_ActivityPub\Tests\ActivityPub\Transformer;
/**
* Sample test case.
*/
class Test_Modern_Events_Calendar_Lite extends WP_UnitTestCase {
class Test_Modern_Events_Calendar_Lite extends \WP_UnitTestCase {
/**
* The MEC main instance.
*

View file

@ -5,10 +5,12 @@
* @package Event_Bridge_For_ActivityPub
*/
namespace Event_Bridge_For_ActivityPub\Tests\ActivityPub\Transformer;
/**
* Sample test case.
*/
class Test_VS_Event_List extends WP_UnitTestCase {
class Test_VS_Event_List extends \WP_UnitTestCase {
/**
* Override the setup function, so that tests don't run if the Events Calendar is not active.
*/

View file

@ -5,10 +5,12 @@
* @package Event_Bridge_For_ActivityPub
*/
namespace Event_Bridge_For_ActivityPub\Tests\ActivityPub\Transformer;
/**
* Sample test case.
*/
class Test_The_Events_Calendar extends WP_UnitTestCase {
class Test_The_Events_Calendar extends \WP_UnitTestCase {
/**
* Mockup events of certain complexity.
*/

View file

@ -5,10 +5,12 @@
* @package Event_Bridge_For_ActivityPub
*/
namespace Event_Bridge_For_ActivityPub\Tests\ActivityPub\Transformer;
/**
* Sample test case.
*/
class Test_WP_Event_Manager extends WP_UnitTestCase {
class Test_WP_Event_Manager extends \WP_UnitTestCase {
/**
* Override the setup function, so that tests don't run if the Events Calendar is not active.
*/

View file

@ -0,0 +1,226 @@
<?php
/**
* Test file for the Event Sources feature.
*
* @package Event_Bridge_For_ActivityPub
* @since 1.0.0
* @license AGPL-3.0-or-later
*/
namespace Event_Bridge_For_ActivityPub\Tests;
use WP_REST_Request;
use WP_REST_Server;
/**
* Test class for Activitypub Rest Inbox.
*
* @coversDefaultClass \Event_Bridge_For_ActivityPub\Event_Sources
*/
class Test_Event_Sources extends \WP_UnitTestCase {
const FOLLOWED_ACTOR = array(
'id' => 'https://remote.example/@organizer',
'type' => 'Person',
'inbox' => 'https://remote.example/@organizer/inbox',
'outbox' => 'https://remote.example/@organizer/outbox',
'name' => 'The Organizer',
'summary' => 'Just a random organizer of events in the Fediverse',
);
/**
* Post ID.
*
* @var int
*/
protected static $event_source_post_id;
/**
* REST Server.
*
* @var WP_REST_Server
*/
protected $server;
/**
* Create fake data before tests run.
*
* @param WP_UnitTest_Factory $factory Helper that creates fake data.
*/
public static function wpSetUpBeforeClass( $factory ) {
// Follow actor.
$event_source = new \Event_Bridge_For_ActivityPub\ActivityPub\Model\Event_Source();
$event_source->from_array( self::FOLLOWED_ACTOR );
$post_id = $event_source->save();
self::$event_source_post_id = $post_id;
}
/**
* Set up the test.
*/
public function set_up() {
\add_option( 'permalink_structure', '/%postname%/' );
global $wp_rest_server;
$wp_rest_server = new WP_REST_Server();
$this->server = $wp_rest_server;
do_action( 'rest_api_init' );
\Activitypub\Rest\Server::add_hooks();
}
/**
* Tear down the test.
*/
public function tear_down() {
\delete_option( 'permalink_structure' );
\add_filter( 'activitypub_defer_signature_verification', '__return_false' );
}
/**
* Test receiving event from followed actor.
*/
public function test_incoming_event() {
\add_filter( 'activitypub_defer_signature_verification', '__return_true' );
$json = array(
'id' => 'https://remote.example/@organizer/events/new-year-party#create',
'type' => 'Create',
'actor' => 'https://remote.example/@organizer',
'object' => array(
'id' => 'https://remote.example/@organizer/events/new-year-party',
'type' => 'Event',
'startTime' => \gmdate( 'Y-m-d\TH:i:s\Z', time() + WEEK_IN_SECONDS ),
'name' => 'New Years Party 50/51',
'to' => 'https://www.w3.org/ns/activitystreams#Public',
'published' => '2020-01-01T00:00:00Z',
),
);
$request = new WP_REST_Request( 'POST', '/activitypub/1.0/users/0/inbox' );
$request->set_header( 'Content-Type', 'application/activity+json' );
$request->set_body( \wp_json_encode( $json ) );
// Dispatch the request.
$response = \rest_do_request( $request );
$this->assertEquals( 202, $response->get_status() );
}
/**
* Test receiving event from followed actor with missing start time.
*/
public function test_incoming_create_with_missing_start_time() {
\add_filter( 'activitypub_defer_signature_verification', '__return_true' );
$json = array(
'id' => 'https://remote.example/@organizer/events/new-year-party#create',
'type' => 'Create',
'actor' => 'https://remote.example/@organizer',
'object' => array(
'id' => 'https://remote.example/@organizer/events/new-year-party',
'type' => 'Event',
'name' => 'New Years Party 50/51',
'to' => 'https://www.w3.org/ns/activitystreams#Public',
'published' => '2020-01-01T00:00:00Z',
),
);
$request = new WP_REST_Request( 'POST', '/activitypub/1.0/users/0/inbox' );
$request->set_header( 'Content-Type', 'application/activity+json' );
$request->set_body( \wp_json_encode( $json ) );
// Dispatch the request.
$response = \rest_do_request( $request );
$this->assertEquals( 400, $response->get_status() );
}
/**
* Test receiving event from followed actor with wrongly formatted start time.
*/
public function test_incoming_event_with_faulty_start_time() {
\add_filter( 'activitypub_defer_signature_verification', '__return_true' );
$json = array(
'id' => 'https://remote.example/@organizer/events/new-year-party#create',
'type' => 'Create',
'actor' => 'https://remote.example/@organizer',
'object' => array(
'id' => 'https://remote.example/@organizer/events/new-year-party',
'type' => 'Event',
'name' => 'New Years Party 50/51',
'startTime' => \gmdate( 'Y-m-d\TH:i:s\Z', time() + WEEK_IN_SECONDS ),
'to' => 'https://www.w3.org/ns/activitystreams#Public',
'published' => '2020-01-01T00:00:00Z',
),
);
$request = new WP_REST_Request( 'POST', '/activitypub/1.0/users/0/inbox' );
$request->set_header( 'Content-Type', 'application/activity+json' );
$request->set_body( \wp_json_encode( $json ) );
// Dispatch the request.
$response = \rest_do_request( $request );
$this->assertEquals( 401, $response->get_status() );
}
/**
* We do understand, but do not care about incoming events that happened in the past.
*/
public function test_incoming_event_which_took_place_in_the_past() {
\add_filter( 'activitypub_defer_signature_verification', '__return_true' );
$json = array(
'id' => 'https://remote.example/@organizer/events/new-year-party#create',
'type' => 'Create',
'actor' => 'https://remote.example/@organizer',
'object' => array(
'id' => 'https://remote.example/@organizer/events/new-year-party',
'type' => 'Event',
'name' => 'New Years Party 50/51',
'startTime' => \gmdate( 'Y-m-d\TH:i:s\Z', time() - WEEK_IN_SECONDS ),
'to' => 'https://www.w3.org/ns/activitystreams#Public',
'published' => '2020-01-01T00:00:00Z',
),
);
$request = new WP_REST_Request( 'POST', '/activitypub/1.0/users/0/inbox' );
$request->set_header( 'Content-Type', 'application/activity+json' );
$request->set_body( \wp_json_encode( $json ) );
// Dispatch the request.
$response = \rest_do_request( $request );
// This should be 403 but it is not possible without lots of hacks at the moment.
$this->assertEquals( 401, $response->get_status() );
}
/**
* Test receiving event from actor we do not follow.
*/
public function test_incoming_create_from_non_followed_actor() {
\add_filter( 'activitypub_defer_signature_verification', '__return_true' );
$json = array(
'id' => 'https://remote.example/@another_organizer/events/new-year-party#create',
'type' => 'Create',
'actor' => 'https://remote.example/@another_organizer',
'object' => array(
'id' => 'https://remote.example/@another_organizer/events/new-year-party',
'type' => 'Event',
'startTime' => '2050-12-31T18:00:00Z',
'name' => 'New Years Party 50/51',
'to' => 'https://www.w3.org/ns/activitystreams#Public',
'published' => '2020-01-01T00:00:00Z',
),
);
$request = new WP_REST_Request( 'POST', '/activitypub/1.0/users/0/inbox' );
$request->set_header( 'Content-Type', 'application/activity+json' );
$request->set_body( \wp_json_encode( $json ) );
// Dispatch the request.
$response = \rest_do_request( $request );
$this->assertEquals( 401, $response->get_status() );
}
}

View file

@ -1,356 +0,0 @@
<?php
/**
* Test file for the Event Sources feature.
*
* @package Event_Bridge_For_ActivityPub
* @since 1.0.0
* @license AGPL-3.0-or-later
*/
/**
* Test class for Activitypub Rest Inbox.
*
* @coversDefaultClass \Activitypub\Rest\Inbox
*/
class Test_Event_Bridge_For_ActivityPub_Event_Sources extends WP_UnitTestCase {
/**
* Set up the test.
*/
public function set_up() {
\add_option( 'permalink_structure', '/%postname%/' );
\Activitypub\Rest\Server::add_hooks();
}
/**
* Tear down the test.
*/
public function tear_down() {
\delete_option( 'permalink_structure' );
\add_filter( 'activitypub_defer_signature_verification', '__return_false' );
}
/**
* Test the inbox signature issue.
*/
public function test_inbox_signature_issue() {
\add_filter( 'activitypub_defer_signature_verification', '__return_false' );
$json = array(
'id' => 'https://remote.example/@id',
'type' => 'Follow',
'actor' => 'https://remote.example/@test',
'object' => 'https://local.example/@test',
);
$request = new \WP_REST_Request( 'POST', '/activitypub/1.0/users/1/inbox' );
$request->set_header( 'Content-Type', 'application/activity+json' );
$request->set_body( \wp_json_encode( $json ) );
$response = \rest_do_request( $request );
$this->assertEquals( 401, $response->get_status() );
$this->assertEquals( 'activitypub_signature_verification', $response->get_data()['code'] );
}
/**
* Test missing attribute.
*/
public function test_missing_attribute() {
\add_filter( 'activitypub_defer_signature_verification', '__return_true' );
$json = array(
'id' => 'https://remote.example/@id',
'type' => 'Follow',
'actor' => 'https://remote.example/@test',
);
$request = new \WP_REST_Request( 'POST', '/activitypub/1.0/users/1/inbox' );
$request->set_header( 'Content-Type', 'application/activity+json' );
$request->set_body( \wp_json_encode( $json ) );
$response = \rest_do_request( $request );
$this->assertEquals( 400, $response->get_status() );
$this->assertEquals( 'rest_missing_callback_param', $response->get_data()['code'] );
$this->assertEquals( 'object', $response->get_data()['data']['params'][0] );
}
/**
* Test follow request.
*/
public function test_follow_request() {
\add_filter( 'activitypub_defer_signature_verification', '__return_true' );
$json = array(
'id' => 'https://remote.example/@id',
'type' => 'Follow',
'actor' => 'https://remote.example/@test',
'object' => 'https://local.example/@test',
);
$request = new \WP_REST_Request( 'POST', '/activitypub/1.0/users/1/inbox' );
$request->set_header( 'Content-Type', 'application/activity+json' );
$request->set_body( \wp_json_encode( $json ) );
// Dispatch the request.
$response = \rest_do_request( $request );
$this->assertEquals( 202, $response->get_status() );
}
/**
* Test follow request global inbox.
*/
public function test_follow_request_global_inbox() {
\add_filter( 'activitypub_defer_signature_verification', '__return_true' );
$json = array(
'id' => 'https://remote.example/@id',
'type' => 'Follow',
'actor' => 'https://remote.example/@test',
'object' => 'https://local.example/@test',
);
$request = new \WP_REST_Request( 'POST', '/activitypub/1.0/inbox' );
$request->set_header( 'Content-Type', 'application/activity+json' );
$request->set_body( \wp_json_encode( $json ) );
// Dispatch the request.
$response = \rest_do_request( $request );
$this->assertEquals( 202, $response->get_status() );
}
/**
* Test create request with a remote actor.
*/
public function test_create_request() {
\add_filter( 'activitypub_defer_signature_verification', '__return_true' );
// Invalid request, because of an invalid object.
$json = array(
'id' => 'https://remote.example/@id',
'type' => 'Create',
'actor' => 'https://remote.example/@test',
'object' => 'https://local.example/@test',
);
$request = new \WP_REST_Request( 'POST', '/activitypub/1.0/users/1/inbox' );
$request->set_header( 'Content-Type', 'application/activity+json' );
$request->set_body( \wp_json_encode( $json ) );
// Dispatch the request.
$response = \rest_do_request( $request );
$this->assertEquals( 400, $response->get_status() );
$this->assertEquals( 'rest_invalid_param', $response->get_data()['code'] );
// Valid request, because of a valid object.
$json['object'] = array(
'id' => 'https://remote.example/post/test',
'type' => 'Note',
'content' => 'Hello, World!',
'inReplyTo' => 'https://local.example/post/test',
'published' => '2020-01-01T00:00:00Z',
);
$request = new \WP_REST_Request( 'POST', '/activitypub/1.0/users/1/inbox' );
$request->set_header( 'Content-Type', 'application/activity+json' );
$request->set_body( \wp_json_encode( $json ) );
// Dispatch the request.
$response = \rest_do_request( $request );
$this->assertEquals( 202, $response->get_status() );
}
/**
* Test create request global inbox.
*/
public function test_create_request_global_inbox() {
\add_filter( 'activitypub_defer_signature_verification', '__return_true' );
// Invalid request, because of an invalid object.
$json = array(
'id' => 'https://remote.example/@id',
'type' => 'Create',
'actor' => 'https://remote.example/@test',
'object' => 'https://local.example/@test',
);
$request = new \WP_REST_Request( 'POST', '/activitypub/1.0/inbox' );
$request->set_header( 'Content-Type', 'application/activity+json' );
$request->set_body( \wp_json_encode( $json ) );
// Dispatch the request.
$response = \rest_do_request( $request );
$this->assertEquals( 400, $response->get_status() );
$this->assertEquals( 'rest_invalid_param', $response->get_data()['code'] );
// Valid request, because of a valid object.
$json['object'] = array(
'id' => 'https://remote.example/post/test',
'type' => 'Note',
'content' => 'Hello, World!',
'inReplyTo' => 'https://local.example/post/test',
'published' => '2020-01-01T00:00:00Z',
);
$request = new \WP_REST_Request( 'POST', '/activitypub/1.0/inbox' );
$request->set_header( 'Content-Type', 'application/activity+json' );
$request->set_body( \wp_json_encode( $json ) );
// Dispatch the request.
$response = \rest_do_request( $request );
$this->assertEquals( 202, $response->get_status() );
}
/**
* Test update request.
*/
public function test_update_request() {
\add_filter( 'activitypub_defer_signature_verification', '__return_true' );
$json = array(
'id' => 'https://remote.example/@id',
'type' => 'Update',
'actor' => 'https://remote.example/@test',
'object' => array(
'id' => 'https://remote.example/post/test',
'type' => 'Note',
'content' => 'Hello, World!',
'inReplyTo' => 'https://local.example/post/test',
'published' => '2020-01-01T00:00:00Z',
),
);
$request = new \WP_REST_Request( 'POST', '/activitypub/1.0/users/1/inbox' );
$request->set_header( 'Content-Type', 'application/activity+json' );
$request->set_body( \wp_json_encode( $json ) );
// Dispatch the request.
$response = \rest_do_request( $request );
$this->assertEquals( 202, $response->get_status() );
}
/**
* Test like request.
*/
public function test_like_request() {
\add_filter( 'activitypub_defer_signature_verification', '__return_true' );
$json = array(
'id' => 'https://remote.example/@id',
'type' => 'Like',
'actor' => 'https://remote.example/@test',
'object' => 'https://local.example/post/test',
);
$request = new \WP_REST_Request( 'POST', '/activitypub/1.0/users/1/inbox' );
$request->set_header( 'Content-Type', 'application/activity+json' );
$request->set_body( \wp_json_encode( $json ) );
// Dispatch the request.
$response = \rest_do_request( $request );
$this->assertEquals( 202, $response->get_status() );
}
/**
* Test announce request.
*/
public function test_announce_request() {
\add_filter( 'activitypub_defer_signature_verification', '__return_true' );
$json = array(
'id' => 'https://remote.example/@id',
'type' => 'Announce',
'actor' => 'https://remote.example/@test',
'object' => 'https://local.example/post/test',
);
$request = new \WP_REST_Request( 'POST', '/activitypub/1.0/users/1/inbox' );
$request->set_header( 'Content-Type', 'application/activity+json' );
$request->set_body( \wp_json_encode( $json ) );
// Dispatch the request.
$response = \rest_do_request( $request );
$this->assertEquals( 202, $response->get_status() );
}
/**
* Test whether an activity is public.
*
* @dataProvider the_data_provider
*
* @param array $data The data.
* @param bool $check The check.
*/
public function test_is_activity_public( $data, $check ) {
$this->assertEquals( $check, Activitypub\is_activity_public( $data ) );
}
/**
* Data provider.
*
* @return array[]
*/
public function the_data_provider() {
return array(
array(
array(
'cc' => array(
'https://example.org/@test',
'https://example.com/@test2',
),
'to' => 'https://www.w3.org/ns/activitystreams#Public',
'object' => array(),
),
true,
),
array(
array(
'cc' => array(
'https://example.org/@test',
'https://example.com/@test2',
),
'to' => array(
'https://www.w3.org/ns/activitystreams#Public',
),
'object' => array(),
),
true,
),
array(
array(
'cc' => array(
'https://example.org/@test',
'https://example.com/@test2',
),
'object' => array(),
),
false,
),
array(
array(
'cc' => array(
'https://example.org/@test',
'https://example.com/@test2',
),
'object' => array(
'to' => 'https://www.w3.org/ns/activitystreams#Public',
),
),
true,
),
array(
array(
'cc' => array(
'https://example.org/@test',
'https://example.com/@test2',
),
'object' => array(
'to' => array(
'https://www.w3.org/ns/activitystreams#Public',
),
),
),
true,
),
);
}
}