Compare commits

...

21 Commits

Author SHA1 Message Date
Mike Wilkerson bb4f7c9d57 add missing @throws 2022-10-25 17:56:32 -07:00
Mike Wilkerson e61cf138a8 ignoreFile for phpcs 2022-10-25 17:55:53 -07:00
Mike Wilkerson 0e1e7feb92 auto-formatting 2022-10-25 17:54:26 -07:00
Mike Wilkerson 4169edddf9 test cleanup 2022-10-25 17:51:01 -07:00
Mike Wilkerson e5af8e0f41 more multisite test refactoring 2022-10-25 17:50:26 -07:00
Mike Wilkerson 15572f398b add additional assertion to multisite-activation test 2022-10-25 17:49:25 -07:00
Mike Wilkerson 0029e3cf34 fix multisite-upgrade test 2022-10-25 17:49:11 -07:00
Mike Wilkerson 7d26a84f8e WIP: multisite test refactoring 2022-10-25 17:22:09 -07:00
Mike Wilkerson 3861bc7e13 fix and test multisite uninstall 2022-10-25 17:07:46 -07:00
Mike Wilkerson 2e0568012a bump to verson 4.3.2-1 2022-10-25 16:49:05 -07:00
Mike Wilkerson 15e70274f7 include network option deletion in the cleanup utility plugin 2022-10-25 16:16:42 -07:00
Mike Wilkerson 6705c24f2e when delete_network_option when cleaning up ReleaseProvider 2022-10-25 16:16:25 -07:00
Mike Wilkerson 6cf8697add implement multisite upgrade for moving release metadata network option to main network 2022-10-25 11:05:43 -07:00
Mike Wilkerson 2ed559be7f add exception for multisite upgrade 2022-10-25 11:04:44 -07:00
Mike Wilkerson 8f4700ce7c test refactoring 2022-10-25 10:29:35 -07:00
Mike Wilkerson e637cac9d6 add failing tests for multisite upgrade 2022-10-25 10:25:31 -07:00
Mike Wilkerson c9ad87f3a9 code cleanup and auto-formatting 2022-10-24 17:59:26 -07:00
Mike Wilkerson f27c5c6922 Fix ReleaseProvider options storage in multisite to use main network 2022-10-24 17:55:16 -07:00
Mike Wilkerson d812349a57 complete a failing test for adding a network after activating this plugin 2022-10-24 17:52:42 -07:00
Mike Wilkerson 04471bfb49 WIP: working toward a test of adding a network after activating this plugin 2022-10-24 17:32:12 -07:00
Mike Wilkerson 12ce2cffbc add wp-multi-network-functions 2022-10-24 17:31:10 -07:00
15 changed files with 1470 additions and 18 deletions

View File

@ -1,12 +1,12 @@
{
"name": "font-awesome-admin",
"version": "4.3.1",
"version": "4.3.2-1",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "font-awesome-admin",
"version": "4.3.1",
"version": "4.3.2-1",
"dependencies": {
"@fortawesome/fa-icon-chooser-react": "0.4.1",
"@fortawesome/fontawesome-svg-core": "^6.2.0",

View File

@ -1,6 +1,6 @@
{
"name": "font-awesome-admin",
"version": "4.3.1",
"version": "4.3.2-1",
"private": true,
"dependencies": {
"@fortawesome/fa-icon-chooser-react": "0.4.1",

View File

@ -1,12 +1,12 @@
{
"name": "fa-compat-js",
"version": "4.3.1",
"version": "4.3.2-1",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "fa-compat-js",
"version": "4.3.1",
"version": "4.3.2-1",
"dependencies": {
"@wordpress/api-fetch": "^5.1.1",
"@wordpress/components": "14.1.10",

View File

@ -1,6 +1,6 @@
{
"name": "fa-compat-js",
"version": "4.3.1",
"version": "4.3.2-1",
"private": true,
"dependencies": {
"@wordpress/api-fetch": "^5.1.1",

View File

@ -46,11 +46,13 @@ class FontAwesome_Deactivator {
} else {
self::delete_options();
}
// This one handles its own multisite considerations.
FontAwesome_Release_Provider::delete_option();
}
private static function delete_options() {
delete_option( FontAwesome::OPTIONS_KEY );
FontAwesome_Release_Provider::delete_option();
delete_option( FontAwesome::CONFLICT_DETECTION_OPTIONS_KEY );
delete_option( FontAwesome_API_Settings::OPTIONS_KEY );
}

View File

@ -591,4 +591,19 @@ class UpgradeException extends FontAwesome_ServerException {
)
);
}
/**
* Internal use only.
*
* @internal
* @ignore
*/
public static function multisite_network_option_update() {
return new static(
esc_html__(
'Failed updating release metadata on a main network option when trying to upgrade the Font Awesome plugin in multisite mode.',
'font-awesome'
)
);
}
}

View File

@ -466,7 +466,7 @@ EOD;
*/
public static function update_option( $option_value ) {
if ( is_multisite() ) {
$network_id = get_current_network_id();
$network_id = get_main_network_id();
return update_network_option( $network_id, self::OPTIONS_KEY, $option_value );
} else {
return update_option( self::OPTIONS_KEY, $option_value, false );
@ -484,7 +484,7 @@ EOD;
*/
public static function get_option() {
if ( is_multisite() ) {
$network_id = get_current_network_id();
$network_id = get_main_network_id();
return get_network_option( $network_id, self::OPTIONS_KEY );
} else {
return get_option( self::OPTIONS_KEY );
@ -499,8 +499,22 @@ EOD;
*/
public static function delete_option() {
if ( is_multisite() ) {
$network_id = get_current_network_id();
return delete_network_option( $network_id, self::OPTIONS_KEY );
$result_accumulator = true;
/**
* Delete the network option for all networks.
* In 4.3.1, it's possible that this option could have been created in
* any network, which ever one was the current network at the time the plugin
* refreshed releases metadata.
*
* Starting in 4.3.2, we only store the releases metadata on an option associated with the main network.
*/
foreach ( get_networks() as $network ) {
$current_result = delete_network_option( $network->id, self::OPTIONS_KEY );
$result_accumulator = $result_accumulator && $current_result;
}
return $result_accumulator;
} else {
return delete_option( self::OPTIONS_KEY );
}

View File

@ -126,7 +126,7 @@ class FontAwesome {
*
* @since 4.0.0
*/
const PLUGIN_VERSION = '4.3.1';
const PLUGIN_VERSION = '4.3.2-1';
/**
* The namespace for this plugin's REST API.
*
@ -489,12 +489,28 @@ class FontAwesome {
$should_upgrade = true;
}
if ( is_multisite() && ! boolval( get_network_option( get_main_network_id(), FontAwesome_Release_Provider::OPTIONS_KEY ) ) ) {
/**
* Handle possible multisite upgrade from 4.3.1.
* In 4.3.1 the release metadata might have been stored in a network
* option associated with a non-main network. As of 4.3.2, it's
* always stored on a network option associated with the main network.
* So if we're in multisite mode and we don't find the release metadata
* on a network option associated with the main network, we need to fix it up.
*/
$should_upgrade = true;
}
if ( $should_upgrade ) {
$this->validate_options( $options );
$this->maybe_update_last_used_release_schema_for_upgrade();
$this->maybe_move_release_metadata_for_upgrade();
if ( is_multisite() ) {
$this->maybe_move_release_metadata_for_upgrade_multisite();
} else {
$this->maybe_move_release_metadata_for_upgrade_single_site();
}
/**
* Delete the main option to make sure it's removed entirely, including
@ -529,7 +545,7 @@ class FontAwesome {
* @ignore
* @internal
*/
private function maybe_move_release_metadata_for_upgrade() {
private function maybe_move_release_metadata_for_upgrade_single_site() {
if ( boolval( get_option( FontAwesome_Release_Provider::OPTIONS_KEY ) ) ) {
// If this option is set, then we're all caught up.
return;
@ -568,6 +584,69 @@ class FontAwesome {
FontAwesome_Release_Provider::reset();
}
/**
* If upgrading from 4.3.1 to 4.3.2 or beyond, and we don't have the release
* metadata stored on a network option associated with the main network,
* we need to find it on a non-main network and move it to main network.
*
* If we can't find it on a non-main network, either, then that's an
* exception. We intentionally will not query the API server, since
* issuing a blocking request on upgrade is known to cause load problems
* and request timeouts.
*
* Internal use only.
*
* @throws ReleaseMetadataMissingException
* @throws UpgradeException
* @ignore
* @internal
*/
private function maybe_move_release_metadata_for_upgrade_multisite() {
if ( ! is_multisite() ) {
return;
}
if ( boolval( get_network_option( get_main_network_id(), FontAwesome_Release_Provider::OPTIONS_KEY ) ) ) {
// If there's already release metadata on a network option for the main network, we're done.
return;
}
foreach ( get_networks() as $network ) {
$option_value = get_network_option( $network->id, FontAwesome_Release_Provider::OPTIONS_KEY );
if ( is_array( $option_value ) ) {
$result = update_network_option( get_main_network_id(), FontAwesome_Release_Provider::OPTIONS_KEY, $option_value );
if ( ! $result ) {
throw UpgradeException::multisite_network_option_update();
}
delete_network_option( $network->id, FontAwesome_Release_Provider::OPTIONS_KEY );
/**
* Return early, once we've found what we're looking for.
* While it's possible that there are additional non-main networks that also
* have options with release metadata, it's unlikely. Regardless,
* since this upgrade process happens on a normal front-end page load,
* we don't want to do any unnecessary processing here. The only reason
* to go searching through other network options would be to clean up
* any additional obsolete data. We'll leave that clean up to the plugin's
* uninstall logic.
*/
return;
}
}
/**
* Now we'll reset the release provider.
*
* If we've fallen through to this point, and we haven't found the release
* metadata stored in one of the previous locations, then this will throw an
* exception.
*/
FontAwesome_Release_Provider::reset();
}
/**
* With 4.1.0, the name of one of the keys in the LAST_USED_RELEASE_TRANSIENT changed.
* We can fix it up.

View File

@ -3,7 +3,7 @@
* Plugin Name: Font Awesome
* Plugin URI: https://fontawesome.com/how-to-use/on-the-web/using-with/wordpress
* Description: The official way to use Font Awesome Free or Pro icons on your site, brought to you by the Font Awesome team.
* Version: 4.3.1
* Version: 4.3.2-1
* Author: Font Awesome
* Author URI: https://fontawesome.com/
* License: GPLv2 (or later)

View File

@ -72,6 +72,10 @@ function cleanup() {
cleanup_site();
}
);
foreach ( get_options() as $option ) {
delete_network_option( get_current_network_id(), $option );
}
} else {
cleanup_site();
}
@ -204,6 +208,8 @@ function display_cleanup_scope_multisite() {
if ( $is_cleanup_network_active ) {
$network_id = get_current_network_id();
$networks = get_networks();
for_each_blog(
function( $site ) use (&$sites) {
array_push( $sites, $site );
@ -212,6 +218,10 @@ function display_cleanup_scope_multisite() {
?>
<p>Cleaning ALL sites in network with network_id: <?= $network_id ?>.</p>
<p>To clean up only one site, activate this cleanup plugin only on that one site instead of activating it network-wide.</p>
<?php if ( count( $networks ) > 0 ) { ?>
<p>There are <?php echo count( $networks ) - 1 ?> other networks that will not be affected by this cleanup.</p>
<p>To clean up multiple <em>networks</em>, network activate this cleanup plugin for each network, and run this cleanup for each network.</p>
<?php } ?>
<?php
} else {
array_push( $sites, get_site() );

View File

@ -131,3 +131,41 @@ function create_subsites($domains = ['alpha.example.com', 'beta.example.com']) {
return $results;
}
if ( is_multisite() ) :
require_once dirname( __FILE__ ) . '/wp-multi-network-functions.php';
function add_network() {
$sub_domain = dechex( wp_rand( PHP_INT_MIN, PHP_INT_MAX ) );
$domain = "$sub_domain.example.com";
$path = '/';
$admin_user = get_users( array( 'role' => 'administrator' ) )[0];
$result = \add_network(
array(
'domain' => $domain,
'path' => '/',
'site_name' => $domain,
'network_name' => $domain,
'user_id' => $admin_user->ID,
'network_admin_id' => $admin_user->ID,
)
);
if ( is_wp_error( $result ) ) {
throw new \Exception( 'failed creating network' );
}
return $result;
}
function curry_add_network_handler( &$network_ids ) {
return function ( $network_id, $params ) use ( &$network_ids ) {
if ( ! is_array( $network_ids ) ) {
return null;
}
array_push( $network_ids, $network_id );
};
}
endif;

File diff suppressed because it is too large Load Diff

View File

@ -11,8 +11,10 @@ use Yoast\WPTestUtils\WPIntegration\TestCase;
* Class MultisiteActivationTest
*/
class MultisiteActivationTest extends TestCase {
protected $sub_sites = array();
protected $original_blog_id = null;
protected $sub_sites = array();
protected $original_blog_id = null;
protected $original_network_id = null;
protected $added_network_ids = array();
public function set_up() {
parent::set_up();
@ -28,11 +30,13 @@ class MultisiteActivationTest extends TestCase {
throw new \Exception();
}
$this->original_blog_id = get_current_blog_id();
$this->original_blog_id = get_current_blog_id();
$this->original_network_id = get_current_network_id();
reset_db();
remove_all_actions( 'font_awesome_preferences' );
remove_all_filters( 'wp_is_large_network' );
add_action( 'add_network', curry_add_network_handler( $this->added_network_ids ), 99, 2 );
FontAwesome::reset();
( new Mock_FontAwesome_Metadata_Provider() )->mock(
array(
@ -64,8 +68,26 @@ class MultisiteActivationTest extends TestCase {
public function tear_down() {
parent::tear_down();
remove_all_actions( 'add_network' );
switch_to_blog( $this->original_blog_id );
// Delete all sites on the non-original network.
foreach ( $this->added_network_ids as $network_id ) {
\switch_to_network( $network_id );
$sites = get_sites(
array(
'network_id' => $network_id,
)
);
foreach ( $sites as $site ) {
wp_delete_site( $site->ID );
}
}
\switch_to_network( $this->original_network_id );
foreach ( $this->sub_sites as $blog_id ) {
wp_delete_site( $blog_id );
}
@ -246,4 +268,37 @@ class MultisiteActivationTest extends TestCase {
$this->assertEquals( $all_site_blog_ids, $visited_blog_ids );
}
public function test_add_network_after_activation() {
if ( ! $this->is_wp_version_compatible() ) {
$this->assertTrue( true );
return;
}
if ( ! is_network_admin() ) {
// Do nothing when we're not in network admin mode.
$this->assertTrue( true );
return;
}
$test_obj = $this;
// This activates network wide, for all sites that exist at the time.
FontAwesome_Activator::initialize();
// Now create a new network.
$new_network_id = add_network();
// Switch to it.
\switch_to_network( $new_network_id );
FontAwesome_Release_Provider::reset();
// This should not throw an exception, despite switching networks.
$ver = fa()->latest_version_6();
$this->assertEquals( $ver, '6.1.1' );
$expected_options = array_merge( FontAwesome::DEFAULT_USER_OPTIONS, array( 'version' => fa()->latest_version_6() ) );
$this->assertEquals( $expected_options, fa()->options() );
}
}

View File

@ -0,0 +1,106 @@
<?php
namespace FortAwesome;
/**
* Class OptionsTest
*
* @noinspection PhpCSValidationInspection
*/
// phpcs:ignoreFile Squiz.Commenting.ClassComment.Missing
// phpcs:ignoreFile Generic.Commenting.DocComment.MissingShort
require_once dirname( __FILE__ ) . '/../includes/class-fontawesome-deactivator.php';
require_once dirname( __FILE__ ) . '/_support/font-awesome-phpunit-util.php';
use Yoast\WPTestUtils\WPIntegration\TestCase;
class MultisiteDeactivationTest extends TestCase {
protected $added_network_ids = array();
public function set_up() {
parent::set_up();
wp_cache_delete ( 'alloptions', 'options' );
reset_db();
delete_option( FontAwesome::OPTIONS_KEY );
/**
* We need this to be defined for this test, though it's normally defined in
* the top-level loader file that is not being included in this test configuration.
*/
if ( ! defined( 'FONTAWESOME_PLUGIN_FILE' ) ) {
define( 'FONTAWESOME_PLUGIN_FILE', 'font-awesome/index.php' );
}
FontAwesome::reset();
(new Mock_FontAwesome_Metadata_Provider())->mock(
array(
wp_json_encode(
array(
'data' => graphql_releases_query_fixture(),
)
),
wp_json_encode(
array(
'data' => graphql_releases_query_fixture(),
)
)
)
);
// This activates network wide, for all sites that exist at the time.
FontAwesome_Activator::initialize();
add_action( 'add_network', curry_add_network_handler( $this->added_network_ids ), 99, 2 );
}
public function tear_down() {
FontAwesome_Metadata_Provider::reset();
remove_all_actions( 'add_network' );
}
public function test_uninstall_on_main_network() {
$this->run_multisite_uninstall_test( true );
}
public function test_uninstall_on_non_main_network() {
$this->run_multisite_uninstall_test( false );
}
public function run_multisite_uninstall_test( $run_on_main_network = true ) {
if ( ! is_multisite() ) {
throw new \Exception();
}
/**
* As of 4.3.2, the initialize() that will have run in the set_up() above will have put the release metadata
* in a network option associated with the main network.
* In 4.3.1, it would have been stored in a network option associated with the *current* network
* at the time of retrieval and storage.
*
* So to simulate the scenario that would have been possible in 4.3.1, we'll add it also to a non-main network.
*
* We want to ensure that any possible network option is cleaned up at the time of uninstall.
*/
// Create a new, non-main network.
$new_network_id = add_network();
$main_network_id = get_main_network_id();
// Get the metadata that would have been stored on a main network option.
$opt = get_network_option( $main_network_id, FontAwesome_Release_Provider::OPTIONS_KEY );
// Put it on an option associated with the new network.
update_network_option( $new_network_id, FontAwesome_Release_Provider::OPTIONS_KEY, $opt );
// Make sure they're both there.
$this->assertArrayHasKey( 'refreshed_at', get_network_option( $new_network_id, FontAwesome_Release_Provider::OPTIONS_KEY ) );
$this->assertArrayHasKey( 'refreshed_at', get_network_option( $main_network_id, FontAwesome_Release_Provider::OPTIONS_KEY ) );
if ( ! $run_on_main_network ) {
// Now switch to that new network.
\switch_to_network( $new_network_id );
}
FontAwesome_Deactivator::uninstall();
$this->assertFalse( get_network_option( $new_network_id, FontAwesome_Release_Provider::OPTIONS_KEY ) );
$this->assertFalse( get_network_option( $main_network_id, FontAwesome_Release_Provider::OPTIONS_KEY ) );
}
}

View File

@ -0,0 +1,115 @@
<?php
namespace FortAwesome;
/**
* Class OptionsTest
*
* @noinspection PhpCSValidationInspection
*/
// phpcs:ignoreFile Squiz.Commenting.ClassComment.Missing
// phpcs:ignoreFile Generic.Commenting.DocComment.MissingShort
require_once dirname( __FILE__ ) . '/../includes/class-fontawesome-activator.php';
require_once dirname( __FILE__ ) . '/_support/font-awesome-phpunit-util.php';
use Yoast\WPTestUtils\WPIntegration\TestCase;
class MultisiteUpgradeTest extends TestCase {
protected $added_network_ids = array();
public function set_up() {
parent::set_up();
wp_cache_delete ( 'alloptions', 'options' );
reset_db();
delete_option( FontAwesome::OPTIONS_KEY );
/**
* We need this to be defined for this test, though it's normally defined in
* the top-level loader file that is not being included in this test configuration.
*/
if ( ! defined( 'FONTAWESOME_PLUGIN_FILE' ) ) {
define( 'FONTAWESOME_PLUGIN_FILE', 'font-awesome/index.php' );
}
FontAwesome::reset();
(new Mock_FontAwesome_Metadata_Provider())->mock(
array(
wp_json_encode(
array(
'data' => graphql_releases_query_fixture(),
)
),
wp_json_encode(
array(
'data' => graphql_releases_query_fixture(),
)
)
)
);
FontAwesome_Release_Provider::load_releases();
add_action( 'add_network', curry_add_network_handler( $this->added_network_ids ), 99, 2 );
}
public function tear_down() {
FontAwesome_Metadata_Provider::reset();
remove_all_actions( 'add_network' );
}
public function test_try_upgrade_on_main_network_when_release_metatdata_stored_in_non_main_network() {
$this->run_multisite_upgrade_test( true );
}
public function test_try_upgrade_on_non_main_network_when_release_metatdata_stored_in_non_main_network() {
$this->run_multisite_upgrade_test( false );
}
public function run_multisite_upgrade_test($run_on_main_network = true) {
if ( ! is_multisite() ) {
throw new \Exception();
}
/**
* As of 4.3.2, the initialize() that will have run in the set_up() above will have put the release metadata
* in a network option associated with the main network.
* In 4.3.1, it would have been stored in a network option associated with the *current* network
* at the time of retrieval and storage.
*
* So to simulate the scenario that would have been possible in 4.3.1, we'll move it to a non-main network,
* such that the release metadata are stored on an option associated with the *current* network at the time
* of retrieval and storage.
*/
// Create a new, non-main network.
$new_network_id = add_network();
$main_network_id = get_main_network_id();
// Get the metadata that would have been stored on a main network option.
$opt = get_network_option( $main_network_id, FontAwesome_Release_Provider::OPTIONS_KEY );
// Put it on an option associated with the new network.
update_network_option( $new_network_id, FontAwesome_Release_Provider::OPTIONS_KEY, $opt );
// And get rid of the original one on the main network.
delete_network_option( $main_network_id, FontAwesome_Release_Provider::OPTIONS_KEY );
$this->assertFalse( get_network_option( $main_network_id, FontAwesome_Release_Provider::OPTIONS_KEY ) );
$this->assertArrayHasKey( 'refreshed_at', get_network_option( $new_network_id, FontAwesome_Release_Provider::OPTIONS_KEY ) );
// Clear options cache.
wp_cache_delete ( 'alloptions', 'options' );
if ( ! $run_on_main_network ) {
// Now switch to that new network.
\switch_to_network( $new_network_id );
}
// This activates network wide, for all sites that exist at the time on the current network.
$expected_options = array_merge( FontAwesome::DEFAULT_USER_OPTIONS, array( 'version' => fa()->latest_version_6() ) );
update_option( FontAwesome::OPTIONS_KEY, $expected_options );
// Expecting no exception to be thrown.
$this->assertNull( fa()->try_upgrade() );
$this->assertFalse( get_network_option( $new_network_id, FontAwesome_Release_Provider::OPTIONS_KEY ) );
$this->assertArrayHasKey( 'refreshed_at', get_network_option( $main_network_id, FontAwesome_Release_Provider::OPTIONS_KEY ) );
}
}