d36bb954d1
Baseline before backporting wp-data-optimizer v3.0.1-v3.4.6. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TbG1keQQ7XBa7qMQY16KCY
143 lines
4.9 KiB
PHP
143 lines
4.9 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
use PHPUnit\Framework\TestCase;
|
|
|
|
if ( ! function_exists( 'is_email' ) ) {
|
|
function is_email( $v ): bool {
|
|
return is_string( $v ) && (bool) filter_var( $v, FILTER_VALIDATE_EMAIL );
|
|
}
|
|
}
|
|
if ( ! function_exists( 'wp_mail' ) ) {
|
|
function wp_mail( $to, $subject, $body, $headers = '', $attachments = array() ): bool {
|
|
$GLOBALS['_wpdo_mails'][] = compact( 'to', 'subject', 'body' );
|
|
return true;
|
|
}
|
|
}
|
|
if ( ! function_exists( 'sanitize_email' ) ) {
|
|
function sanitize_email( $v ): string {
|
|
return filter_var( (string) $v, FILTER_SANITIZE_EMAIL ) ?: '';
|
|
}
|
|
}
|
|
if ( ! function_exists( '__' ) ) {
|
|
function __( string $text, string $domain = 'default' ): string {
|
|
return $text;
|
|
}
|
|
}
|
|
if ( ! function_exists( 'home_url' ) ) {
|
|
function home_url( string $path = '/' ): string {
|
|
return 'https://example.test' . $path;
|
|
}
|
|
}
|
|
if ( ! function_exists( 'admin_url' ) ) {
|
|
function admin_url( string $path = '' ): string {
|
|
return 'https://example.test/wp-admin/' . ltrim( $path, '/' );
|
|
}
|
|
}
|
|
|
|
require_once dirname( __DIR__, 3 ) . '/includes/class-tmdo-logger.php';
|
|
require_once dirname( __DIR__, 3 ) . '/includes/notifications/class-tmdo-email-notifier.php';
|
|
|
|
/**
|
|
* Unit tests for WPDO_Email_Notifier (v2.4.0 M10).
|
|
*/
|
|
class EmailNotifierTest extends TestCase {
|
|
|
|
protected function setUp(): void {
|
|
$GLOBALS['_wp_options'] = array();
|
|
$GLOBALS['_wpdo_mails'] = array();
|
|
}
|
|
|
|
private function sample_summary( int $crit = 1 ): array {
|
|
return array(
|
|
'critical_count' => $crit,
|
|
'recommended_count' => 0,
|
|
'ran_at' => '2026-04-28 03:30:00',
|
|
'tests' => array(
|
|
'wpdo_schema_drift' => array(
|
|
'status' => 'critical',
|
|
'description' => 'Missing tables: wpdo_audit',
|
|
),
|
|
'wpdo_error_budget' => array(
|
|
'status' => 'good',
|
|
'description' => 'OK',
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
public function test_default_disabled(): void {
|
|
$this->assertFalse( WPDO_Email_Notifier::is_enabled() );
|
|
}
|
|
|
|
public function test_recipient_falls_back_to_admin_email(): void {
|
|
update_option( 'admin_email', 'admin@example.com', false );
|
|
$this->assertSame( 'admin@example.com', WPDO_Email_Notifier::recipient() );
|
|
|
|
update_option( 'wpdo_alert_email', 'alerts@example.com', false );
|
|
$this->assertSame( 'alerts@example.com', WPDO_Email_Notifier::recipient() );
|
|
}
|
|
|
|
public function test_throttle_hours_clamps_to_range(): void {
|
|
update_option( 'wpdo_alert_throttle_hours', 0, false );
|
|
$this->assertSame( 1, WPDO_Email_Notifier::throttle_hours() );
|
|
|
|
update_option( 'wpdo_alert_throttle_hours', 999, false );
|
|
$this->assertSame( 168, WPDO_Email_Notifier::throttle_hours() );
|
|
|
|
update_option( 'wpdo_alert_throttle_hours', 12, false );
|
|
$this->assertSame( 12, WPDO_Email_Notifier::throttle_hours() );
|
|
}
|
|
|
|
public function test_maybe_send_skips_when_disabled(): void {
|
|
$result = WPDO_Email_Notifier::maybe_send( $this->sample_summary() );
|
|
$this->assertFalse( $result );
|
|
$this->assertEmpty( $GLOBALS['_wpdo_mails'] );
|
|
}
|
|
|
|
public function test_maybe_send_sends_when_enabled(): void {
|
|
update_option( 'wpdo_email_alerts_enabled', '1', false );
|
|
update_option( 'wpdo_alert_email', 'ops@example.com', false );
|
|
|
|
$result = WPDO_Email_Notifier::maybe_send( $this->sample_summary() );
|
|
$this->assertTrue( $result );
|
|
$this->assertCount( 1, $GLOBALS['_wpdo_mails'] );
|
|
$mail = $GLOBALS['_wpdo_mails'][0];
|
|
$this->assertSame( 'ops@example.com', $mail['to'] );
|
|
$this->assertStringContainsString( 'wpdo_schema_drift', $mail['body'] );
|
|
$this->assertStringContainsString( 'WPDO 警告', $mail['subject'] );
|
|
}
|
|
|
|
public function test_maybe_send_throttle_dedupes_same_fingerprint(): void {
|
|
update_option( 'wpdo_email_alerts_enabled', '1', false );
|
|
update_option( 'wpdo_alert_email', 'ops@example.com', false );
|
|
$summary = $this->sample_summary();
|
|
|
|
$first = WPDO_Email_Notifier::maybe_send( $summary );
|
|
$second = WPDO_Email_Notifier::maybe_send( $summary );
|
|
$this->assertTrue( $first );
|
|
$this->assertFalse( $second, '同 fingerprint 第 2 次應 throttle' );
|
|
$this->assertCount( 1, $GLOBALS['_wpdo_mails'] );
|
|
}
|
|
|
|
public function test_maybe_send_skips_invalid_email(): void {
|
|
update_option( 'wpdo_email_alerts_enabled', '1', false );
|
|
update_option( 'wpdo_alert_email', 'not-an-email', false );
|
|
|
|
$result = WPDO_Email_Notifier::maybe_send( $this->sample_summary() );
|
|
$this->assertFalse( $result );
|
|
}
|
|
|
|
public function test_fingerprint_changes_with_critical_count(): void {
|
|
update_option( 'wpdo_email_alerts_enabled', '1', false );
|
|
update_option( 'wpdo_alert_email', 'ops@example.com', false );
|
|
|
|
$first = WPDO_Email_Notifier::maybe_send( $this->sample_summary( 1 ) );
|
|
// Different critical_count → different fingerprint → not throttled.
|
|
$second = WPDO_Email_Notifier::maybe_send( $this->sample_summary( 5 ) );
|
|
$this->assertTrue( $first );
|
|
$this->assertTrue( $second, '不同 critical_count 應視為不同警告' );
|
|
$this->assertCount( 2, $GLOBALS['_wpdo_mails'] );
|
|
}
|
|
}
|