Add remote logger as a log handler to wc logger (#50430)
* Register remote log handler in WooCommerce class * Add changefile(s) from automation for the following project(s): woocommerce * Fix lint --------- Co-authored-by: github-actions <github-actions@github.com>
This commit is contained in:
parent
d0e0567291
commit
e4bb2c2317
|
@ -0,0 +1,4 @@
|
||||||
|
Significance: patch
|
||||||
|
Type: update
|
||||||
|
|
||||||
|
Add remote logger as a log handler to wc logger
|
|
@ -311,6 +311,7 @@ final class WooCommerce {
|
||||||
|
|
||||||
self::add_filter( 'robots_txt', array( $this, 'robots_txt' ) );
|
self::add_filter( 'robots_txt', array( $this, 'robots_txt' ) );
|
||||||
add_filter( 'wp_plugin_dependencies_slug', array( $this, 'convert_woocommerce_slug' ) );
|
add_filter( 'wp_plugin_dependencies_slug', array( $this, 'convert_woocommerce_slug' ) );
|
||||||
|
self::add_filter( 'woocommerce_register_log_handlers', array( $this, 'register_remote_log_handler' ) );
|
||||||
|
|
||||||
// These classes set up hooks on instantiation.
|
// These classes set up hooks on instantiation.
|
||||||
$container = wc_get_container();
|
$container = wc_get_container();
|
||||||
|
@ -410,9 +411,6 @@ final class WooCommerce {
|
||||||
$mc_stats->add( 'error', 'fatal-errors-during-shutdown' );
|
$mc_stats->add( 'error', 'fatal-errors-during-shutdown' );
|
||||||
$mc_stats->do_server_side_stats();
|
$mc_stats->do_server_side_stats();
|
||||||
|
|
||||||
$remote_logger = $container->get( RemoteLogger::class );
|
|
||||||
$remote_logger->handle( time(), WC_Log_Levels::CRITICAL, $message, $context );
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Action triggered when there are errors during shutdown.
|
* Action triggered when there are errors during shutdown.
|
||||||
*
|
*
|
||||||
|
@ -1314,4 +1312,16 @@ final class WooCommerce {
|
||||||
}
|
}
|
||||||
return $slug;
|
return $slug;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register the remote log handler.
|
||||||
|
*
|
||||||
|
* @param \WC_Log_Handler[] $handlers The handlers to register.
|
||||||
|
*
|
||||||
|
* @return \WC_Log_Handler[]
|
||||||
|
*/
|
||||||
|
private function register_remote_log_handler( $handlers ) {
|
||||||
|
$handlers[] = wc_get_container()->get( RemoteLogger::class );
|
||||||
|
return $handlers;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ namespace Automattic\WooCommerce\Internal\Logging;
|
||||||
use Automattic\WooCommerce\Utilities\FeaturesUtil;
|
use Automattic\WooCommerce\Utilities\FeaturesUtil;
|
||||||
use Automattic\WooCommerce\Utilities\StringUtil;
|
use Automattic\WooCommerce\Utilities\StringUtil;
|
||||||
use WC_Rate_Limiter;
|
use WC_Rate_Limiter;
|
||||||
|
use WC_Log_Levels;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* WooCommerce Remote Logger
|
* WooCommerce Remote Logger
|
||||||
|
@ -25,25 +26,6 @@ class RemoteLogger extends \WC_Log_Handler {
|
||||||
const WC_LATEST_VERSION_TRANSIENT = 'latest_woocommerce_version';
|
const WC_LATEST_VERSION_TRANSIENT = 'latest_woocommerce_version';
|
||||||
const FETCH_LATEST_VERSION_RETRY = 'fetch_latest_woocommerce_version_retry';
|
const FETCH_LATEST_VERSION_RETRY = 'fetch_latest_woocommerce_version_retry';
|
||||||
|
|
||||||
/**
|
|
||||||
* The logger instance.
|
|
||||||
*
|
|
||||||
* @var \WC_Logger_Interface|null
|
|
||||||
*/
|
|
||||||
private $local_logger;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remote logger constructor.
|
|
||||||
*
|
|
||||||
* @internal
|
|
||||||
* @param \WC_Logger_Interface|null $logger Logger instance.
|
|
||||||
*/
|
|
||||||
public function __construct( \WC_Logger_Interface $logger = null ) {
|
|
||||||
$this->local_logger = null === $logger
|
|
||||||
? wc_get_logger()
|
|
||||||
: $logger;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle a log entry.
|
* Handle a log entry.
|
||||||
*
|
*
|
||||||
|
@ -57,67 +39,13 @@ class RemoteLogger extends \WC_Log_Handler {
|
||||||
* @return bool False if value was not handled and true if value was handled.
|
* @return bool False if value was not handled and true if value was handled.
|
||||||
*/
|
*/
|
||||||
public function handle( $timestamp, $level, $message, $context ) {
|
public function handle( $timestamp, $level, $message, $context ) {
|
||||||
if ( ! \WC_Log_Levels::is_valid_level( $level ) ) {
|
if ( ! $this->should_handle( $level, $message, $context ) ) {
|
||||||
/* translators: 1: WC_Remote_Logger::log 2: level */
|
|
||||||
wc_doing_it_wrong( __METHOD__, sprintf( __( '%1$s was called with an invalid level "%2$s".', 'woocommerce' ), '<code>WC_Remote_Logger::handle</code>', $level ), '9.2.0' );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( ! $this->is_remote_logging_allowed() ) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( $this->is_third_party_error( (string) $message, (array) $context ) ) {
|
return $this->log( $level, $message, $context );
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( WC_Rate_Limiter::retried_too_soon( self::RATE_LIMIT_ID ) ) {
|
|
||||||
$this->local_logger->info( 'Remote logging throttled.', array( 'source' => 'wc-remote-logger' ) );
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
$log_data = $this->get_formatted_log( $level, $message, $context );
|
|
||||||
|
|
||||||
// Ensure the log data is valid.
|
|
||||||
if ( ! is_array( $log_data ) || empty( $log_data['message'] ) || empty( $log_data['feature'] ) ) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$body = array(
|
|
||||||
'params' => wp_json_encode( $log_data ),
|
|
||||||
);
|
|
||||||
|
|
||||||
WC_Rate_Limiter::set_rate_limit( self::RATE_LIMIT_ID, self::RATE_LIMIT_DELAY );
|
|
||||||
|
|
||||||
if ( $this->is_dev_or_local_environment() ) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$response = wp_safe_remote_post(
|
|
||||||
self::LOG_ENDPOINT,
|
|
||||||
array(
|
|
||||||
'body' => wp_json_encode( $body ),
|
|
||||||
'timeout' => 2,
|
|
||||||
'headers' => array(
|
|
||||||
'Content-Type' => 'application/json',
|
|
||||||
),
|
|
||||||
'blocking' => false,
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
if ( is_wp_error( $response ) ) {
|
|
||||||
throw new \Exception( $response->get_error_message() );
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
} catch ( \Exception $e ) {
|
|
||||||
// Log the error locally if the remote logging fails.
|
|
||||||
$this->local_logger->error( 'Remote logging failed: ' . $e->getMessage() );
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get formatted log data to be sent to the remote logging service.
|
* Get formatted log data to be sent to the remote logging service.
|
||||||
*
|
*
|
||||||
|
@ -228,6 +156,90 @@ class RemoteLogger extends \WC_Log_Handler {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether to handle or ignore log.
|
||||||
|
*
|
||||||
|
* @param string $level emergency|alert|critical|error|warning|notice|info|debug.
|
||||||
|
* @param string $message Log message to be recorded.
|
||||||
|
* @param array $context Additional information for log handlers.
|
||||||
|
*
|
||||||
|
* @return bool True if the log should be handled.
|
||||||
|
*/
|
||||||
|
protected function should_handle( $level, $message, $context ) {
|
||||||
|
if ( ! $this->is_remote_logging_allowed() ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Ignore logs that are less severe than critical. This is temporary to prevent sending too many logs to the remote logging service. We can consider remove this if the remote logging service can handle more logs.
|
||||||
|
if ( WC_Log_Levels::get_level_severity( $level ) < WC_Log_Levels::get_level_severity( WC_Log_Levels::CRITICAL ) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( $this->is_third_party_error( (string) $message, (array) $context ) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( WC_Rate_Limiter::retried_too_soon( self::RATE_LIMIT_ID ) ) {
|
||||||
|
error_log( 'Remote logging throttled.' ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send the log to the remote logging service.
|
||||||
|
*
|
||||||
|
* @param string $level Log level (e.g., 'error', 'warning', 'info').
|
||||||
|
* @param string $message Log message to be recorded.
|
||||||
|
* @param array $context Optional. Additional information for log handlers, such as 'backtrace', 'tags', 'extra', and 'error'.
|
||||||
|
*
|
||||||
|
* @throws \Exception If the remote logging fails. The error is caught and logged locally.
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
private function log( $level, $message, $context ) {
|
||||||
|
try {
|
||||||
|
$log_data = $this->get_formatted_log( $level, $message, $context );
|
||||||
|
|
||||||
|
// Ensure the log data is valid.
|
||||||
|
if ( ! is_array( $log_data ) || empty( $log_data['message'] ) || empty( $log_data['feature'] ) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$body = array(
|
||||||
|
'params' => wp_json_encode( $log_data ),
|
||||||
|
);
|
||||||
|
|
||||||
|
WC_Rate_Limiter::set_rate_limit( self::RATE_LIMIT_ID, self::RATE_LIMIT_DELAY );
|
||||||
|
|
||||||
|
if ( $this->is_dev_or_local_environment() ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$response = wp_safe_remote_post(
|
||||||
|
self::LOG_ENDPOINT,
|
||||||
|
array(
|
||||||
|
'body' => wp_json_encode( $body ),
|
||||||
|
'timeout' => 2,
|
||||||
|
'headers' => array(
|
||||||
|
'Content-Type' => 'application/json',
|
||||||
|
),
|
||||||
|
'blocking' => false,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
if ( is_wp_error( $response ) ) {
|
||||||
|
throw new \Exception( $response->get_error_message() );
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} catch ( \Exception $e ) {
|
||||||
|
// Log the error locally if the remote logging fails.
|
||||||
|
error_log( 'Remote logging failed: ' . $e->getMessage() ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if the store is allowed to log based on the variant assignment percentage.
|
* Check if the store is allowed to log based on the variant assignment percentage.
|
||||||
*
|
*
|
||||||
|
|
|
@ -6,20 +6,17 @@ namespace Automattic\WooCommerce\Tests\Internal\Logging;
|
||||||
use Automattic\WooCommerce\Internal\Logging\RemoteLogger;
|
use Automattic\WooCommerce\Internal\Logging\RemoteLogger;
|
||||||
use WC_Rate_Limiter;
|
use WC_Rate_Limiter;
|
||||||
use WC_Cache_Helper;
|
use WC_Cache_Helper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class RemoteLoggerTest.
|
* Class RemoteLoggerTest.
|
||||||
*/
|
*/
|
||||||
class RemoteLoggerTest extends \WC_Unit_Test_Case {
|
class RemoteLoggerTest extends \WC_Unit_Test_Case {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* System under test.
|
* System under test.
|
||||||
*
|
*
|
||||||
* @var RemoteLogger;
|
* @var RemoteLogger
|
||||||
*/
|
*/
|
||||||
private $sut;
|
private $sut;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set up test
|
* Set up test
|
||||||
*
|
*
|
||||||
|
@ -27,9 +24,7 @@ class RemoteLoggerTest extends \WC_Unit_Test_Case {
|
||||||
*/
|
*/
|
||||||
public function setUp(): void {
|
public function setUp(): void {
|
||||||
parent::setUp();
|
parent::setUp();
|
||||||
|
$this->sut = wc_get_container()->get( RemoteLogger::class );
|
||||||
$this->sut = wc_get_container()->get( RemoteLogger::class );
|
|
||||||
|
|
||||||
WC()->version = '9.2.0';
|
WC()->version = '9.2.0';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,418 +35,274 @@ class RemoteLoggerTest extends \WC_Unit_Test_Case {
|
||||||
*/
|
*/
|
||||||
public function tearDown(): void {
|
public function tearDown(): void {
|
||||||
$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 );
|
delete_transient( RemoteLogger::WC_LATEST_VERSION_TRANSIENT );
|
||||||
|
|
||||||
global $wpdb;
|
global $wpdb;
|
||||||
$wpdb->query(
|
$wpdb->query( "DELETE FROM {$wpdb->prefix}wc_rate_limits" );
|
||||||
"DELETE FROM {$wpdb->prefix}wc_rate_limits"
|
|
||||||
);
|
|
||||||
|
|
||||||
WC_Cache_Helper::invalidate_cache_group( WC_Rate_Limiter::CACHE_GROUP );
|
WC_Cache_Helper::invalidate_cache_group( WC_Rate_Limiter::CACHE_GROUP );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clean up filters.
|
* Cleanup filters used in tests.
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
private function cleanup_filters() {
|
private function cleanup_filters() {
|
||||||
remove_all_filters( 'option_woocommerce_admin_remote_feature_enabled' );
|
$filters = array(
|
||||||
remove_all_filters( 'option_woocommerce_allow_tracking' );
|
'option_woocommerce_admin_remote_feature_enabled',
|
||||||
remove_all_filters( 'option_woocommerce_version' );
|
'option_woocommerce_allow_tracking',
|
||||||
remove_all_filters( 'option_woocommerce_remote_variant_assignment' );
|
'option_woocommerce_version',
|
||||||
remove_all_filters( 'plugins_api' );
|
'option_woocommerce_remote_variant_assignment',
|
||||||
remove_all_filters( 'pre_http_request' );
|
'plugins_api',
|
||||||
remove_all_filters( 'woocommerce_remote_logger_formatted_log_data' );
|
'pre_http_request',
|
||||||
|
'woocommerce_remote_logger_formatted_log_data',
|
||||||
|
);
|
||||||
|
foreach ( $filters as $filter ) {
|
||||||
|
remove_all_filters( $filter );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @testdox Test that remote logging is allowed when all conditions are met.
|
* @testdox 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' );
|
$this->setup_remote_logging_conditions( true );
|
||||||
|
|
||||||
add_filter(
|
|
||||||
'option_woocommerce_allow_tracking',
|
|
||||||
function () {
|
|
||||||
return 'yes';
|
|
||||||
}
|
|
||||||
);
|
|
||||||
add_filter(
|
|
||||||
'option_woocommerce_remote_variant_assignment',
|
|
||||||
function () {
|
|
||||||
return 5;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
add_filter(
|
|
||||||
'plugins_api',
|
|
||||||
function ( $result, $action, $args ) {
|
|
||||||
if ( 'plugin_information' === $action && 'woocommerce' === $args->slug ) {
|
|
||||||
return (object) array(
|
|
||||||
'version' => '9.2.0',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return $result;
|
|
||||||
},
|
|
||||||
10,
|
|
||||||
3
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->assertTrue( $this->sut->is_remote_logging_allowed() );
|
$this->assertTrue( $this->sut->is_remote_logging_allowed() );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @testdox Test that remote logging is not allowed when the feature flag is disabled.
|
* @testdox Remote logging is not allowed under various conditions
|
||||||
|
* @dataProvider remote_logging_disallowed_provider
|
||||||
|
*
|
||||||
|
* @param string $condition The condition being tested.
|
||||||
|
* @param callable $setup_callback Callback to set up the test condition.
|
||||||
*/
|
*/
|
||||||
public function test_remote_logging_not_allowed_feature_flag_disabled() {
|
public function test_remote_logging_not_allowed( $condition, $setup_callback ) {
|
||||||
update_option( 'woocommerce_feature_remote_logging_enabled', 'no' );
|
$this->setup_remote_logging_conditions( true );
|
||||||
|
$setup_callback( $this );
|
||||||
add_filter(
|
|
||||||
'option_woocommerce_allow_tracking',
|
|
||||||
function () {
|
|
||||||
return 'yes';
|
|
||||||
}
|
|
||||||
);
|
|
||||||
add_filter(
|
|
||||||
'option_woocommerce_remote_variant_assignment',
|
|
||||||
function () {
|
|
||||||
return 5;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
set_transient( RemoteLogger::WC_LATEST_VERSION_TRANSIENT, '9.2.0', DAY_IN_SECONDS );
|
|
||||||
|
|
||||||
$this->assertFalse( $this->sut->is_remote_logging_allowed() );
|
$this->assertFalse( $this->sut->is_remote_logging_allowed() );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @testdox Test that remote logging is not allowed when user tracking is not opted in.
|
* Data provider for test_remote_logging_not_allowed.
|
||||||
|
*
|
||||||
|
* @return array[] Test cases with conditions and setup callbacks.
|
||||||
*/
|
*/
|
||||||
public function test_remote_logging_not_allowed_tracking_opted_out() {
|
public function remote_logging_disallowed_provider() {
|
||||||
update_option( 'woocommerce_feature_remote_logging_enabled', 'yes' );
|
return array(
|
||||||
add_filter(
|
'feature flag disabled' => array(
|
||||||
'option_woocommerce_allow_tracking',
|
'condition' => 'feature flag disabled',
|
||||||
function () {
|
'setup' => fn() => update_option( 'woocommerce_feature_remote_logging_enabled', 'no' ),
|
||||||
return 'no';
|
),
|
||||||
}
|
'tracking opted out' => array(
|
||||||
);
|
'condition' => 'tracking opted out',
|
||||||
add_filter(
|
'setup' => fn() => add_filter( 'option_woocommerce_allow_tracking', fn() => 'no' ),
|
||||||
'option_woocommerce_remote_variant_assignment',
|
),
|
||||||
function () {
|
'outdated version' => array(
|
||||||
return 5;
|
'condition' => 'outdated version',
|
||||||
}
|
'setup' => fn() => WC()->version = '9.0.0',
|
||||||
);
|
),
|
||||||
|
'high variant assignment' => array(
|
||||||
set_transient( RemoteLogger::WC_LATEST_VERSION_TRANSIENT, '9.2.0', DAY_IN_SECONDS );
|
'condition' => 'high variant assignment',
|
||||||
|
'setup' => fn() => add_filter( 'option_woocommerce_remote_variant_assignment', fn() => 15 ),
|
||||||
$this->assertFalse( $this->sut->is_remote_logging_allowed() );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @testdox Test that remote logging is not allowed when the WooCommerce version is outdated.
|
|
||||||
*/
|
|
||||||
public function test_remote_logging_not_allowed_outdated_version() {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
set_transient( RemoteLogger::WC_LATEST_VERSION_TRANSIENT, '9.2.0', DAY_IN_SECONDS );
|
|
||||||
WC()->version = '9.0.0';
|
|
||||||
|
|
||||||
$this->assertFalse( $this->sut->is_remote_logging_allowed() );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @testdox Test that remote logging is not allowed when the variant assignment is high.
|
|
||||||
*/
|
|
||||||
public function test_remote_logging_not_allowed_high_variant_assignment() {
|
|
||||||
update_option( 'woocommerce_feature_remote_logging_enabled', 'yes' );
|
|
||||||
add_filter(
|
|
||||||
'option_woocommerce_allow_tracking',
|
|
||||||
function () {
|
|
||||||
return 'yes';
|
|
||||||
}
|
|
||||||
);
|
|
||||||
add_filter(
|
|
||||||
'option_woocommerce_version',
|
|
||||||
function () {
|
|
||||||
return '9.2.0';
|
|
||||||
}
|
|
||||||
);
|
|
||||||
add_filter(
|
|
||||||
'option_woocommerce_remote_variant_assignment',
|
|
||||||
function () {
|
|
||||||
return 15;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
set_transient( RemoteLogger::WC_LATEST_VERSION_TRANSIENT, '9.2.0', DAY_IN_SECONDS );
|
|
||||||
|
|
||||||
$this->assertFalse( $this->sut->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 ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @testdox Test get_formatted_log method with basic log data returns expected array.
|
|
||||||
*/
|
|
||||||
public function test_get_formatted_log_basic() {
|
|
||||||
$level = 'error';
|
|
||||||
$message = 'Fatal error occurred at line 123 in ' . ABSPATH . 'wp-content/file.php';
|
|
||||||
$context = array( 'tags' => array( 'tag1', 'tag2' ) );
|
|
||||||
|
|
||||||
$formatted_log = $this->sut->get_formatted_log( $level, $message, $context );
|
|
||||||
|
|
||||||
$this->assertArrayHasKey( 'feature', $formatted_log );
|
|
||||||
$this->assertArrayHasKey( 'severity', $formatted_log );
|
|
||||||
$this->assertArrayHasKey( 'message', $formatted_log );
|
|
||||||
$this->assertArrayHasKey( 'host', $formatted_log );
|
|
||||||
$this->assertArrayHasKey( 'tags', $formatted_log );
|
|
||||||
$this->assertArrayHasKey( 'properties', $formatted_log );
|
|
||||||
|
|
||||||
$this->assertEquals( 'woocommerce_core', $formatted_log['feature'] );
|
|
||||||
$this->assertEquals( 'error', $formatted_log['severity'] );
|
|
||||||
$this->assertEquals( 'Fatal error occurred at line 123 in **/wp-content/file.php', $formatted_log['message'] );
|
|
||||||
$this->assertEquals( wp_parse_url( home_url(), PHP_URL_HOST ), $formatted_log['host'] );
|
|
||||||
|
|
||||||
// Tags.
|
|
||||||
$this->assertArrayHasKey( 'tags', $formatted_log );
|
|
||||||
$this->assertEquals( array( 'woocommerce', 'php', 'tag1', 'tag2' ), $formatted_log['tags'] );
|
|
||||||
|
|
||||||
// Properties.
|
|
||||||
$this->assertEquals( WC()->version, $formatted_log['properties']['wc_version'] );
|
|
||||||
$this->assertEquals( get_bloginfo( 'version' ), $formatted_log['properties']['wp_version'] );
|
|
||||||
$this->assertEquals( phpversion(), $formatted_log['properties']['php_version'] );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @testdox Test get_formatted_log method sanitizes backtrace.
|
|
||||||
*/
|
|
||||||
public function test_get_formatted_log_with_backtrace() {
|
|
||||||
$level = 'error';
|
|
||||||
$message = 'Test error message';
|
|
||||||
$context = array( 'backtrace' => ABSPATH . 'wp-content/file.php' );
|
|
||||||
|
|
||||||
$result = $this->sut->get_formatted_log( $level, $message, $context );
|
|
||||||
$this->assertEquals( '**/wp-content/file.php', $result['trace'] );
|
|
||||||
|
|
||||||
$context = array( 'backtrace' => ABSPATH . 'wp-content/plugins/woocommerce/file.php' );
|
|
||||||
$result = $this->sut->get_formatted_log( $level, $message, $context );
|
|
||||||
$this->assertEquals( '**/woocommerce/file.php', $result['trace'] );
|
|
||||||
|
|
||||||
$context = array( 'backtrace' => true );
|
|
||||||
$result = $this->sut->get_formatted_log( $level, $message, $context );
|
|
||||||
|
|
||||||
$this->assertIsString( $result['trace'] );
|
|
||||||
$this->assertStringContainsString( '**/woocommerce/tests/php/src/Internal/Logging/RemoteLoggerTest.php', $result['trace'] );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @testdox Test get_formatted_log method log extra attributes.
|
|
||||||
*/
|
|
||||||
public function test_get_formatted_log_with_extra() {
|
|
||||||
$level = 'error';
|
|
||||||
$message = 'Test error message';
|
|
||||||
$context = array(
|
|
||||||
'extra' => array(
|
|
||||||
'key1' => 'value1',
|
|
||||||
'key2' => 'value2',
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
$result = $this->sut->get_formatted_log( $level, $message, $context );
|
|
||||||
|
|
||||||
$this->assertArrayHasKey( 'extra', $result );
|
|
||||||
$this->assertEquals( 'value1', $result['extra']['key1'] );
|
|
||||||
$this->assertEquals( 'value2', $result['extra']['key2'] );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @testdox Fetch latest WooCommerce version retries on API failure
|
||||||
|
*/
|
||||||
|
public function test_fetch_latest_woocommerce_version_retry() {
|
||||||
|
$this->setup_remote_logging_conditions( true );
|
||||||
|
add_filter( 'plugins_api', fn() => new \WP_Error(), 10, 3 );
|
||||||
|
|
||||||
|
for ( $i = 1; $i <= 4; $i++ ) {
|
||||||
|
$this->sut->is_remote_logging_allowed();
|
||||||
|
$retry_count = get_transient( RemoteLogger::FETCH_LATEST_VERSION_RETRY );
|
||||||
|
$this->assertEquals( min( $i, 3 ), $retry_count );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @testdox Test handle() method when throttled.
|
* @testdox get_formatted_log method returns expected array structure
|
||||||
|
* @dataProvider get_formatted_log_provider
|
||||||
*
|
*
|
||||||
* @return void
|
* @param string $level The log level.
|
||||||
|
* @param string $message The log message.
|
||||||
|
* @param array $context The log context.
|
||||||
|
* @param array $expected The expected formatted log array.
|
||||||
*/
|
*/
|
||||||
public function test_handle_returns_false_when_throttled() {
|
public function test_get_formatted_log( $level, $message, $context, $expected ) {
|
||||||
$mock_local_logger = $this->createMock( \WC_Logger::class );
|
$formatted_log = $this->sut->get_formatted_log( $level, $message, $context );
|
||||||
$mock_local_logger->expects( $this->once() )
|
foreach ( $expected as $key => $value ) {
|
||||||
->method( 'info' )
|
$this->assertArrayHasKey( $key, $formatted_log );
|
||||||
->with( 'Remote logging throttled.', array( 'source' => 'wc-remote-logger' ) );
|
$this->assertEquals( $value, $formatted_log[ $key ] );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data provider for test_get_formatted_log.
|
||||||
|
*
|
||||||
|
* @return array[] Test cases with log data and expected formatted output.
|
||||||
|
*/
|
||||||
|
public function get_formatted_log_provider() {
|
||||||
|
return array(
|
||||||
|
'basic log data' => array(
|
||||||
|
'error',
|
||||||
|
'Fatal error occurred at line 123 in ' . ABSPATH . 'wp-content/file.php',
|
||||||
|
array( 'tags' => array( 'tag1', 'tag2' ) ),
|
||||||
|
array(
|
||||||
|
'feature' => 'woocommerce_core',
|
||||||
|
'severity' => 'error',
|
||||||
|
'message' => 'Fatal error occurred at line 123 in **/wp-content/file.php',
|
||||||
|
'tags' => array( 'woocommerce', 'php', 'tag1', 'tag2' ),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'log with backtrace' => array(
|
||||||
|
'error',
|
||||||
|
'Test error message',
|
||||||
|
array( 'backtrace' => ABSPATH . 'wp-content/plugins/woocommerce/file.php' ),
|
||||||
|
array( 'trace' => '**/woocommerce/file.php' ),
|
||||||
|
),
|
||||||
|
'log with extra attributes' => array(
|
||||||
|
'error',
|
||||||
|
'Test error message',
|
||||||
|
array(
|
||||||
|
'extra' => array(
|
||||||
|
'key1' => 'value1',
|
||||||
|
'key2' => 'value2',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'extra' => array(
|
||||||
|
'key1' => 'value1',
|
||||||
|
'key2' => 'value2',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @testdox should_handle method behaves correctly under different conditions
|
||||||
|
* @dataProvider should_handle_provider
|
||||||
|
*
|
||||||
|
* @param callable $setup Function to set up the test environment.
|
||||||
|
* @param string $level Log level to test.
|
||||||
|
* @param bool $expected Expected result of should_handle method.
|
||||||
|
*/
|
||||||
|
public function test_should_handle( $setup, $level, $expected ) {
|
||||||
|
$this->sut = $this->getMockBuilder( RemoteLogger::class )
|
||||||
|
->onlyMethods( array( 'is_remote_logging_allowed', 'is_third_party_error' ) )
|
||||||
|
->getMock();
|
||||||
|
|
||||||
|
$this->sut->method( 'is_remote_logging_allowed' )->willReturn( true );
|
||||||
|
$this->sut->method( 'is_third_party_error' )->willReturn( false );
|
||||||
|
|
||||||
|
$setup( $this );
|
||||||
|
|
||||||
|
$result = $this->invoke_private_method( $this->sut, 'should_handle', array( $level, 'Test message', array() ) );
|
||||||
|
$this->assertEquals( $expected, $result );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data provider for test_should_handle method.
|
||||||
|
*
|
||||||
|
* @return array Test cases for should_handle method.
|
||||||
|
*/
|
||||||
|
public function should_handle_provider() {
|
||||||
|
return array(
|
||||||
|
'throttled' => array(
|
||||||
|
fn() => WC_Rate_Limiter::set_rate_limit( RemoteLogger::RATE_LIMIT_ID, 10 ),
|
||||||
|
'critical',
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
'less severe than critical' => array(
|
||||||
|
fn() => null,
|
||||||
|
'error',
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
'critical level' => array(
|
||||||
|
fn() => null,
|
||||||
|
'critical',
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @testdox handle method applies filter and doesn't send logs when filtered to null
|
||||||
|
*/
|
||||||
|
public function test_handle_filtered_log_null() {
|
||||||
$this->sut = $this->getMockBuilder( RemoteLogger::class )
|
$this->sut = $this->getMockBuilder( RemoteLogger::class )
|
||||||
->setConstructorArgs( array( $mock_local_logger ) )
|
|
||||||
->onlyMethods( array( 'is_remote_logging_allowed' ) )
|
->onlyMethods( array( 'is_remote_logging_allowed' ) )
|
||||||
->getMock();
|
->getMock();
|
||||||
|
|
||||||
$this->sut->method( 'is_remote_logging_allowed' )->willReturn( true );
|
$this->sut->method( 'is_remote_logging_allowed' )->willReturn( true );
|
||||||
|
|
||||||
// Set rate limit to simulate exceeded limit.
|
add_filter( 'woocommerce_remote_logger_formatted_log_data', fn() => null, 10, 4 );
|
||||||
WC_Rate_Limiter::set_rate_limit( RemoteLogger::RATE_LIMIT_ID, 10 );
|
add_filter( 'pre_http_request', fn() => $this->fail( 'wp_safe_remote_post should not be called' ), 10, 3 );
|
||||||
$result = $this->sut->handle( time(), 'error', 'Test message', array() );
|
|
||||||
$this->assertFalse( $result );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @testdox Test handle() method applies filter.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function test_handle_filtered_log_null() {
|
|
||||||
$this->sut = $this->getMockBuilder( RemoteLogger::class )
|
|
||||||
->onlyMethods( array( 'is_remote_logging_allowed' ) )
|
|
||||||
->getMock();
|
|
||||||
|
|
||||||
$this->sut->method( 'is_remote_logging_allowed' )->willReturn( true );
|
|
||||||
|
|
||||||
add_filter(
|
|
||||||
'woocommerce_remote_logger_formatted_log_data',
|
|
||||||
function ( $log_data, $level, $message, $context ) {
|
|
||||||
$this->assertEquals( 'Test message', $log_data['message'] );
|
|
||||||
$this->assertEquals( 'error', $level );
|
|
||||||
$this->assertEquals( 'Test message', $message );
|
|
||||||
$this->assertEquals( array(), $context );
|
|
||||||
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
10,
|
|
||||||
4
|
|
||||||
);
|
|
||||||
|
|
||||||
// Mock wp_safe_remote_post using pre_http_request filter.
|
|
||||||
add_filter(
|
|
||||||
'pre_http_request',
|
|
||||||
function () {
|
|
||||||
// assert not called.
|
|
||||||
$this->assertFalse( true );
|
|
||||||
},
|
|
||||||
10,
|
|
||||||
3
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->assertFalse( $this->sut->handle( time(), 'error', 'Test message', array() ) );
|
$this->assertFalse( $this->sut->handle( time(), 'error', 'Test message', array() ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @testdox Test handle() method does not send logs in dev environment
|
* @testdox handle method does not send logs in dev environment
|
||||||
*/
|
*/
|
||||||
public function test_handle_does_not_send_logs_in_dev_environment() {
|
public function test_handle_does_not_send_logs_in_dev_environment() {
|
||||||
$this->sut = $this->getMockBuilder( RemoteLoggerWithEnvironmentOverride::class )
|
$this->sut = $this->getMockBuilder( RemoteLoggerWithEnvironmentOverride::class )
|
||||||
->setMethods( array( 'is_remote_logging_allowed' ) )
|
->onlyMethods( array( 'is_remote_logging_allowed' ) )
|
||||||
->getMock();
|
->getMock();
|
||||||
|
|
||||||
$this->sut->set_is_dev_or_local( true );
|
$this->sut->set_is_dev_or_local( true );
|
||||||
$this->sut->method( 'is_remote_logging_allowed' )->willReturn( true );
|
$this->sut->method( 'is_remote_logging_allowed' )->willReturn( true );
|
||||||
$result = $this->sut->handle( time(), 'error', 'Test message', array() );
|
|
||||||
|
|
||||||
$this->assertFalse( $result, 'Handle should return false in dev environment' );
|
$this->assertFalse( $this->sut->handle( time(), 'error', 'Test message', array() ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @testdox Test handle() method successfully sends log.
|
* @testdox handle method successfully sends log
|
||||||
*/
|
*/
|
||||||
public function test_handle_successful() {
|
public function test_handle_successful() {
|
||||||
$this->sut = $this->getMockBuilder( RemoteLoggerWithEnvironmentOverride::class )
|
$this->sut = $this->getMockBuilder( RemoteLoggerWithEnvironmentOverride::class )
|
||||||
->setMethods( array( 'is_remote_logging_allowed' ) )
|
|
||||||
->getMock();
|
|
||||||
|
|
||||||
$this->sut->set_is_dev_or_local( false );
|
|
||||||
$this->sut->method( 'is_remote_logging_allowed' )->willReturn( true );
|
|
||||||
|
|
||||||
// Mock wp_safe_remote_post using pre_http_request filter.
|
|
||||||
add_filter(
|
|
||||||
'pre_http_request',
|
|
||||||
function ( $preempt, $args, $url ) { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed
|
|
||||||
$this->assertArrayHasKey( 'body', $args );
|
|
||||||
$this->assertArrayHasKey( 'headers', $args );
|
|
||||||
return array(
|
|
||||||
'response' => array(
|
|
||||||
'code' => 200,
|
|
||||||
'message' => 'OK',
|
|
||||||
),
|
|
||||||
'body' => wp_json_encode( array( 'success' => true ) ),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
10,
|
|
||||||
3
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->assertTrue( $this->sut->handle( time(), 'error', 'Test message', array() ) );
|
|
||||||
// Verify that rate limit was set.
|
|
||||||
$this->assertTrue( WC_Rate_Limiter::retried_too_soon( RemoteLogger::RATE_LIMIT_ID ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @testdox Test handle method when remote logging fails.
|
|
||||||
**/
|
|
||||||
public function test_handle_remote_logging_failure() {
|
|
||||||
$mock_local_logger = $this->createMock( \WC_Logger::class );
|
|
||||||
$mock_local_logger->expects( $this->once() )
|
|
||||||
->method( 'error' );
|
|
||||||
|
|
||||||
$this->sut = $this->getMockBuilder( RemoteLoggerWithEnvironmentOverride::class )
|
|
||||||
->setConstructorArgs( array( $mock_local_logger ) )
|
|
||||||
->onlyMethods( array( 'is_remote_logging_allowed' ) )
|
->onlyMethods( array( 'is_remote_logging_allowed' ) )
|
||||||
->getMock();
|
->getMock();
|
||||||
|
|
||||||
$this->sut->set_is_dev_or_local( false );
|
$this->sut->set_is_dev_or_local( false );
|
||||||
$this->sut->method( 'is_remote_logging_allowed' )->willReturn( true );
|
$this->sut->method( 'is_remote_logging_allowed' )->willReturn( true );
|
||||||
|
|
||||||
// Mock wp_safe_remote_post to throw an exception using pre_http_request filter.
|
add_filter(
|
||||||
|
'pre_http_request',
|
||||||
|
function ( $preempt, $args ) {
|
||||||
|
$this->assertArrayHasKey( 'body', $args );
|
||||||
|
$this->assertArrayHasKey( 'headers', $args );
|
||||||
|
return array(
|
||||||
|
'response' => array(
|
||||||
|
'code' => 200,
|
||||||
|
'message' => 'OK',
|
||||||
|
),
|
||||||
|
'body' => wp_json_encode( array( 'success' => true ) ),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
10,
|
||||||
|
3
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertTrue( $this->sut->handle( time(), 'critical', 'Test message', array() ) );
|
||||||
|
$this->assertTrue( WC_Rate_Limiter::retried_too_soon( RemoteLogger::RATE_LIMIT_ID ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @testdox handle method handles remote logging failure
|
||||||
|
*/
|
||||||
|
public function test_handle_remote_logging_failure() {
|
||||||
|
$this->sut = $this->getMockBuilder( RemoteLoggerWithEnvironmentOverride::class )
|
||||||
|
->onlyMethods( array( 'is_remote_logging_allowed' ) )
|
||||||
|
->getMock();
|
||||||
|
|
||||||
|
$this->sut->set_is_dev_or_local( false );
|
||||||
|
$this->sut->method( 'is_remote_logging_allowed' )->willReturn( true );
|
||||||
|
|
||||||
add_filter(
|
add_filter(
|
||||||
'pre_http_request',
|
'pre_http_request',
|
||||||
function ( $preempt, $args, $url ) {
|
function ( $preempt, $args, $url ) {
|
||||||
|
@ -464,94 +315,111 @@ class RemoteLoggerTest extends \WC_Unit_Test_Case {
|
||||||
3
|
3
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->assertFalse( $this->sut->handle( time(), 'error', 'Test message', array() ) );
|
$this->assertFalse( $this->sut->handle( time(), 'critical', 'Test message', array() ) );
|
||||||
// Verify that rate limit was set.
|
|
||||||
$this->assertTrue( WC_Rate_Limiter::retried_too_soon( RemoteLogger::RATE_LIMIT_ID ) );
|
$this->assertTrue( WC_Rate_Limiter::retried_too_soon( RemoteLogger::RATE_LIMIT_ID ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @testdox Test is_third_party_error method.
|
* @testdox is_third_party_error method correctly identifies third-party errors
|
||||||
*
|
* @dataProvider is_third_party_error_provider
|
||||||
* @dataProvider data_provider_for_is_third_party_error
|
* @param string $message The error message to check.
|
||||||
*
|
* @param array $context The context of the error.
|
||||||
* @param string $message Error message.
|
* @param bool $expected_result The expected result of the check.
|
||||||
* @param array $context Context.
|
|
||||||
* @param bool $expected_result Expected result.
|
|
||||||
*/
|
*/
|
||||||
public function test_is_third_party_error( $message, $context, $expected_result ) {
|
public function test_is_third_party_error( $message, $context, $expected_result ) {
|
||||||
$result = $this->invoke_private_method( $this->sut, 'is_third_party_error', array( $message, $context ) );
|
$result = $this->invoke_private_method( $this->sut, 'is_third_party_error', array( $message, $context ) );
|
||||||
|
|
||||||
$this->assertEquals( $expected_result, $result );
|
$this->assertEquals( $expected_result, $result );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Data provider for third party error test.
|
* Data provider for test_is_third_party_error.
|
||||||
*
|
*
|
||||||
* @return array
|
* @return array[] Test cases.
|
||||||
*/
|
*/
|
||||||
public function data_provider_for_is_third_party_error() {
|
public function is_third_party_error_provider() {
|
||||||
return array(
|
return array(
|
||||||
|
array( 'Fatal error in ' . WC_ABSPATH . 'file.php', array(), false ),
|
||||||
|
array( 'Fatal error in /wp-content/file.php', array(), false ),
|
||||||
|
array( 'Fatal error in /wp-content/file.php', array( 'source' => 'fatal-errors' ), false ),
|
||||||
array(
|
array(
|
||||||
'Fatal error occurred at line 123 in' . WC_ABSPATH . 'file.php',
|
'Fatal error in /wp-content/plugins/3rd-plugin/file.php',
|
||||||
array(),
|
|
||||||
false,
|
|
||||||
),
|
|
||||||
array(
|
|
||||||
'Fatal error occurred at line 123 in /home/user/path/wp-content/file.php',
|
|
||||||
array(),
|
|
||||||
false, // source is not.
|
|
||||||
),
|
|
||||||
array(
|
|
||||||
'Fatal error occurred at line 123 in /home/user/path/wp-content/file.php',
|
|
||||||
array( 'source' => 'fatal-errors' ),
|
|
||||||
false, // backtrace is not set.
|
|
||||||
),
|
|
||||||
array(
|
|
||||||
'Fatal error occurred at line 123 in /home/user/path/wp-content/plugins/3rd-plugin/file.php',
|
|
||||||
array(
|
array(
|
||||||
'source' => 'fatal-errors',
|
'source' => 'fatal-errors',
|
||||||
'backtrace' => array(
|
'backtrace' => array( '/wp-content/plugins/3rd-plugin/file.php', WC_ABSPATH . 'file.php' ),
|
||||||
'/home/user/path/wp-content/plugins/3rd-plugin/file.php',
|
|
||||||
WC_ABSPATH . 'file.php',
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
false,
|
false,
|
||||||
),
|
),
|
||||||
array(
|
array(
|
||||||
'Fatal error occurred at line 123 in /home/user/path/wp-content/plugins/woocommerce-3rd-plugin/file.php',
|
'Fatal error in /wp-content/plugins/woocommerce-3rd-plugin/file.php',
|
||||||
array(
|
array(
|
||||||
'source' => 'fatal-errors',
|
'source' => 'fatal-errors',
|
||||||
'backtrace' => array(
|
'backtrace' => array( WP_PLUGIN_DIR . 'woocommerce-3rd-plugin/file.php' ),
|
||||||
WP_PLUGIN_DIR . 'woocommerce-3rd-plugin/file.php',
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
true,
|
true,
|
||||||
),
|
),
|
||||||
array(
|
array(
|
||||||
'Fatal error occurred at line 123 in /home/user/path/wp-content/plugins/3rd-plugin/file.php',
|
'Fatal error in /wp-content/plugins/3rd-plugin/file.php',
|
||||||
array(
|
array(
|
||||||
'source' => 'fatal-errors',
|
'source' => 'fatal-errors',
|
||||||
'backtrace' => array(
|
'backtrace' => array( WP_PLUGIN_DIR . '3rd-plugin/file.php' ),
|
||||||
WP_PLUGIN_DIR . '3rd-plugin/file.php',
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
true,
|
true,
|
||||||
),
|
),
|
||||||
array(
|
array(
|
||||||
'Fatal error occurred at line 123 in /home/user/path/wp-content/plugins/3rd-plugin/file.php',
|
'Fatal error in /wp-content/plugins/3rd-plugin/file.php',
|
||||||
array(
|
array(
|
||||||
'source' => 'fatal-errors',
|
'source' => 'fatal-errors',
|
||||||
'backtrace' => array(
|
'backtrace' => array( array( 'file' => WP_PLUGIN_DIR . '3rd-plugin/file.php' ) ),
|
||||||
array(
|
|
||||||
'file' => WP_PLUGIN_DIR . '3rd-plugin/file.php',
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
true,
|
true,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @testdox sanitize method correctly sanitizes paths
|
||||||
|
*/
|
||||||
|
public function test_sanitize() {
|
||||||
|
$message = WC_ABSPATH . 'includes/class-wc-test.php on line 123';
|
||||||
|
$expected = '**/woocommerce/includes/class-wc-test.php on line 123';
|
||||||
|
$result = $this->invoke_private_method( $this->sut, 'sanitize', array( $message ) );
|
||||||
|
$this->assertEquals( $expected, $result );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @testdox sanitize_trace method correctly sanitizes stack traces
|
||||||
|
*/
|
||||||
|
public function test_sanitize_trace() {
|
||||||
|
$trace = array(
|
||||||
|
WC_ABSPATH . 'includes/class-wc-test.php:123',
|
||||||
|
ABSPATH . 'wp-includes/plugin.php:456',
|
||||||
|
);
|
||||||
|
$expected = "**/woocommerce/includes/class-wc-test.php:123\n**/wp-includes/plugin.php:456";
|
||||||
|
$result = $this->invoke_private_method( $this->sut, 'sanitize_trace', array( $trace ) );
|
||||||
|
$this->assertEquals( $expected, $result );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setup common conditions for remote logging tests.
|
||||||
|
*
|
||||||
|
* @param bool $enabled Whether remote logging is enabled.
|
||||||
|
*/
|
||||||
|
private function setup_remote_logging_conditions( $enabled = true ) {
|
||||||
|
update_option( 'woocommerce_feature_remote_logging_enabled', $enabled ? 'yes' : 'no' );
|
||||||
|
add_filter( 'option_woocommerce_allow_tracking', fn() => 'yes' );
|
||||||
|
add_filter( 'option_woocommerce_remote_variant_assignment', fn() => 5 );
|
||||||
|
add_filter(
|
||||||
|
'plugins_api',
|
||||||
|
function ( $result, $action, $args ) {
|
||||||
|
if ( 'plugin_information' === $action && 'woocommerce' === $args->slug ) {
|
||||||
|
return (object) array( 'version' => '9.2.0' );
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
},
|
||||||
|
10,
|
||||||
|
3
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper method to invoke private methods.
|
* Helper method to invoke private methods.
|
||||||
|
@ -570,7 +438,7 @@ class RemoteLoggerTest extends \WC_Unit_Test_Case {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//phpcs:disable Generic.Files.OneObjectStructurePerFile.MultipleFound, Squiz.Classes.ClassFileName.NoMatch
|
//phpcs:disable Generic.Files.OneObjectStructurePerFile.MultipleFound, Squiz.Classes.ClassFileName.NoMatch, Suin.Classes.PSR4.IncorrectClassName
|
||||||
/**
|
/**
|
||||||
* Mock class that extends RemoteLogger to allow overriding is_dev_or_local_environment.
|
* Mock class that extends RemoteLogger to allow overriding is_dev_or_local_environment.
|
||||||
*/
|
*/
|
||||||
|
@ -598,4 +466,4 @@ class RemoteLoggerWithEnvironmentOverride extends RemoteLogger {
|
||||||
return $this->is_dev_or_local;
|
return $this->is_dev_or_local;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//phpcs:enable Generic.Files.OneObjectStructurePerFile.MultipleFound, Squiz.Classes.ClassFileName.NoMatch
|
//phpcs:enable Generic.Files.OneObjectStructurePerFile.MultipleFound, Squiz.Classes.ClassFileName.NoMatch, Suin.Classes.PSR4.IncorrectClassName
|
||||||
|
|
Loading…
Reference in New Issue