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
198 lines
8.3 KiB
PHP
198 lines
8.3 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
use PHPUnit\Framework\TestCase;
|
|
|
|
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, '/' ); }
|
|
}
|
|
if ( ! class_exists( 'WP_Error' ) ) {
|
|
class WP_Error {
|
|
public string $code;
|
|
public string $message;
|
|
public array $data;
|
|
public function __construct( string $code = '', string $message = '', $data = array() ) {
|
|
$this->code = $code;
|
|
$this->message = $message;
|
|
$this->data = (array) $data;
|
|
}
|
|
public function get_error_code(): string { return $this->code; }
|
|
public function get_error_message(): string { return $this->message; }
|
|
public function get_error_data() { return $this->data; }
|
|
}
|
|
}
|
|
if ( ! function_exists( 'is_wp_error' ) ) {
|
|
function is_wp_error( $thing ): bool { return $thing instanceof WP_Error; }
|
|
}
|
|
// Mock wp_remote_post — captures into $GLOBALS['_wpdo_remote_posts'] and returns simulated response.
|
|
if ( ! function_exists( 'wp_remote_post' ) ) {
|
|
function wp_remote_post( $url, $args = array() ) {
|
|
$GLOBALS['_wpdo_remote_posts'][] = array( 'url' => $url, 'args' => $args );
|
|
// Default 200 OK; test can override via $GLOBALS['_wpdo_remote_status'].
|
|
return array( 'response' => array( 'code' => $GLOBALS['_wpdo_remote_status'] ?? 200 ) );
|
|
}
|
|
}
|
|
if ( ! function_exists( 'wp_remote_retrieve_response_code' ) ) {
|
|
function wp_remote_retrieve_response_code( $resp ) {
|
|
return $resp['response']['code'] ?? 0;
|
|
}
|
|
}
|
|
|
|
require_once dirname( __DIR__, 3 ) . '/includes/class-tmdo-logger.php';
|
|
require_once dirname( __DIR__, 3 ) . '/includes/notifications/abstract-class-tmdo-notifier.php';
|
|
require_once dirname( __DIR__, 3 ) . '/includes/notifications/class-tmdo-slack-notifier.php';
|
|
require_once dirname( __DIR__, 3 ) . '/includes/notifications/class-tmdo-discord-notifier.php';
|
|
require_once dirname( __DIR__, 3 ) . '/includes/notifications/class-tmdo-telegram-notifier.php';
|
|
|
|
/**
|
|
* Unit tests for v2.5.0 M15 multi-channel notifiers.
|
|
*/
|
|
class MultiChannelNotifierTest extends TestCase {
|
|
|
|
protected function setUp(): void {
|
|
$GLOBALS['_wp_options'] = array();
|
|
$GLOBALS['_wpdo_remote_posts'] = array();
|
|
$GLOBALS['_wpdo_remote_status'] = 200;
|
|
}
|
|
|
|
private function summary(): array {
|
|
return array(
|
|
'critical_count' => 1,
|
|
'recommended_count' => 0,
|
|
'ran_at' => '2026-04-28 03:30:00',
|
|
'tests' => array(
|
|
'wpdo_schema_drift' => array(
|
|
'status' => 'critical',
|
|
'description' => 'Missing tables: wpdo_audit',
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
// ─── Slack ────────────────────────────────────────────────────────
|
|
|
|
public function test_slack_default_disabled(): void {
|
|
$this->assertFalse( WPDO_Slack_Notifier::is_enabled() );
|
|
}
|
|
|
|
public function test_slack_skips_send_when_disabled(): void {
|
|
$result = WPDO_Slack_Notifier::maybe_send( $this->summary() );
|
|
$this->assertFalse( $result );
|
|
$this->assertEmpty( $GLOBALS['_wpdo_remote_posts'] );
|
|
}
|
|
|
|
public function test_slack_skips_when_webhook_invalid(): void {
|
|
update_option( 'wpdo_slack_enabled', '1', false );
|
|
update_option( 'wpdo_slack_webhook', 'http://evil.com/wh', false );
|
|
$result = WPDO_Slack_Notifier::maybe_send( $this->summary() );
|
|
$this->assertFalse( $result );
|
|
}
|
|
|
|
public function test_slack_sends_with_valid_webhook(): void {
|
|
update_option( 'wpdo_slack_enabled', '1', false );
|
|
update_option( 'wpdo_slack_webhook', 'https://hooks.slack.com/services/T/B/X', false );
|
|
|
|
$result = WPDO_Slack_Notifier::maybe_send( $this->summary() );
|
|
$this->assertTrue( $result );
|
|
$this->assertCount( 1, $GLOBALS['_wpdo_remote_posts'] );
|
|
$captured = $GLOBALS['_wpdo_remote_posts'][0];
|
|
$this->assertSame( 'https://hooks.slack.com/services/T/B/X', $captured['url'] );
|
|
$payload = json_decode( (string) $captured['args']['body'], true );
|
|
$this->assertArrayHasKey( 'text', $payload );
|
|
$this->assertStringContainsString( 'WPDO 警告', $payload['text'] );
|
|
$this->assertStringContainsString( 'wpdo_schema_drift', $payload['text'] );
|
|
}
|
|
|
|
public function test_slack_throttle_dedupes(): void {
|
|
update_option( 'wpdo_slack_enabled', '1', false );
|
|
update_option( 'wpdo_slack_webhook', 'https://hooks.slack.com/services/T/B/X', false );
|
|
|
|
$first = WPDO_Slack_Notifier::maybe_send( $this->summary() );
|
|
$second = WPDO_Slack_Notifier::maybe_send( $this->summary() );
|
|
$this->assertTrue( $first );
|
|
$this->assertFalse( $second );
|
|
$this->assertCount( 1, $GLOBALS['_wpdo_remote_posts'] );
|
|
}
|
|
|
|
// ─── Discord ─────────────────────────────────────────────────────
|
|
|
|
public function test_discord_validates_webhook_prefix(): void {
|
|
update_option( 'wpdo_discord_enabled', '1', false );
|
|
update_option( 'wpdo_discord_webhook', 'https://attack.example.com/x', false );
|
|
$this->assertFalse( WPDO_Discord_Notifier::maybe_send( $this->summary() ) );
|
|
}
|
|
|
|
public function test_discord_sends_content_payload(): void {
|
|
update_option( 'wpdo_discord_enabled', '1', false );
|
|
update_option( 'wpdo_discord_webhook', 'https://discord.com/api/webhooks/123/abc', false );
|
|
|
|
$result = WPDO_Discord_Notifier::maybe_send( $this->summary() );
|
|
$this->assertTrue( $result );
|
|
$captured = $GLOBALS['_wpdo_remote_posts'][0];
|
|
$payload = json_decode( (string) $captured['args']['body'], true );
|
|
$this->assertArrayHasKey( 'content', $payload );
|
|
}
|
|
|
|
// ─── Telegram ────────────────────────────────────────────────────
|
|
|
|
public function test_telegram_skips_when_token_missing(): void {
|
|
update_option( 'wpdo_telegram_enabled', '1', false );
|
|
// No token / chat_id.
|
|
$this->assertFalse( WPDO_Telegram_Notifier::maybe_send( $this->summary() ) );
|
|
}
|
|
|
|
public function test_telegram_validates_token_format(): void {
|
|
update_option( 'wpdo_telegram_enabled', '1', false );
|
|
update_option( 'wpdo_telegram_bot_token', 'not_a_token', false );
|
|
update_option( 'wpdo_telegram_chat_id', '123', false );
|
|
$this->assertFalse( WPDO_Telegram_Notifier::maybe_send( $this->summary() ) );
|
|
}
|
|
|
|
public function test_telegram_sends_when_valid(): void {
|
|
update_option( 'wpdo_telegram_enabled', '1', false );
|
|
update_option( 'wpdo_telegram_bot_token', '123456:ABCDEFghijklmnopqrstuvwxyz0123456789', false );
|
|
update_option( 'wpdo_telegram_chat_id', '-1001234567890', false );
|
|
|
|
$result = WPDO_Telegram_Notifier::maybe_send( $this->summary() );
|
|
$this->assertTrue( $result );
|
|
$captured = $GLOBALS['_wpdo_remote_posts'][0];
|
|
$this->assertStringStartsWith( 'https://api.telegram.org/bot', $captured['url'] );
|
|
$payload = json_decode( (string) $captured['args']['body'], true );
|
|
$this->assertSame( '-1001234567890', $payload['chat_id'] );
|
|
$this->assertStringContainsString( '🚨', $payload['text'] );
|
|
}
|
|
|
|
// ─── Severity filter ─────────────────────────────────────────────
|
|
|
|
public function test_severity_critical_only_skips_when_no_critical(): void {
|
|
update_option( 'wpdo_slack_enabled', '1', false );
|
|
update_option( 'wpdo_slack_webhook', 'https://hooks.slack.com/services/T/B/X', false );
|
|
update_option( 'wpdo_slack_severity', 'critical_only', false );
|
|
|
|
$summary_recommended_only = array(
|
|
'critical_count' => 0,
|
|
'recommended_count' => 2,
|
|
'ran_at' => '2026-04-28 03:30:00',
|
|
'tests' => array(
|
|
'wpdo_error_budget' => array( 'status' => 'recommended', 'description' => 'too many errors' ),
|
|
),
|
|
);
|
|
|
|
$this->assertFalse( WPDO_Slack_Notifier::maybe_send( $summary_recommended_only ) );
|
|
}
|
|
|
|
// ─── Channel ID identity ────────────────────────────────────────
|
|
|
|
public function test_channel_ids(): void {
|
|
$this->assertSame( 'slack', WPDO_Slack_Notifier::channel_id() );
|
|
$this->assertSame( 'discord', WPDO_Discord_Notifier::channel_id() );
|
|
$this->assertSame( 'telegram', WPDO_Telegram_Notifier::channel_id() );
|
|
}
|
|
}
|