chore: initial snapshot of 2meet-data-optimizer v0.1.0
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
This commit is contained in:
@@ -0,0 +1,142 @@
|
||||
<?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'] );
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user