Move remote logger to `./src` and enhance `fetch_latest_woocommerce_version()` logic (#49639)

* Move remote logger to ./src

* Change fetch_latest_woocommerce_version transient expiration to a week

* Add changelog

* Add retry timeout to prevent repeated attempts to connect to the API when it errors

* Fix Remote_Logger

* Remove class_wc_remote_logger.php

* Update changelog

* Rename remote logger directory

* Move to internel

* Move to internel

* Update plugins/woocommerce/src/Internal/Loggers/RemoteLogger.php

Co-authored-by: Adrian Duffell <9312929+adrianduffell@users.noreply.github.com>

* Rename folder/namespace Logger -> Logging

---------

Co-authored-by: Adrian Duffell <9312929+adrianduffell@users.noreply.github.com>
This commit is contained in:
Chi-Hsuan Huang 2024-07-23 19:57:20 +08:00 committed by GitHub
parent 8906783e80
commit 572b497ec7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 105 additions and 30 deletions

View File

@ -0,0 +1,4 @@
Significance: patch
Type: update
Move remote logger to `./src` and improve `fetch_latest_woocommerce_version()` logic

View File

@ -28,7 +28,6 @@ use Automattic\WooCommerce\Internal\Utilities\WebhookUtil;
use Automattic\WooCommerce\Internal\Admin\Marketplace; use Automattic\WooCommerce\Internal\Admin\Marketplace;
use Automattic\WooCommerce\Proxies\LegacyProxy; use Automattic\WooCommerce\Proxies\LegacyProxy;
use Automattic\WooCommerce\Utilities\{LoggingUtil, RestApiUtil, TimeUtil}; use Automattic\WooCommerce\Utilities\{LoggingUtil, RestApiUtil, TimeUtil};
use Automattic\WooCommerce\Admin\WCAdminHelper;
/** /**
* Main WooCommerce Class. * Main WooCommerce Class.
@ -647,7 +646,6 @@ final class WooCommerce {
include_once WC_ABSPATH . 'includes/class-wc-structured-data.php'; include_once WC_ABSPATH . 'includes/class-wc-structured-data.php';
include_once WC_ABSPATH . 'includes/class-wc-shortcodes.php'; include_once WC_ABSPATH . 'includes/class-wc-shortcodes.php';
include_once WC_ABSPATH . 'includes/class-wc-logger.php'; include_once WC_ABSPATH . 'includes/class-wc-logger.php';
include_once WC_ABSPATH . 'includes/class-wc-remote-logger.php';
include_once WC_ABSPATH . 'includes/queue/class-wc-action-queue.php'; include_once WC_ABSPATH . 'includes/queue/class-wc-action-queue.php';
include_once WC_ABSPATH . 'includes/queue/class-wc-queue.php'; include_once WC_ABSPATH . 'includes/queue/class-wc-queue.php';
include_once WC_ABSPATH . 'includes/admin/marketplace-suggestions/class-wc-marketplace-updater.php'; include_once WC_ABSPATH . 'includes/admin/marketplace-suggestions/class-wc-marketplace-updater.php';

View File

@ -5,6 +5,7 @@ namespace Automattic\WooCommerce\Internal\DependencyManagement\ServiceProviders;
use Automattic\WooCommerce\Internal\Admin\Logging\{ PageController, Settings }; use Automattic\WooCommerce\Internal\Admin\Logging\{ PageController, Settings };
use Automattic\WooCommerce\Internal\Admin\Logging\FileV2\FileController; use Automattic\WooCommerce\Internal\Admin\Logging\FileV2\FileController;
use Automattic\WooCommerce\Internal\DependencyManagement\AbstractServiceProvider; use Automattic\WooCommerce\Internal\DependencyManagement\AbstractServiceProvider;
use Automattic\WooCommerce\Internal\Logging\RemoteLogger;
/** /**
* LoggingServiceProvider class. * LoggingServiceProvider class.
@ -19,6 +20,7 @@ class LoggingServiceProvider extends AbstractServiceProvider {
FileController::class, FileController::class,
PageController::class, PageController::class,
Settings::class, Settings::class,
RemoteLogger::class,
); );
/** /**
@ -37,5 +39,7 @@ class LoggingServiceProvider extends AbstractServiceProvider {
); );
$this->share( Settings::class ); $this->share( Settings::class );
$this->share( RemoteLogger::class );
} }
} }

View File

@ -1,6 +1,8 @@
<?php <?php
declare( strict_types = 1 ); declare( strict_types = 1 );
namespace Automattic\WooCommerce\Internal\Logging;
use Automattic\WooCommerce\Utilities\FeaturesUtil; use Automattic\WooCommerce\Utilities\FeaturesUtil;
/** /**
@ -10,11 +12,14 @@ use Automattic\WooCommerce\Utilities\FeaturesUtil;
* *
* No personal information is logged, only error information and relevant context. * No personal information is logged, only error information and relevant context.
* *
* @class WC_Remote_Logger * @class RemoteLogger
* @since 9.2.0 * @since 9.2.0
* @package WooCommerce\Classes * @package WooCommerce\Classes
*/ */
class WC_Remote_Logger { class RemoteLogger {
const WC_LATEST_VERSION_TRANSIENT = 'latest_woocommerce_version';
const FETCH_LATEST_VERSION_RETRY = 'fetch_latest_woocommerce_version_retry';
/** /**
* Determines if remote logging is allowed based on the following conditions: * Determines if remote logging is allowed based on the following conditions:
* *
@ -85,24 +90,36 @@ class WC_Remote_Logger {
* @return string|null * @return string|null
*/ */
private function fetch_latest_woocommerce_version() { private function fetch_latest_woocommerce_version() {
$transient_key = 'latest_woocommerce_version'; $cached_version = get_transient( self::WC_LATEST_VERSION_TRANSIENT );
$cached_version = get_transient( $transient_key );
if ( $cached_version ) { if ( $cached_version ) {
return $cached_version; return $cached_version;
} }
$retry_count = get_transient( self::FETCH_LATEST_VERSION_RETRY );
if ( false === $retry_count || ! is_numeric( $retry_count ) ) {
$retry_count = 0;
}
if ( $retry_count >= 3 ) {
return null;
}
if ( ! function_exists( 'plugins_api' ) ) { if ( ! function_exists( 'plugins_api' ) ) {
require_once ABSPATH . 'wp-admin/includes/plugin-install.php'; require_once ABSPATH . 'wp-admin/includes/plugin-install.php';
} }
// Fetch the latest version from the WordPress API.
$plugin_info = plugins_api( 'plugin_information', array( 'slug' => 'woocommerce' ) ); $plugin_info = plugins_api( 'plugin_information', array( 'slug' => 'woocommerce' ) );
if ( is_wp_error( $plugin_info ) ) { if ( is_wp_error( $plugin_info ) ) {
++$retry_count;
set_transient( self::FETCH_LATEST_VERSION_RETRY, $retry_count, HOUR_IN_SECONDS );
return null; return null;
} }
if ( ! empty( $plugin_info->version ) ) { if ( ! empty( $plugin_info->version ) ) {
$latest_version = $plugin_info->version; $latest_version = $plugin_info->version;
set_transient( $transient_key, $latest_version, DAY_IN_SECONDS ); set_transient( self::WC_LATEST_VERSION_TRANSIENT, $latest_version, WEEK_IN_SECONDS );
delete_transient( self::FETCH_LATEST_VERSION_RETRY );
return $latest_version; return $latest_version;
} }

View File

@ -1,10 +1,22 @@
<?php <?php
declare( strict_types = 1 ); declare( strict_types = 1 );
namespace Automattic\WooCommerce\Tests\Internal\Logging;
use Automattic\WooCommerce\Internal\Logging\RemoteLogger;
/** /**
* Class WC_Remote_Logger_Test. * Class RemoteLoggerTest.
*/ */
class WC_Remote_Logger_Test extends \WC_Unit_Test_Case { class RemoteLoggerTest extends \WC_Unit_Test_Case {
/**
* System under test.
*
* @var RemoteLogger;
*/
private $sut;
/** /**
* Set up test * Set up test
@ -13,7 +25,8 @@ class WC_Remote_Logger_Test extends \WC_Unit_Test_Case {
*/ */
public function setUp(): void { public function setUp(): void {
parent::setUp(); parent::setUp();
include_once WC_ABSPATH . 'includes/class-wc-remote-logger.php';
$this->sut = wc_get_container()->get( RemoteLogger::class );
WC()->version = '9.2.0'; WC()->version = '9.2.0';
} }
@ -27,6 +40,7 @@ class WC_Remote_Logger_Test extends \WC_Unit_Test_Case {
$this->cleanup_filters(); $this->cleanup_filters();
delete_option( 'woocommerce_feature_remote_logging_enabled' ); delete_option( 'woocommerce_feature_remote_logging_enabled' );
delete_transient( RemoteLogger::WC_LATEST_VERSION_TRANSIENT );
} }
/** /**
@ -39,10 +53,11 @@ class WC_Remote_Logger_Test extends \WC_Unit_Test_Case {
remove_all_filters( 'option_woocommerce_allow_tracking' ); remove_all_filters( 'option_woocommerce_allow_tracking' );
remove_all_filters( 'option_woocommerce_version' ); remove_all_filters( 'option_woocommerce_version' );
remove_all_filters( 'option_woocommerce_remote_variant_assignment' ); remove_all_filters( 'option_woocommerce_remote_variant_assignment' );
remove_all_filters( 'plugins_api' );
} }
/** /**
* Test that remote logging is allowed when all conditions are met. * @testdox Test that remote logging is allowed when all conditions are met.
*/ */
public function test_remote_logging_allowed() { public function test_remote_logging_allowed() {
update_option( 'woocommerce_feature_remote_logging_enabled', 'yes' ); update_option( 'woocommerce_feature_remote_logging_enabled', 'yes' );
@ -74,12 +89,11 @@ class WC_Remote_Logger_Test extends \WC_Unit_Test_Case {
3 3
); );
$checker = new WC_Remote_Logger(); $this->assertTrue( $this->sut->is_remote_logging_allowed() );
$this->assertTrue( $checker->is_remote_logging_allowed() );
} }
/** /**
* Test that remote logging is not allowed when the feature flag is disabled. * @testdox Test that remote logging is not allowed when the feature flag is disabled.
*/ */
public function test_remote_logging_not_allowed_feature_flag_disabled() { public function test_remote_logging_not_allowed_feature_flag_disabled() {
update_option( 'woocommerce_feature_remote_logging_enabled', 'no' ); update_option( 'woocommerce_feature_remote_logging_enabled', 'no' );
@ -97,14 +111,13 @@ class WC_Remote_Logger_Test extends \WC_Unit_Test_Case {
} }
); );
set_transient( 'latest_woocommerce_version', '9.2.0', DAY_IN_SECONDS ); set_transient( RemoteLogger::WC_LATEST_VERSION_TRANSIENT, '9.2.0', DAY_IN_SECONDS );
$checker = new WC_Remote_Logger(); $this->assertFalse( $this->sut->is_remote_logging_allowed() );
$this->assertFalse( $checker->is_remote_logging_allowed() );
} }
/** /**
* Test that remote logging is not allowed when user tracking is not opted in. * @testdox Test that remote logging is not allowed when user tracking is not opted in.
*/ */
public function test_remote_logging_not_allowed_tracking_opted_out() { public function test_remote_logging_not_allowed_tracking_opted_out() {
update_option( 'woocommerce_feature_remote_logging_enabled', 'yes' ); update_option( 'woocommerce_feature_remote_logging_enabled', 'yes' );
@ -121,14 +134,13 @@ class WC_Remote_Logger_Test extends \WC_Unit_Test_Case {
} }
); );
set_transient( 'latest_woocommerce_version', '9.2.0', DAY_IN_SECONDS ); set_transient( RemoteLogger::WC_LATEST_VERSION_TRANSIENT, '9.2.0', DAY_IN_SECONDS );
$checker = new WC_Remote_Logger(); $this->assertFalse( $this->sut->is_remote_logging_allowed() );
$this->assertFalse( $checker->is_remote_logging_allowed() );
} }
/** /**
* Test that remote logging is not allowed when the WooCommerce version is outdated. * @testdox Test that remote logging is not allowed when the WooCommerce version is outdated.
*/ */
public function test_remote_logging_not_allowed_outdated_version() { public function test_remote_logging_not_allowed_outdated_version() {
update_option( 'woocommerce_feature_remote_logging_enabled', 'yes' ); update_option( 'woocommerce_feature_remote_logging_enabled', 'yes' );
@ -145,15 +157,14 @@ class WC_Remote_Logger_Test extends \WC_Unit_Test_Case {
} }
); );
set_transient( 'latest_woocommerce_version', '9.2.0', DAY_IN_SECONDS ); set_transient( RemoteLogger::WC_LATEST_VERSION_TRANSIENT, '9.2.0', DAY_IN_SECONDS );
WC()->version = '9.0.0'; WC()->version = '9.0.0';
$checker = new WC_Remote_Logger(); $this->assertFalse( $this->sut->is_remote_logging_allowed() );
$this->assertFalse( $checker->is_remote_logging_allowed() );
} }
/** /**
* Test that remote logging is not allowed when the variant assignment is high. * @testdox Test that remote logging is not allowed when the variant assignment is high.
*/ */
public function test_remote_logging_not_allowed_high_variant_assignment() { public function test_remote_logging_not_allowed_high_variant_assignment() {
update_option( 'woocommerce_feature_remote_logging_enabled', 'yes' ); update_option( 'woocommerce_feature_remote_logging_enabled', 'yes' );
@ -176,9 +187,50 @@ class WC_Remote_Logger_Test extends \WC_Unit_Test_Case {
} }
); );
set_transient( 'latest_woocommerce_version', '9.2.0', DAY_IN_SECONDS ); set_transient( RemoteLogger::WC_LATEST_VERSION_TRANSIENT, '9.2.0', DAY_IN_SECONDS );
$checker = new WC_Remote_Logger(); $this->assertFalse( $this->sut->is_remote_logging_allowed() );
$this->assertFalse( $checker->is_remote_logging_allowed() ); }
/**
* @testdox Test that the fetch_latest_woocommerce_version method retries fetching the latest WooCommerce version when the API call fails.
*/
public function test_fetch_latest_woocommerce_version_retry() {
update_option( 'woocommerce_feature_remote_logging_enabled', 'yes' );
add_filter(
'option_woocommerce_allow_tracking',
function () {
return 'yes';
}
);
add_filter(
'option_woocommerce_remote_variant_assignment',
function () {
return 5;
}
);
add_filter(
'plugins_api', // phpcs:ignore PEAR.Functions.FunctionCallSignature.MultipleArguments
function ( $result, $action, $args ) { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed
return new \WP_Error();
},
10,
3
);
$this->sut->is_remote_logging_allowed();
$this->assertEquals( 1, get_transient( RemoteLogger::FETCH_LATEST_VERSION_RETRY ) );
$this->sut->is_remote_logging_allowed();
$this->assertEquals( 2, get_transient( RemoteLogger::FETCH_LATEST_VERSION_RETRY ) );
$this->sut->is_remote_logging_allowed();
$this->assertEquals( 3, get_transient( RemoteLogger::FETCH_LATEST_VERSION_RETRY ) );
// After 3 retries, the transient should not be updated.
$this->sut->is_remote_logging_allowed();
$this->assertEquals( 3, get_transient( RemoteLogger::FETCH_LATEST_VERSION_RETRY ) );
} }
} }