Logging: Improve compatibility with multisite (#44735)

* Add static method for getting the log directory

* Add filter for customizing the log directory path

* Handle case where constant is already defined

* Do directory creation on the fly instead of during install

* Replace all Core usages of WC_LOG_DIR

* Ensure each site's log handler setting is respected

* Add unit tests

* Fix legacy logger unit tests

* Update docs

* Regenerate docs manifest file (required by GitHub CI)

---------

Co-authored-by: Nestor Soriano <konamiman@konamiman.com>
This commit is contained in:
Corey McKrill 2024-02-28 03:31:31 -08:00 committed by GitHub
parent e1d83555a2
commit d581512171
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
21 changed files with 291 additions and 137 deletions

View File

@ -350,7 +350,7 @@
{
"post_title": "Logging in WooCommerce",
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/extension-development/logging.md",
"hash": "2cb0d0d594481127d144a95ccf8ca8ca826711dbf25a42fdc69a75c7d200d99f",
"hash": "7f5777df46d83e49b024ae205111e0a0960d8c53466d351a8744999d256cb0c0",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/extension-development/logging.md",
"id": "c684e2efba45051a4e1f98eb5e6ef6bab194f25c"
},
@ -916,11 +916,6 @@
],
"categories": []
},
{
"category_slug": "utilities",
"category_title": "Utilities",
"categories": []
},
{
"content": "\nThis section covers general guidelines, and best practices to follow in order to ensure your product experience aligns with WooCommerce for ease of use, seamless integration, and strong adoption.\n\nWe strongly recommend you review the current [WooCommerce setup experience](https://woo.com/documentation/plugins/woocommerce/getting-started/) to get familiar with the user experience and taxonomy.\n\nWe also recommend you review the [WordPress core guidelines](https://developer.wordpress.org/plugins/wordpress-org/detailed-plugin-guidelines/) to ensure your product isn't breaking any rules, and review [this helpful resource](https://woo.com/document/grammar-punctuation-style-guide/) on content style.\n\n## General\n\nUse existing WordPress/WooCommerce UI, built in components (text fields, checkboxes, etc) and existing menu structures.\n\nPlugins which draw on WordPress' core design aesthetic will benefit from future updates to this design as WordPress continues to evolve. If you need to make an exception for your product, be prepared to provide a valid use case.\n\n- [WordPress Components library](https://wordpress.github.io/gutenberg/?path=/story/docs-introduction--page)\n- [Figma for WordPress](https://make.wordpress.org/design/2018/11/19/figma-for-wordpress/) | ([WordPress Design Library Figma](https://www.figma.com/file/e4tLacmlPuZV47l7901FEs/WordPress-Design-Library))\n- [WooCommerce Component Library](https://woocommerce.github.io/woocommerce-admin/)\n",
"category_slug": "user-experience-extensions",
@ -1209,5 +1204,5 @@
"categories": []
}
],
"hash": "a485b51014a2262571751ae495976ca40aa8ffd4fddc7ee8ca8171ee51bd8984"
"hash": "2453d3ac64b6f1f4f4cd8efddfc166602f7182a9dff17218070fd2dccf8722e5"
}

View File

@ -48,7 +48,7 @@ Uncheck the box here to turn off all logging. This is not recommended in most ci
Out-of-the-box, WooCommerce has two different log storage methods available:
* **File system** - Log entries are recorded to files. Files are differentiated by the `source` value for the log entry (see the "Adding logs" section below), and by the current date. The files are stored in `wp-content/uploads/wc-logs`, but this can be changed by defining the `WC_LOG_DIR` constant in your `wp-config.php` file with a custom path. Log files can be up to 5 MB in size, after which the log file will rotate.
* **File system** - Log entries are recorded to files. Files are differentiated by the `source` value for the log entry (see the "Adding logs" section below), and by the current date. The files are stored in the `wc-logs` subdirectory of the site's `uploads` directory. A custom directory can be defined using the `woocommerce_log_directory` filter hook. Log files can be up to 5 MB in size, after which the log file will rotate.
* **Database** - Log entries are recorded to the database, in the `{$wpdb->prefix}woocommerce_log` table.
If you change this setting, and you already have some log entries, those entries will not be migrated to the other storage method, but neither will they be deleted.

View File

@ -0,0 +1,4 @@
Significance: minor
Type: update
Improve compatibility of the logging system with multisite

View File

@ -5,10 +5,14 @@
* @package WooCommerce\Admin\Logs
*/
use Automattic\WooCommerce\Utilities\LoggingUtil;
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
$log_directory = LoggingUtil::get_log_directory();
?>
<?php if ( $logs ) : ?>
<div id="log-viewer-select">
@ -25,7 +29,7 @@ if ( ! defined( 'ABSPATH' ) ) {
<select class="wc-enhanced-select" name="log_file">
<?php foreach ( $logs as $log_key => $log_file ) : ?>
<?php
$timestamp = filemtime( WC_LOG_DIR . $log_file );
$timestamp = filemtime( $log_directory . $log_file );
$date = sprintf(
/* translators: 1: last access date 2: last access time 3: last access timezone abbreviation */
__( '%1$s at %2$s %3$s', 'woocommerce' ),
@ -43,7 +47,7 @@ if ( ! defined( 'ABSPATH' ) ) {
<div class="clear"></div>
</div>
<div id="log-viewer">
<pre><?php echo esc_html( file_get_contents( WC_LOG_DIR . $viewed_log ) ); ?></pre>
<pre><?php echo esc_html( file_get_contents( $log_directory . $viewed_log ) ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents ?></pre>
</div>
<?php else : ?>
<div class="updated woocommerce-message inline"><p><?php esc_html_e( 'There are currently no logs to view.', 'woocommerce' ); ?></p></div>

View File

@ -120,8 +120,14 @@ $inactive_plugins_count = is_countable( $inactive_plugins ) ? count( $inactive_p
if ( $environment['log_directory_writable'] ) {
echo '<mark class="yes"><span class="dashicons dashicons-yes"></span> <code class="private">' . esc_html( $environment['log_directory'] ) . '</code></mark> ';
} else {
/* Translators: %1$s: Log directory, %2$s: Log directory constant */
echo '<mark class="error"><span class="dashicons dashicons-warning"></span> ' . sprintf( esc_html__( 'To allow logging, make %1$s writable or define a custom %2$s.', 'woocommerce' ), '<code>' . esc_html( $environment['log_directory'] ) . '</code>', '<code>WC_LOG_DIR</code>' ) . '</mark>';
printf(
'<mark class="error"><span class="dashicons dashicons-warning"></span> %s</mark>',
sprintf(
// Translators: %s: Log directory path.
esc_html__( 'To allow logging, make %s writable.', 'woocommerce' ),
'<code>' . esc_html( $environment['log_directory'] ) . '</code>'
)
);
}
?>
</td>

View File

@ -1876,16 +1876,6 @@ $hpos_table_schema;
'file' => 'index.html',
'content' => '',
),
array(
'base' => WC_LOG_DIR,
'file' => '.htaccess',
'content' => 'deny from all',
),
array(
'base' => WC_LOG_DIR,
'file' => 'index.html',
'content' => '',
),
array(
'base' => $upload_dir['basedir'] . '/woocommerce_uploads',
'file' => '.htaccess',

View File

@ -36,7 +36,24 @@ class WC_Logger implements WC_Logger_Interface {
* @param string $threshold Optional. Define an explicit threshold. May be configured via WC_LOG_THRESHOLD. By default, all logs will be processed.
*/
public function __construct( $handlers = null, $threshold = null ) {
if ( null === $handlers ) {
if ( is_array( $handlers ) ) {
$this->handlers = $handlers;
}
if ( is_string( $threshold ) ) {
$this->threshold = $threshold;
}
}
/**
* Get an array of log handler instances.
*
* @return WC_Log_Handler_Interface[]
*/
protected function get_handlers() {
if ( ! is_null( $this->handlers ) ) {
$handlers = $this->handlers;
} else {
$default_handler = LoggingUtil::get_default_handler();
$handler_instance = new $default_handler();
@ -50,12 +67,12 @@ class WC_Logger implements WC_Logger_Interface {
$handlers = apply_filters( 'woocommerce_register_log_handlers', array( $handler_instance ) );
}
$register_handlers = array();
$registered_handlers = array();
if ( ! empty( $handlers ) && is_array( $handlers ) ) {
foreach ( $handlers as $handler ) {
if ( $handler instanceof WC_Log_Handler_Interface ) {
$register_handlers[] = $handler;
$registered_handlers[] = $handler;
} else {
wc_doing_it_wrong(
__METHOD__,
@ -71,12 +88,22 @@ class WC_Logger implements WC_Logger_Interface {
}
}
return $registered_handlers;
}
/**
* Get the log threshold as a numerical level severity.
*
* @return int
*/
protected function get_threshold() {
$threshold = $this->threshold;
if ( ! WC_Log_Levels::is_valid_level( $threshold ) ) {
$threshold = LoggingUtil::get_level_threshold();
}
$this->handlers = $register_handlers;
$this->threshold = WC_Log_Levels::get_level_severity( $threshold );
return WC_Log_Levels::get_level_severity( $threshold );
}
/**
@ -90,11 +117,9 @@ class WC_Logger implements WC_Logger_Interface {
return false;
}
if ( null === $this->threshold ) {
return true;
}
$threshold = $this->get_threshold();
return $this->threshold <= WC_Log_Levels::get_level_severity( $level );
return $threshold <= WC_Log_Levels::get_level_severity( $level );
}
/**
@ -148,7 +173,7 @@ class WC_Logger implements WC_Logger_Interface {
if ( $this->should_handle( $level ) ) {
$timestamp = time();
foreach ( $this->handlers as $handler ) {
foreach ( $this->get_handlers() as $handler ) {
/**
* Filter the logging message. Returning null will prevent logging from occurring since 5.3.
*
@ -296,11 +321,13 @@ class WC_Logger implements WC_Logger_Interface {
if ( ! $source ) {
return false;
}
foreach ( $this->handlers as $handler ) {
foreach ( $this->get_handlers() as $handler ) {
if ( is_callable( array( $handler, 'clear' ) ) ) {
$handler->clear( $source );
}
}
return true;
}
@ -313,7 +340,7 @@ class WC_Logger implements WC_Logger_Interface {
$days = LoggingUtil::get_retention_period();
$timestamp = strtotime( "-{$days} days" );
foreach ( $this->handlers as $handler ) {
foreach ( $this->get_handlers() as $handler ) {
if ( is_callable( array( $handler, 'delete_logs_before_timestamp' ) ) ) {
$handler->delete_logs_before_timestamp( $timestamp );
}

View File

@ -23,7 +23,7 @@ use Automattic\WooCommerce\Internal\Settings\OptionSanitizer;
use Automattic\WooCommerce\Internal\Utilities\WebhookUtil;
use Automattic\WooCommerce\Internal\Admin\Marketplace;
use Automattic\WooCommerce\Proxies\LegacyProxy;
use Automattic\WooCommerce\Utilities\TimeUtil;
use Automattic\WooCommerce\Utilities\{ LoggingUtil, TimeUtil };
/**
* Main WooCommerce Class.
@ -366,10 +366,19 @@ final class WooCommerce {
$this->define( 'WC_DISCOUNT_ROUNDING_MODE', 2 );
$this->define( 'WC_TAX_ROUNDING_MODE', 'yes' === get_option( 'woocommerce_prices_include_tax', 'no' ) ? 2 : 1 );
$this->define( 'WC_DELIMITER', '|' );
$this->define( 'WC_LOG_DIR', $upload_dir['basedir'] . '/wc-logs/' );
$this->define( 'WC_SESSION_CACHE_GROUP', 'wc_session_id' );
$this->define( 'WC_TEMPLATE_DEBUG_MODE', false );
/**
* As of 8.8.0, it is preferable to use the `woocommerce_log_directory` filter hook to change the log
* directory. WC_LOG_DIR_CUSTOM is a back-compatibility measure so we can tell if `WC_LOG_DIR` has been
* defined outside of WC Core.
*/
if ( defined( 'WC_LOG_DIR' ) ) {
$this->define( 'WC_LOG_DIR_CUSTOM', true );
}
$this->define( 'WC_LOG_DIR', LoggingUtil::get_log_directory() );
// These three are kept defined for compatibility, but are no longer used.
$this->define( 'WC_NOTICE_MIN_PHP_VERSION', '7.2' );
$this->define( 'WC_NOTICE_MIN_WP_VERSION', '5.2' );

View File

@ -6,6 +6,7 @@
*/
use Automattic\Jetpack\Constants;
use Automattic\WooCommerce\Utilities\LoggingUtil;
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
@ -251,13 +252,14 @@ class WC_Log_Handler_File extends WC_Log_Handler {
* @return bool
*/
public function remove( $handle ) {
$removed = false;
$logs = $this->get_log_files();
$handle = sanitize_title( $handle );
$removed = false;
$logs = $this->get_log_files();
$log_directory = LoggingUtil::get_log_directory();
$handle = sanitize_title( $handle );
if ( isset( $logs[ $handle ] ) && $logs[ $handle ] ) {
$file = realpath( trailingslashit( WC_LOG_DIR ) . $logs[ $handle ] );
if ( 0 === stripos( $file, realpath( trailingslashit( WC_LOG_DIR ) ) ) && is_file( $file ) && is_writable( $file ) ) { // phpcs:ignore WordPress.VIP.FileSystemWritesDisallow.file_ops_is_writable
$file = realpath( trailingslashit( $log_directory ) . $logs[ $handle ] );
if ( 0 === stripos( $file, realpath( trailingslashit( $log_directory ) ) ) && is_file( $file ) && is_writable( $file ) ) { // phpcs:ignore WordPress.VIP.FileSystemWritesDisallow.file_ops_is_writable
$this->close( $file ); // Close first to be certain no processes keep it alive after it is unlinked.
$removed = unlink( $file ); // phpcs:ignore WordPress.VIP.FileSystemWritesDisallow.file_ops_unlink
}
@ -349,8 +351,10 @@ class WC_Log_Handler_File extends WC_Log_Handler {
* @return bool|string The log file path or false if path cannot be determined.
*/
public static function get_log_file_path( $handle ) {
$log_directory = LoggingUtil::get_log_directory();
if ( function_exists( 'wp_hash' ) ) {
return trailingslashit( WC_LOG_DIR ) . self::get_log_file_name( $handle );
return trailingslashit( $log_directory ) . self::get_log_file_name( $handle );
} else {
wc_doing_it_wrong( __METHOD__, __( 'This method should not be called before plugins_loaded.', 'woocommerce' ), '3.0' );
return false;
@ -410,13 +414,14 @@ class WC_Log_Handler_File extends WC_Log_Handler {
return;
}
$log_files = self::get_log_files();
$log_files = self::get_log_files();
$log_directory = LoggingUtil::get_log_directory();
foreach ( $log_files as $log_file ) {
$last_modified = filemtime( trailingslashit( WC_LOG_DIR ) . $log_file );
$last_modified = filemtime( trailingslashit( $log_directory ) . $log_file );
if ( $last_modified < $timestamp ) {
@unlink( trailingslashit( WC_LOG_DIR ) . $log_file ); // @codingStandardsIgnoreLine.
@unlink( trailingslashit( $log_directory ) . $log_file ); // @codingStandardsIgnoreLine.
}
}
}
@ -428,7 +433,9 @@ class WC_Log_Handler_File extends WC_Log_Handler {
* @return array
*/
public static function get_log_files() {
$files = @scandir( WC_LOG_DIR ); // @codingStandardsIgnoreLine.
$log_directory = LoggingUtil::get_log_directory();
$files = @scandir( $log_directory ); // @codingStandardsIgnoreLine.
$result = array();
if ( ! empty( $files ) ) {

View File

@ -870,6 +870,7 @@ class WC_REST_System_Status_V2_Controller extends WC_REST_Controller {
}
$database_version = wc_get_server_database_version();
$log_directory = LoggingUtil::get_log_directory();
// Return all environment info. Described by JSON Schema.
return array(
@ -877,8 +878,8 @@ class WC_REST_System_Status_V2_Controller extends WC_REST_Controller {
'site_url' => get_option( 'siteurl' ),
'store_id' => get_option( \WC_Install::STORE_ID_OPTION, null ),
'version' => WC()->version,
'log_directory' => WC_LOG_DIR,
'log_directory_writable' => (bool) @fopen( WC_LOG_DIR . 'test-log.log', 'a' ), // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged, WordPress.WP.AlternativeFunctions.file_system_read_fopen
'log_directory' => $log_directory,
'log_directory_writable' => wp_is_writable( $log_directory ),
'wp_version' => get_bloginfo( 'version' ),
'wp_multisite' => is_multisite(),
'wp_memory_limit' => $wp_memory_limit,

View File

@ -1156,7 +1156,7 @@ function wc_register_default_log_handler( $handlers = array() ) {
function wc_get_log_file_path( $handle ) {
wc_deprecated_function( 'wc_get_log_file_path', '8.6.0' );
$directory = trailingslashit( realpath( Constants::get_constant( 'WC_LOG_DIR' ) ) );
$directory = LoggingUtil::get_log_directory();
$file_id = LoggingUtil::generate_log_file_id( $handle, null, time() );
$hash = LoggingUtil::generate_log_file_hash( $file_id );

View File

@ -4,6 +4,7 @@ declare( strict_types = 1 );
namespace Automattic\WooCommerce\Internal\Admin\Logging\FileV2;
use Automattic\Jetpack\Constants;
use Automattic\WooCommerce\Internal\Admin\Logging\Settings;
use PclZip;
use WC_Cache_Helper;
use WP_Error;
@ -75,20 +76,6 @@ class FileController {
*/
private const SEARCH_CACHE_KEY = 'logs_previous_search';
/**
* The absolute path to the log directory.
*
* @var string
*/
private $log_directory;
/**
* Class FileController
*/
public function __construct() {
$this->log_directory = trailingslashit( Constants::get_constant( 'WC_LOG_DIR' ) );
}
/**
* Get the file size limit that determines when to rotate a file.
*
@ -141,7 +128,7 @@ class FileController {
}
if ( ! $file instanceof File ) {
$new_path = $this->log_directory . $this->generate_filename( $source, $time );
$new_path = Settings::get_log_directory() . $this->generate_filename( $source, $time );
$file = new File( $new_path );
}
@ -217,7 +204,7 @@ class FileController {
$args = wp_parse_args( $args, self::DEFAULTS_GET_FILES );
$pattern = $args['source'] . '*.log';
$paths = glob( $this->log_directory . $pattern );
$paths = glob( Settings::get_log_directory() . $pattern );
if ( false === $paths ) {
return new WP_Error(
@ -332,14 +319,15 @@ class FileController {
* @return File[]
*/
public function get_files_by_id( array $file_ids ): array {
$paths = array();
$log_directory = Settings::get_log_directory();
$paths = array();
foreach ( $file_ids as $file_id ) {
// Look for the standard filename format first, which includes a hash.
$glob = glob( $this->log_directory . $file_id . '-*.log' );
$glob = glob( $log_directory . $file_id . '-*.log' );
if ( ! $glob ) {
$glob = glob( $this->log_directory . $file_id . '.log' );
$glob = glob( $log_directory . $file_id . '.log' );
}
if ( is_array( $glob ) ) {
@ -423,7 +411,7 @@ class FileController {
$created_pattern = $created ? '-' . gmdate( 'Y-m-d', $created ) . '-' : '';
$rotation_pattern = $this->log_directory . $source . $rotations_pattern . $created_pattern . '*.log';
$rotation_pattern = Settings::get_log_directory() . $source . $rotations_pattern . $created_pattern . '*.log';
$rotation_paths = glob( $rotation_pattern );
$rotation_files = $this->convert_paths_to_objects( $rotation_paths );
foreach ( $rotation_files as $rotation_file ) {
@ -462,7 +450,7 @@ class FileController {
* @return array|WP_Error
*/
public function get_file_sources() {
$paths = glob( $this->log_directory . '*.log' );
$paths = glob( Settings::get_log_directory() . '*.log' );
if ( false === $paths ) {
return new WP_Error(
'wc_log_directory_error',
@ -671,7 +659,7 @@ class FileController {
*/
public function get_log_directory_size(): int {
$bytes = 0;
$path = realpath( $this->log_directory );
$path = realpath( Settings::get_log_directory() );
if ( wp_is_writable( $path ) ) {
$iterator = new \RecursiveIteratorIterator( new \RecursiveDirectoryIterator( $path, \FilesystemIterator::SKIP_DOTS ) );

View File

@ -8,8 +8,10 @@ use Automattic\WooCommerce\Internal\Admin\Logging\FileV2\File;
use Automattic\WooCommerce\Internal\Admin\Logging\LogHandlerFileV2;
use Automattic\WooCommerce\Internal\Admin\Logging\FileV2\FileController;
use Automattic\WooCommerce\Internal\Traits\AccessiblePrivateMethods;
use Automattic\WooCommerce\Proxies\LegacyProxy;
use WC_Admin_Settings;
use WC_Log_Handler_DB, WC_Log_Handler_File, WC_Log_Levels;
use WP_Filesystem_Base;
/**
* Settings class.
@ -44,6 +46,52 @@ class Settings {
self::add_action( 'wc_logs_load_tab', array( $this, 'save_settings' ) );
}
/**
* Get the directory for storing log files.
*
* The `wp_upload_dir` function takes into account the possibility of multisite, and handles changing
* the directory if the context is switched to a different site in the network mid-request.
*
* @return string The full directory path, with trailing slash.
*/
public static function get_log_directory(): string {
if ( true === Constants::get_constant( 'WC_LOG_DIR_CUSTOM' ) ) {
$dir = Constants::get_constant( 'WC_LOG_DIR' );
} else {
$upload_dir = wc_get_container()->get( LegacyProxy::class )->call_function( 'wp_upload_dir' );
/**
* Filter to change the directory for storing WooCommerce's log files.
*
* @param string $dir The full directory path, with trailing slash.
*
* @since 8.8.0
*/
$dir = apply_filters( 'woocommerce_log_directory', $upload_dir['basedir'] . '/wc-logs/' );
}
$dir = trailingslashit( $dir );
$realpath = realpath( $dir );
if ( false === $realpath ) {
$result = wp_mkdir_p( $dir );
if ( true === $result ) {
// Create infrastructure to prevent listing contents of the logs directory.
require_once ABSPATH . 'wp-admin/includes/file.php';
global $wp_filesystem;
if ( ! $wp_filesystem instanceof WP_Filesystem_Base ) {
WP_Filesystem();
}
$wp_filesystem->put_contents( $dir . '.htaccess', 'deny from all' );
$wp_filesystem->put_contents( $dir . 'index.html', '' );
}
}
return $dir;
}
/**
* The definitions used by WC_Admin_Settings to render and save settings controls.
*
@ -242,7 +290,7 @@ class Settings {
*/
private function get_filesystem_settings_definitions(): array {
$location_info = array();
$directory = trailingslashit( Constants::get_constant( 'WC_LOG_DIR' ) );
$directory = self::get_log_directory();
$location_info[] = sprintf(
// translators: %s is a location in the filesystem.
@ -257,13 +305,6 @@ class Settings {
$location_info[] = __( '⚠️ This directory does not appear to be writable.', 'woocommerce' );
}
$location_info[] = sprintf(
// translators: %1$s is a code variable. %2$s is the name of a file.
__( 'Change the location by defining the %1$s constant in your %2$s file with a new path.', 'woocommerce' ),
'<code>WC_LOG_DIR</code>',
'<code>wp-config.php</code>'
);
$location_info[] = sprintf(
// translators: %s is an amount of computer disk space, e.g. 5 KB.
__( 'Directory size: %s', 'woocommerce' ),

View File

@ -83,6 +83,15 @@ final class LoggingUtil {
return File::generate_hash( $file_id );
}
/**
* Get the directory for storing log files.
*
* @return string The full directory path, with trailing slash.
*/
public static function get_log_directory(): string {
return Settings::get_log_directory();
}
/**
* Calculate the size, in bytes, of the log directory.
*

View File

@ -5,6 +5,8 @@
* @package WooCommerce\Tests
*/
use Automattic\WooCommerce\Utilities\LoggingUtil;
/**
* Class WC_Tests_Log_Handler_File
* @package WooCommerce\Tests\Log
@ -224,7 +226,7 @@ class WC_Tests_Log_Handler_File extends WC_Unit_Test_Case {
* @since 3.0.0
*/
public function test_get_log_file_path() {
$log_dir = trailingslashit( WC_LOG_DIR );
$log_dir = LoggingUtil::get_log_directory();
$date_suffix = gmdate( 'Y-m-d', time() );
$hash_name = sanitize_file_name( wp_hash( 'unit-tests' ) );
$this->assertEquals( $log_dir . 'unit-tests-' . $date_suffix . '-' . $hash_name . '.log', WC_Log_Handler_File::get_log_file_path( 'unit-tests' ) );

View File

@ -6,6 +6,7 @@
*/
use Automattic\Jetpack\Constants;
use Automattic\WooCommerce\Internal\Admin\Logging\Settings;
/**
* Class WC_Tests_Logger
@ -39,7 +40,7 @@ class WC_Tests_Logger extends WC_Unit_Test_Case {
* @return void
*/
private static function delete_all_log_files(): void {
$files = glob( trailingslashit( realpath( Constants::get_constant( 'WC_LOG_DIR' ) ) ) . '*.log' );
$files = glob( Settings::get_log_directory() . '*.log' );
foreach ( $files as $file ) {
unlink( $file );
}
@ -81,7 +82,7 @@ class WC_Tests_Logger extends WC_Unit_Test_Case {
* @since 2.4
*/
public function test_clear() {
$path = trailingslashit( realpath( Constants::get_constant( 'WC_LOG_DIR' ) ) ) . 'unit-tests.log';
$path = Settings::get_log_directory() . 'unit-tests.log';
// phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_file_put_contents
file_put_contents( $path, 'Test file content.' );
$this->assertFileExists( $path );
@ -184,7 +185,7 @@ class WC_Tests_Logger extends WC_Unit_Test_Case {
*/
public function test_woocommerce_register_log_handlers_filter() {
add_filter( 'woocommerce_register_log_handlers', array( $this, 'return_assertion_handlers' ) );
$log = new WC_Logger( null, 'debug' );
$log = new WC_Logger();
$log->debug( 'debug' );
$log->info( 'info' );
$log->notice( 'notice' );
@ -252,8 +253,9 @@ class WC_Tests_Logger extends WC_Unit_Test_Case {
->setMethods( array( 'handle' ) )
->getMock();
$handler->expects( $this->never() )->method( 'handle' );
new WC_Logger( array( $handler ) );
$this->setExpectedIncorrectUsage( 'WC_Logger::__construct' );
$logger = new WC_Logger( array( $handler ) );
$logger->debug( 'debug' );
$this->setExpectedIncorrectUsage( 'WC_Logger::get_handlers' );
}
/**
@ -267,11 +269,15 @@ class WC_Tests_Logger extends WC_Unit_Test_Case {
* @return WC_Log_Handler[] array of mocked handlers.
*/
public function return_assertion_handlers() {
$handler = $this
->getMockBuilder( 'WC_Log_Handler_Interface' )
->setMethods( array( 'handle' ) )
->getMock();
$handler->expects( $this->exactly( 8 ) )->method( 'handle' );
static $handler;
if ( ! $handler instanceof WC_Log_Handler_Interface ) {
$handler = $this
->getMockBuilder( 'WC_Log_Handler_Interface' )
->setMethods( array( 'handle' ) )
->getMock();
$handler->expects( $this->exactly( 8 ) )->method( 'handle' );
}
return array( $handler );
}

View File

@ -284,7 +284,7 @@ class WC_Tests_Core_Functions extends WC_Unit_Test_Case {
public function test_wc_get_log_file_path() {
$this->setExpectedDeprecated( 'wc_get_log_file_path' );
$log_dir = trailingslashit( WC_LOG_DIR );
$log_dir = LoggingUtil::get_log_directory();
$hash_name = sanitize_file_name( wp_hash( 'unit-tests' ) );
$file_id = LoggingUtil::generate_log_file_id( 'unit-tests', null, time() );
$hash = LoggingUtil::generate_log_file_hash( $file_id );

View File

@ -4,7 +4,7 @@ declare( strict_types = 1 );
namespace Automattic\WooCommerce\Tests\Internal\Admin\Logging\FileV2;
use Automattic\Jetpack\Constants;
use Automattic\WooCommerce\Internal\Admin\Logging\LogHandlerFileV2;
use Automattic\WooCommerce\Internal\Admin\Logging\{ LogHandlerFileV2, Settings };
use Automattic\WooCommerce\Internal\Admin\Logging\FileV2\{ File, FileController };
use WC_Unit_Test_Case;
@ -66,7 +66,7 @@ class FileControllerTest extends WC_Unit_Test_Case {
* @return void
*/
private static function delete_all_log_files(): void {
$files = glob( trailingslashit( realpath( Constants::get_constant( 'WC_LOG_DIR' ) ) ) . '*.log' );
$files = glob( Settings::get_log_directory() . '*.log' );
foreach ( $files as $file ) {
unlink( $file );
}
@ -82,7 +82,7 @@ class FileControllerTest extends WC_Unit_Test_Case {
$result = $this->sut->write_to_file( $source, $content );
$this->assertTrue( $result );
$paths = glob( trailingslashit( realpath( Constants::get_constant( 'WC_LOG_DIR' ) ) ) . '*.log' );
$paths = glob( Settings::get_log_directory() . '*.log' );
$this->assertCount( 1, $paths );
$path = reset( $paths );
@ -108,12 +108,12 @@ class FileControllerTest extends WC_Unit_Test_Case {
'other2' => 'unit-testing-' . gmdate( 'Y-m-d', strtotime( '-2 days' ) ) . '-' . $hash . '.log',
);
foreach ( $existing_files as $filename ) {
$path = Constants::get_constant( 'WC_LOG_DIR' ) . $filename;
$path = Settings::get_log_directory() . $filename;
$resource = fopen( $path, 'a' );
fclose( $resource );
}
$paths = glob( trailingslashit( realpath( Constants::get_constant( 'WC_LOG_DIR' ) ) ) . '*.log' );
$paths = glob( Settings::get_log_directory() . '*.log' );
$this->assertCount( 3, $paths );
$source = 'unit-testing';
@ -122,10 +122,10 @@ class FileControllerTest extends WC_Unit_Test_Case {
$result = $this->sut->write_to_file( $source, $content, $time );
$this->assertTrue( $result );
$paths = glob( trailingslashit( realpath( Constants::get_constant( 'WC_LOG_DIR' ) ) ) . '*.log' );
$paths = glob( Settings::get_log_directory() . '*.log' );
$this->assertCount( 3, $paths );
$target_path = Constants::get_constant( 'WC_LOG_DIR' ) . $existing_files['target'];
$target_path = Settings::get_log_directory() . $existing_files['target'];
// phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
$actual_content = file_get_contents( $target_path );
$this->assertEquals( $content . "\n", $actual_content );
@ -136,7 +136,7 @@ class FileControllerTest extends WC_Unit_Test_Case {
*/
public function test_write_to_file_needs_rotation() {
$time = time();
$path = Constants::get_constant( 'WC_LOG_DIR' ) . 'unit-testing-' . gmdate( 'Y-m-d', $time ) . '-' . wp_hash( 'cheddar' ) . '.log';
$path = Settings::get_log_directory() . 'unit-testing-' . gmdate( 'Y-m-d', $time ) . '-' . wp_hash( 'cheddar' ) . '.log';
$resource = fopen( $path, 'a' );
$existing_content = random_bytes( 200 ) . "\n";
@ -144,7 +144,7 @@ class FileControllerTest extends WC_Unit_Test_Case {
fwrite( $resource, $existing_content );
fclose( $resource );
$paths = glob( trailingslashit( realpath( Constants::get_constant( 'WC_LOG_DIR' ) ) ) . '*.log' );
$paths = glob( Settings::get_log_directory() . '*.log' );
$this->assertCount( 1, $paths );
// Set the file size low to induce log rotation.
@ -157,7 +157,7 @@ class FileControllerTest extends WC_Unit_Test_Case {
$result = $this->sut->write_to_file( $source, $new_content, $time );
$this->assertTrue( $result );
$paths = glob( trailingslashit( realpath( Constants::get_constant( 'WC_LOG_DIR' ) ) ) . '*.log' );
$paths = glob( Settings::get_log_directory() . '*.log' );
$this->assertCount( 2, $paths );
foreach ( $paths as $path ) {
@ -248,7 +248,7 @@ class FileControllerTest extends WC_Unit_Test_Case {
public function test_get_files_by_id() {
// Create a log file with an accompanying rotation.
$this->handler->handle( time(), 'debug', '1', array( 'source' => 'unit-testing1' ) );
$file1_path = glob( Constants::get_constant( 'WC_LOG_DIR' ) . '*.log' );
$file1_path = glob( Settings::get_log_directory() . '*.log' );
$file1 = new File( reset( $file1_path ) );
$file1->rotate();
$this->handler->handle( time(), 'debug', '1', array( 'source' => 'unit-testing1' ) );
@ -297,8 +297,8 @@ class FileControllerTest extends WC_Unit_Test_Case {
* @testdox The get_file_rotations method should return an associative array of File instances.
*/
public function test_get_file_rotations() {
$target_file_path = Constants::get_constant( 'WC_LOG_DIR' ) . 'test-file.log';
$other_file_path = Constants::get_constant( 'WC_LOG_DIR' ) . 'other-test-file.log';
$target_file_path = Settings::get_log_directory() . 'test-file.log';
$other_file_path = Settings::get_log_directory() . 'other-test-file.log';
$oldest_file = new File( $target_file_path );
$oldest_file->write( 'test' );
@ -315,7 +315,7 @@ class FileControllerTest extends WC_Unit_Test_Case {
$other_file = new File( $other_file_path );
$other_file->write( 'test' );
$paths = glob( trailingslashit( realpath( Constants::get_constant( 'WC_LOG_DIR' ) ) ) . '*.log' );
$paths = glob( Settings::get_log_directory() . '*.log' );
$this->assertCount( 4, $paths );
$file_id = 'test-file';
@ -415,17 +415,17 @@ class FileControllerTest extends WC_Unit_Test_Case {
*/
public function test_get_log_directory_size(): void {
// Non-log files that should be in the log directory.
$htaccess = wp_filesize( Constants::get_constant( 'WC_LOG_DIR' ) . '.htaccess' );
$index = wp_filesize( Constants::get_constant( 'WC_LOG_DIR' ) . 'index.html' );
$htaccess = wp_filesize( Settings::get_log_directory() . '.htaccess' );
$index = wp_filesize( Settings::get_log_directory() . 'index.html' );
$path = Constants::get_constant( 'WC_LOG_DIR' ) . 'unit-testing-1.log';
$path = Settings::get_log_directory() . 'unit-testing-1.log';
$resource = fopen( $path, 'a' );
$existing_content = random_bytes( 200 );
// phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_fwrite
fwrite( $resource, $existing_content );
fclose( $resource );
$path = Constants::get_constant( 'WC_LOG_DIR' ) . 'unit-testing-2.log';
$path = Settings::get_log_directory() . 'unit-testing-2.log';
$resource = fopen( $path, 'a' );
$existing_content = random_bytes( 300 );
// phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_fwrite

View File

@ -5,6 +5,7 @@ namespace Automattic\WooCommerce\Tests\Internal\Admin\Logging\FileV2;
use Automattic\Jetpack\Constants;
use Automattic\WooCommerce\Internal\Admin\Logging\FileV2\File;
use Automattic\WooCommerce\Internal\Admin\Logging\Settings;
use WC_Unit_Test_Case;
// phpcs:disable WordPress.WP.AlternativeFunctions.file_system_read_fopen, WordPress.WP.AlternativeFunctions.file_system_read_fclose
@ -20,7 +21,7 @@ class FileTest extends WC_Unit_Test_Case {
*/
public function tearDown(): void {
// Delete all created files and directories.
$files = glob( trailingslashit( realpath( Constants::get_constant( 'WC_LOG_DIR' ) ) ) . '*' );
$files = glob( Settings::get_log_directory() . '*' );
foreach ( $files as $file ) {
if ( is_dir( $file ) ) {
rmdir( $file );
@ -41,7 +42,7 @@ class FileTest extends WC_Unit_Test_Case {
$hash = wp_hash( 'cheddar' );
yield 'standard filename, no rotation' => array(
Constants::get_constant( 'WC_LOG_DIR' ) . 'test-Source_1-1-2023-10-23-' . $hash . '.log',
Settings::get_log_directory() . 'test-Source_1-1-2023-10-23-' . $hash . '.log',
array(
'basename' => 'test-Source_1-1-2023-10-23-' . $hash . '.log',
'source' => 'test-Source_1-1',
@ -52,7 +53,7 @@ class FileTest extends WC_Unit_Test_Case {
),
);
yield 'standard filename, with rotation' => array(
Constants::get_constant( 'WC_LOG_DIR' ) . 'test-Source_1-1.3-2023-10-23-' . $hash . '.log',
Settings::get_log_directory() . 'test-Source_1-1.3-2023-10-23-' . $hash . '.log',
array(
'basename' => 'test-Source_1-1.3-2023-10-23-' . $hash . '.log',
'source' => 'test-Source_1-1',
@ -63,7 +64,7 @@ class FileTest extends WC_Unit_Test_Case {
),
);
yield 'non-standard filename, no rotation' => array(
Constants::get_constant( 'WC_LOG_DIR' ) . 'test-Source_1-1-' . $hash . '.log',
Settings::get_log_directory() . 'test-Source_1-1-' . $hash . '.log',
array(
'basename' => 'test-Source_1-1-' . $hash . '.log',
'source' => 'test-Source_1-1-' . $hash,
@ -74,7 +75,7 @@ class FileTest extends WC_Unit_Test_Case {
),
);
yield 'non-standard filename, with rotation' => array(
Constants::get_constant( 'WC_LOG_DIR' ) . 'test-Source_1-1-' . $hash . '.5.log',
Settings::get_log_directory() . 'test-Source_1-1-' . $hash . '.5.log',
array(
'basename' => 'test-Source_1-1-' . $hash . '.5.log',
'source' => 'test-Source_1-1-' . $hash,
@ -145,7 +146,7 @@ class FileTest extends WC_Unit_Test_Case {
* and whether the file is readable and writable.
*/
public function test_file_readable_writable() {
$filename = Constants::get_constant( 'WC_LOG_DIR' ) . 'test-file.log';
$filename = Settings::get_log_directory() . 'test-file.log';
$file = new File( $filename );
$this->assertFalse( $file->is_readable() );
@ -162,7 +163,7 @@ class FileTest extends WC_Unit_Test_Case {
* @testdox Check that writing to a file that doesn't exist yet creates that file.
*/
public function test_write_new_file() {
$filename = Constants::get_constant( 'WC_LOG_DIR' ) . 'test-file.log';
$filename = Settings::get_log_directory() . 'test-file.log';
$content = "You can't take the sky from me";
$file = new File( $filename );
@ -183,7 +184,7 @@ class FileTest extends WC_Unit_Test_Case {
* @testdox Check that writing to a file that already exists appends the new content to the existing content.
*/
public function test_write_existing_file() {
$filename = Constants::get_constant( 'WC_LOG_DIR' ) . 'test-file.log';
$filename = Settings::get_log_directory() . 'test-file.log';
$content1 = 'Shiny';
$content2 = 'Scratch';
@ -212,8 +213,8 @@ class FileTest extends WC_Unit_Test_Case {
* @testdox Check that the has_standard_filename method correctly identifies standard and nonstandard filenames.
*/
public function test_has_standard_filename() {
$standard = Constants::get_constant( 'WC_LOG_DIR' ) . 'test-Source_1-1.3-2023-10-23-' . wp_hash( 'cheddar' ) . '.log';
$nonstandard = Constants::get_constant( 'WC_LOG_DIR' ) . 'test-Source_1-1-' . wp_hash( 'cheddar' ) . '.5.log';
$standard = Settings::get_log_directory() . 'test-Source_1-1.3-2023-10-23-' . wp_hash( 'cheddar' ) . '.log';
$nonstandard = Settings::get_log_directory() . 'test-Source_1-1-' . wp_hash( 'cheddar' ) . '.5.log';
$file = new File( $standard );
$this->assertTrue( $file->has_standard_filename() );
@ -226,7 +227,7 @@ class FileTest extends WC_Unit_Test_Case {
* @testdox Check that get_stream returns a PHP resource representation of the file.
*/
public function test_get_and_close_stream() {
$filename = Constants::get_constant( 'WC_LOG_DIR' ) . 'test-file.log';
$filename = Settings::get_log_directory() . 'test-file.log';
$file = new File( $filename );
// File doesn't exist yet.
@ -248,7 +249,7 @@ class FileTest extends WC_Unit_Test_Case {
* @testdox Check that rotating a file without a rotation market will rename it to include a rotation marker.
*/
public function test_rotate_current_file() {
$filename = Constants::get_constant( 'WC_LOG_DIR' ) . 'test-file.log';
$filename = Settings::get_log_directory() . 'test-file.log';
$file = new File( $filename );
$file->write( 'test' );
@ -272,7 +273,7 @@ class FileTest extends WC_Unit_Test_Case {
* @testdox Check that rotating a file with a rotation market will rename it to increment the rotation marker.
*/
public function test_rotate_older_file() {
$filename = Constants::get_constant( 'WC_LOG_DIR' ) . 'test-file.2.log';
$filename = Settings::get_log_directory() . 'test-file.2.log';
$file = new File( $filename );
$file->write( 'test' );
@ -296,19 +297,19 @@ class FileTest extends WC_Unit_Test_Case {
* @testdox The delete method should delete the file from the filesystem.
*/
public function test_delete_existing_file() {
$filename = Constants::get_constant( 'WC_LOG_DIR' ) . 'test-file.log';
$filename = Settings::get_log_directory() . 'test-file.log';
$file = new File( $filename );
$file->write( 'test' );
$this->assertTrue( $file->is_readable() );
$files = glob( trailingslashit( realpath( Constants::get_constant( 'WC_LOG_DIR' ) ) ) . '*.log' );
$files = glob( Settings::get_log_directory() . '*.log' );
$this->assertCount( 1, $files );
$result = $file->delete();
$this->assertTrue( $result );
$this->assertFalse( $file->is_readable() );
$files = glob( trailingslashit( realpath( Constants::get_constant( 'WC_LOG_DIR' ) ) ) . '*.log' );
$files = glob( Settings::get_log_directory() . '*.log' );
$this->assertCount( 0, $files );
}
}

View File

@ -4,7 +4,7 @@ declare( strict_types = 1 );
namespace Automattic\WooCommerce\Tests\Internal\Admin\Logging;
use Automattic\Jetpack\Constants;
use Automattic\WooCommerce\Internal\Admin\Logging\LogHandlerFileV2;
use Automattic\WooCommerce\Internal\Admin\Logging\{ LogHandlerFileV2, Settings };
use Automattic\WooCommerce\Internal\Admin\Logging\FileV2\File;
use WC_Unit_Test_Case;
@ -56,7 +56,7 @@ class LogHandlerFileV2Test extends WC_Unit_Test_Case {
* @return void
*/
private static function delete_all_log_files(): void {
$files = glob( trailingslashit( realpath( Constants::get_constant( 'WC_LOG_DIR' ) ) ) . '*.log' );
$files = glob( Settings::get_log_directory() . '*.log' );
foreach ( $files as $file ) {
unlink( $file );
}
@ -110,7 +110,7 @@ class LogHandlerFileV2Test extends WC_Unit_Test_Case {
$input['context']
);
$paths = glob( trailingslashit( realpath( Constants::get_constant( 'WC_LOG_DIR' ) ) ) . '*.log' );
$paths = glob( Settings::get_log_directory() . '*.log' );
$this->assertCount( 1, $paths );
$parsed = File::parse_path( reset( $paths ) );
@ -138,7 +138,7 @@ MESSAGE;
array()
);
$paths = glob( trailingslashit( realpath( Constants::get_constant( 'WC_LOG_DIR' ) ) ) . '*.log' );
$paths = glob( Settings::get_log_directory() . '*.log' );
$this->assertCount( 1, $paths );
// phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
@ -239,7 +239,7 @@ MESSAGE;
$input,
);
$paths = glob( trailingslashit( realpath( Constants::get_constant( 'WC_LOG_DIR' ) ) ) . '*.log' );
$paths = glob( Settings::get_log_directory() . '*.log' );
$this->assertCount( 1, $paths );
// phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
@ -258,16 +258,16 @@ MESSAGE;
$this->sut->handle( strtotime( '-4 days' ), 'debug', 'duck', array( 'source' => 'duck' ) );
$this->sut->handle( time(), 'debug', 'goose', array( 'source' => 'goose' ) );
$paths = glob( trailingslashit( realpath( Constants::get_constant( 'WC_LOG_DIR' ) ) ) . '*.log' );
$paths = glob( Settings::get_log_directory() . '*.log' );
$this->assertCount( 4, $paths );
$result = $this->sut->clear( 'duck' );
$this->assertEquals( 3, $result );
$paths = glob( trailingslashit( realpath( Constants::get_constant( 'WC_LOG_DIR' ) ) ) . '*.log' );
$paths = glob( Settings::get_log_directory() . '*.log' );
$this->assertCount( 2, $paths ); // New log gets created when old logs are deleted!
$paths = glob( trailingslashit( realpath( Constants::get_constant( 'WC_LOG_DIR' ) ) ) . 'wc_logger*.log' );
$paths = glob( Settings::get_log_directory() . 'wc_logger*.log' );
$this->assertCount( 1, $paths );
// phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
@ -290,16 +290,16 @@ MESSAGE;
$this->sut->handle( $current_time, 'debug', 'new!', array( 'source' => 'source5' ) );
$this->sut->handle( $current_time, 'debug', 'new!', array( 'source' => 'source6' ) );
$paths = glob( trailingslashit( realpath( Constants::get_constant( 'WC_LOG_DIR' ) ) ) . '*.log' );
$paths = glob( Settings::get_log_directory() . '*.log' );
$this->assertCount( 6, $paths );
$result = $this->sut->delete_logs_before_timestamp( strtotime( '-3 days' ) );
$this->assertEquals( 4, $result );
$paths = glob( trailingslashit( realpath( Constants::get_constant( 'WC_LOG_DIR' ) ) ) . '*.log' );
$paths = glob( Settings::get_log_directory() . '*.log' );
$this->assertCount( 3, $paths ); // New log gets created when old logs are deleted!
$paths = glob( trailingslashit( realpath( Constants::get_constant( 'WC_LOG_DIR' ) ) ) . 'wc_logger*.log' );
$paths = glob( Settings::get_log_directory() . 'wc_logger*.log' );
$this->assertCount( 1, $paths );
// phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents

View File

@ -73,12 +73,76 @@ class SettingsTest extends WC_Unit_Test_Case {
* @return void
*/
private static function delete_all_log_files(): void {
$files = glob( trailingslashit( realpath( Constants::get_constant( 'WC_LOG_DIR' ) ) ) . '*.log' );
$upload_dir = wp_upload_dir( null, false );
$log_directory = $upload_dir['basedir'] . '/wc-logs/';
$files = glob( $log_directory . '*.log' );
foreach ( $files as $file ) {
unlink( $file );
}
}
/**
* @testdox Check that the get_log_directory method returns the correct directory path.
*/
public function test_get_log_directory_path(): void {
Constants::set_constant( 'WC_LOG_DIR_CUSTOM', true );
Constants::set_constant( 'WC_LOG_DIR', '/a/test/path/constant' );
$actual = Settings::get_log_directory();
$this->assertEquals( '/a/test/path/constant/', $actual );
Constants::clear_constants();
$callback = fn() => '/a/test/path/filter';
add_filter( 'woocommerce_log_directory', $callback );
$actual = Settings::get_log_directory();
$this->assertEquals( '/a/test/path/filter/', $actual );
remove_filter( 'woocommerce_log_directory', $callback );
$this->register_legacy_proxy_function_mocks(
array(
'wp_upload_dir' => fn() => array( 'basedir' => '/a/test/path' ),
)
);
$actual = Settings::get_log_directory();
$this->assertEquals( '/a/test/path/wc-logs/', $actual );
$this->reset_legacy_proxy_mocks();
}
/**
* @testdox Check that the get_log_directory method creates the directory if it doesn't exist yet.
*/
public function test_get_log_directory_creation() {
$upload_dir = wp_upload_dir();
$path = $upload_dir['basedir'] . '/wc-logs-test/';
$this->assertFalse( wp_is_writable( $path ) );
$callback = fn() => $path;
add_filter( 'woocommerce_log_directory', $callback );
$actual_path = Settings::get_log_directory();
$this->assertEquals( $path, $actual_path );
$this->assertTrue( wp_is_writable( $actual_path ) );
remove_filter( 'woocommerce_log_directory', $callback );
// The GLOB_BRACE flag is not available in some environments.
$files = array_merge(
glob( $path . '*' ),
glob( $path . '.[!.,!..]*' )
);
$this->assertCount( 2, $files );
$this->assertContains( $path . '.htaccess', $files );
$this->assertContains( $path . 'index.html', $files );
foreach ( $files as $file ) {
unlink( $file );
}
rmdir( $path );
}
/**
* @testdox Check that log entries can be recorded while logging is enabled.
*/