Compare commits
2 Commits
fix/image-
...
refactor/s
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
49d094b4f8 | ||
|
|
7197249cab |
@@ -5,7 +5,7 @@ declare(strict_types=1);
|
|||||||
* Displays admin notices for onboarding, errors, and budget warnings.
|
* Displays admin notices for onboarding, errors, and budget warnings.
|
||||||
*
|
*
|
||||||
* Triggered by: PRAutoBlogger::register_admin_hooks() on `admin_notices`.
|
* Triggered by: PRAutoBlogger::register_admin_hooks() on `admin_notices`.
|
||||||
* Dependencies: PRAutoBlogger_Cost_Tracker (for budget warnings).
|
* Dependencies: PRAutoBlogger_Cost_Reporter (for budget warnings).
|
||||||
*
|
*
|
||||||
* @see class-prautoblogger.php — Registers the hook.
|
* @see class-prautoblogger.php — Registers the hook.
|
||||||
*/
|
*/
|
||||||
@@ -51,8 +51,8 @@ class PRAutoBlogger_Admin_Notices {
|
|||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
private function check_budget_notice(): void {
|
private function check_budget_notice(): void {
|
||||||
$cost_tracker = new PRAutoBlogger_Cost_Tracker();
|
$cost_reporter = new PRAutoBlogger_Cost_Reporter();
|
||||||
$utilization = $cost_tracker->get_budget_utilization();
|
$utilization = $cost_reporter->get_budget_utilization();
|
||||||
|
|
||||||
if ( $utilization >= 100.0 ) {
|
if ( $utilization >= 100.0 ) {
|
||||||
printf(
|
printf(
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ declare(strict_types=1);
|
|||||||
* and budget utilization.
|
* and budget utilization.
|
||||||
*
|
*
|
||||||
* Triggered by: Could be registered via wp_dashboard_setup hook.
|
* Triggered by: Could be registered via wp_dashboard_setup hook.
|
||||||
* Dependencies: PRAutoBlogger_Cost_Tracker.
|
* Dependencies: PRAutoBlogger_Cost_Reporter.
|
||||||
*
|
*
|
||||||
* @see class-prautoblogger.php — Can register this on wp_dashboard_setup.
|
* @see class-prautoblogger.php — Can register this on wp_dashboard_setup.
|
||||||
*/
|
*/
|
||||||
@@ -37,10 +37,10 @@ class PRAutoBlogger_Dashboard_Widget {
|
|||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function render_widget(): void {
|
public function render_widget(): void {
|
||||||
$cost_tracker = new PRAutoBlogger_Cost_Tracker();
|
$cost_reporter = new PRAutoBlogger_Cost_Reporter();
|
||||||
$monthly_spend = $cost_tracker->get_monthly_spend();
|
$monthly_spend = $cost_reporter->get_monthly_spend();
|
||||||
$budget = (float) get_option( 'prautoblogger_monthly_budget_usd', 50.00 );
|
$budget = (float) get_option( 'prautoblogger_monthly_budget_usd', 50.00 );
|
||||||
$utilization = $cost_tracker->get_budget_utilization();
|
$utilization = $cost_reporter->get_budget_utilization();
|
||||||
|
|
||||||
$next_run = wp_next_scheduled( 'prautoblogger_daily_generation' );
|
$next_run = wp_next_scheduled( 'prautoblogger_daily_generation' );
|
||||||
|
|
||||||
|
|||||||
141
includes/core/class-cost-reporter.php
Normal file
141
includes/core/class-cost-reporter.php
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides historical cost reporting and analysis methods.
|
||||||
|
*
|
||||||
|
* Extracted from PRAutoBlogger_Cost_Tracker, this class handles all read-only
|
||||||
|
* reporting queries: monthly spend, daily spend trends, spend-by-stage breakdowns,
|
||||||
|
* and budget utilization percentage.
|
||||||
|
*
|
||||||
|
* Called by: Metrics dashboard, admin notices, and dashboard widget.
|
||||||
|
* Dependencies: WordPress $wpdb, get_option() for budget configuration.
|
||||||
|
*
|
||||||
|
* @see core/class-cost-tracker.php — Complementary class for logging and budget enforcement.
|
||||||
|
* @see admin/class-metrics-page.php — Displays cost reports.
|
||||||
|
* @see admin/class-admin-notices.php — Shows budget warnings via get_budget_utilization().
|
||||||
|
* @see admin/class-dashboard-widget.php — Displays current month costs.
|
||||||
|
*/
|
||||||
|
class PRAutoBlogger_Cost_Reporter {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get total estimated spend for the current calendar month.
|
||||||
|
*
|
||||||
|
* @return float Total USD spend this month.
|
||||||
|
*/
|
||||||
|
public function get_monthly_spend(): float {
|
||||||
|
global $wpdb;
|
||||||
|
if ( null === $wpdb ) {
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
$table = $wpdb->prefix . 'prautoblogger_generation_log';
|
||||||
|
|
||||||
|
$first_of_month = gmdate( 'Y-m-01 00:00:00' );
|
||||||
|
|
||||||
|
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
|
||||||
|
$result = $wpdb->get_var(
|
||||||
|
$wpdb->prepare(
|
||||||
|
"SELECT COALESCE(SUM(estimated_cost), 0) FROM {$table} WHERE created_at >= %s AND response_status = 'success'",
|
||||||
|
$first_of_month
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return (float) $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get daily spend for the last N days (for the metrics dashboard chart).
|
||||||
|
*
|
||||||
|
* @param int $days Number of days to look back.
|
||||||
|
*
|
||||||
|
* @return array<string, float> Associative array of date => total_cost.
|
||||||
|
*/
|
||||||
|
public function get_daily_spend( int $days = 30 ): array {
|
||||||
|
global $wpdb;
|
||||||
|
if ( null === $wpdb ) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$table = $wpdb->prefix . 'prautoblogger_generation_log';
|
||||||
|
|
||||||
|
$start_date = gmdate( 'Y-m-d', time() - ( $days * DAY_IN_SECONDS ) );
|
||||||
|
|
||||||
|
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
|
||||||
|
$results = $wpdb->get_results(
|
||||||
|
$wpdb->prepare(
|
||||||
|
"SELECT DATE(created_at) as day, SUM(estimated_cost) as total_cost
|
||||||
|
FROM {$table}
|
||||||
|
WHERE created_at >= %s AND response_status = 'success'
|
||||||
|
GROUP BY DATE(created_at)
|
||||||
|
ORDER BY day ASC",
|
||||||
|
$start_date . ' 00:00:00'
|
||||||
|
),
|
||||||
|
ARRAY_A
|
||||||
|
);
|
||||||
|
|
||||||
|
$daily = [];
|
||||||
|
foreach ( ( $results ?: [] ) as $row ) {
|
||||||
|
$daily[ $row['day'] ] = (float) $row['total_cost'];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $daily;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get spend breakdown by pipeline stage for a given period.
|
||||||
|
*
|
||||||
|
* @param string $start_date Start date (Y-m-d).
|
||||||
|
* @param string $end_date End date (Y-m-d).
|
||||||
|
*
|
||||||
|
* @return array<string, array{cost: float, tokens: int, calls: int}> Breakdown by stage.
|
||||||
|
*/
|
||||||
|
public function get_spend_by_stage( string $start_date, string $end_date ): array {
|
||||||
|
global $wpdb;
|
||||||
|
if ( null === $wpdb ) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$table = $wpdb->prefix . 'prautoblogger_generation_log';
|
||||||
|
|
||||||
|
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
|
||||||
|
$results = $wpdb->get_results(
|
||||||
|
$wpdb->prepare(
|
||||||
|
"SELECT stage,
|
||||||
|
SUM(estimated_cost) as total_cost,
|
||||||
|
SUM(prompt_tokens + completion_tokens) as total_tokens,
|
||||||
|
COUNT(*) as call_count
|
||||||
|
FROM {$table}
|
||||||
|
WHERE created_at BETWEEN %s AND %s AND response_status = 'success'
|
||||||
|
GROUP BY stage",
|
||||||
|
$start_date . ' 00:00:00',
|
||||||
|
$end_date . ' 23:59:59'
|
||||||
|
),
|
||||||
|
ARRAY_A
|
||||||
|
);
|
||||||
|
|
||||||
|
$breakdown = [];
|
||||||
|
foreach ( ( $results ?: [] ) as $row ) {
|
||||||
|
$breakdown[ $row['stage'] ] = [
|
||||||
|
'cost' => (float) $row['total_cost'],
|
||||||
|
'tokens' => (int) $row['total_tokens'],
|
||||||
|
'calls' => (int) $row['call_count'],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $breakdown;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get budget utilization percentage for the current month.
|
||||||
|
*
|
||||||
|
* @return float Percentage (0-100+). Can exceed 100 if overspent.
|
||||||
|
*/
|
||||||
|
public function get_budget_utilization(): float {
|
||||||
|
$budget = (float) get_option( 'prautoblogger_monthly_budget_usd', 50.00 );
|
||||||
|
if ( $budget <= 0 ) {
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
return ( $this->get_monthly_spend() / $budget ) * 100.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,8 +2,7 @@
|
|||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tracks all API costs, enforces monthly budget limits, and provides
|
* Tracks all API costs and enforces monthly budget limits.
|
||||||
* cost reporting data for the admin dashboard.
|
|
||||||
*
|
*
|
||||||
* Every LLM API call in the plugin is logged through this class. The budget
|
* Every LLM API call in the plugin is logged through this class. The budget
|
||||||
* enforcement is a hard stop — if the monthly budget is exceeded, no further
|
* enforcement is a hard stop — if the monthly budget is exceeded, no further
|
||||||
@@ -16,7 +15,8 @@ declare(strict_types=1);
|
|||||||
* @see core/class-content-analyzer.php — Calls log_api_call() after analysis.
|
* @see core/class-content-analyzer.php — Calls log_api_call() after analysis.
|
||||||
* @see core/class-content-generator.php — Calls log_api_call() after each stage.
|
* @see core/class-content-generator.php — Calls log_api_call() after each stage.
|
||||||
* @see core/class-chief-editor.php — Calls log_api_call() after review.
|
* @see core/class-chief-editor.php — Calls log_api_call() after review.
|
||||||
* @see admin/class-metrics-page.php — Displays cost data from this class.
|
* @see core/class-cost-reporter.php — Extracted reporting methods (read-only queries).
|
||||||
|
* @see admin/class-metrics-page.php — Displays cost data via Cost_Reporter.
|
||||||
* @see ARCHITECTURE.md — prab_generation_log table schema.
|
* @see ARCHITECTURE.md — prab_generation_log table schema.
|
||||||
*/
|
*/
|
||||||
class PRAutoBlogger_Cost_Tracker {
|
class PRAutoBlogger_Cost_Tracker {
|
||||||
@@ -127,7 +127,8 @@ class PRAutoBlogger_Cost_Tracker {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$monthly_spend = $this->get_monthly_spend();
|
$reporter = new PRAutoBlogger_Cost_Reporter();
|
||||||
|
$monthly_spend = $reporter->get_monthly_spend();
|
||||||
|
|
||||||
// Round to 4 decimal places (0.01 cent precision) to avoid
|
// Round to 4 decimal places (0.01 cent precision) to avoid
|
||||||
// floating-point representation artifacts triggering false positives.
|
// floating-point representation artifacts triggering false positives.
|
||||||
@@ -189,32 +190,11 @@ class PRAutoBlogger_Cost_Tracker {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$projected = $this->get_monthly_spend() + $estimated_cost_usd;
|
$reporter = new PRAutoBlogger_Cost_Reporter();
|
||||||
|
$projected = $reporter->get_monthly_spend() + $estimated_cost_usd;
|
||||||
return round( $projected, 4 ) >= round( $budget, 4 );
|
return round( $projected, 4 ) >= round( $budget, 4 );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get total estimated spend for the current calendar month.
|
|
||||||
*
|
|
||||||
* @return float Total USD spend this month.
|
|
||||||
*/
|
|
||||||
public function get_monthly_spend(): float {
|
|
||||||
global $wpdb;
|
|
||||||
$table = $wpdb->prefix . 'prautoblogger_generation_log';
|
|
||||||
|
|
||||||
$first_of_month = gmdate( 'Y-m-01 00:00:00' );
|
|
||||||
|
|
||||||
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
|
|
||||||
$result = $wpdb->get_var(
|
|
||||||
$wpdb->prepare(
|
|
||||||
"SELECT COALESCE(SUM(estimated_cost), 0) FROM {$table} WHERE created_at >= %s AND response_status = 'success'",
|
|
||||||
$first_of_month
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
return (float) $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the cost accumulated during the current pipeline run.
|
* Get the cost accumulated during the current pipeline run.
|
||||||
*
|
*
|
||||||
@@ -223,91 +203,4 @@ class PRAutoBlogger_Cost_Tracker {
|
|||||||
public function get_current_run_cost(): float {
|
public function get_current_run_cost(): float {
|
||||||
return $this->current_run_cost;
|
return $this->current_run_cost;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get daily spend for the last N days (for the metrics dashboard chart).
|
|
||||||
*
|
|
||||||
* @param int $days Number of days to look back.
|
|
||||||
*
|
|
||||||
* @return array<string, float> Associative array of date => total_cost.
|
|
||||||
*/
|
|
||||||
public function get_daily_spend( int $days = 30 ): array {
|
|
||||||
global $wpdb;
|
|
||||||
$table = $wpdb->prefix . 'prautoblogger_generation_log';
|
|
||||||
|
|
||||||
$start_date = gmdate( 'Y-m-d', time() - ( $days * DAY_IN_SECONDS ) );
|
|
||||||
|
|
||||||
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
|
|
||||||
$results = $wpdb->get_results(
|
|
||||||
$wpdb->prepare(
|
|
||||||
"SELECT DATE(created_at) as day, SUM(estimated_cost) as total_cost
|
|
||||||
FROM {$table}
|
|
||||||
WHERE created_at >= %s AND response_status = 'success'
|
|
||||||
GROUP BY DATE(created_at)
|
|
||||||
ORDER BY day ASC",
|
|
||||||
$start_date . ' 00:00:00'
|
|
||||||
),
|
|
||||||
ARRAY_A
|
|
||||||
);
|
|
||||||
|
|
||||||
$daily = [];
|
|
||||||
foreach ( ( $results ?: [] ) as $row ) {
|
|
||||||
$daily[ $row['day'] ] = (float) $row['total_cost'];
|
|
||||||
}
|
|
||||||
|
|
||||||
return $daily;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get spend breakdown by pipeline stage for a given period.
|
|
||||||
*
|
|
||||||
* @param string $start_date Start date (Y-m-d).
|
|
||||||
* @param string $end_date End date (Y-m-d).
|
|
||||||
*
|
|
||||||
* @return array<string, array{cost: float, tokens: int, calls: int}> Breakdown by stage.
|
|
||||||
*/
|
|
||||||
public function get_spend_by_stage( string $start_date, string $end_date ): array {
|
|
||||||
global $wpdb;
|
|
||||||
$table = $wpdb->prefix . 'prautoblogger_generation_log';
|
|
||||||
|
|
||||||
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
|
|
||||||
$results = $wpdb->get_results(
|
|
||||||
$wpdb->prepare(
|
|
||||||
"SELECT stage,
|
|
||||||
SUM(estimated_cost) as total_cost,
|
|
||||||
SUM(prompt_tokens + completion_tokens) as total_tokens,
|
|
||||||
COUNT(*) as call_count
|
|
||||||
FROM {$table}
|
|
||||||
WHERE created_at BETWEEN %s AND %s AND response_status = 'success'
|
|
||||||
GROUP BY stage",
|
|
||||||
$start_date . ' 00:00:00',
|
|
||||||
$end_date . ' 23:59:59'
|
|
||||||
),
|
|
||||||
ARRAY_A
|
|
||||||
);
|
|
||||||
|
|
||||||
$breakdown = [];
|
|
||||||
foreach ( ( $results ?: [] ) as $row ) {
|
|
||||||
$breakdown[ $row['stage'] ] = [
|
|
||||||
'cost' => (float) $row['total_cost'],
|
|
||||||
'tokens' => (int) $row['total_tokens'],
|
|
||||||
'calls' => (int) $row['call_count'],
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
return $breakdown;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get budget utilization percentage for the current month.
|
|
||||||
*
|
|
||||||
* @return float Percentage (0-100+). Can exceed 100 if overspent.
|
|
||||||
*/
|
|
||||||
public function get_budget_utilization(): float {
|
|
||||||
$budget = (float) get_option( 'prautoblogger_monthly_budget_usd', 50.00 );
|
|
||||||
if ( $budget <= 0 ) {
|
|
||||||
return 0.0;
|
|
||||||
}
|
|
||||||
return ( $this->get_monthly_spend() / $budget ) * 100.0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,15 +9,15 @@ if ( ! defined( 'ABSPATH' ) ) {
|
|||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
$cost_tracker = new PRAutoBlogger_Cost_Tracker();
|
$cost_reporter = new PRAutoBlogger_Cost_Reporter();
|
||||||
$monthly_spend = $cost_tracker->get_monthly_spend();
|
$monthly_spend = $cost_reporter->get_monthly_spend();
|
||||||
$budget = (float) get_option( 'prautoblogger_monthly_budget_usd', 50.00 );
|
$budget = (float) get_option( 'prautoblogger_monthly_budget_usd', 50.00 );
|
||||||
$utilization = $cost_tracker->get_budget_utilization();
|
$utilization = $cost_reporter->get_budget_utilization();
|
||||||
$daily_spend = $cost_tracker->get_daily_spend( 30 );
|
$daily_spend = $cost_reporter->get_daily_spend( 30 );
|
||||||
|
|
||||||
$first_of_month = gmdate( 'Y-m-01' );
|
$first_of_month = gmdate( 'Y-m-01' );
|
||||||
$today = gmdate( 'Y-m-d' );
|
$today = gmdate( 'Y-m-d' );
|
||||||
$stage_breakdown = $cost_tracker->get_spend_by_stage( $first_of_month, $today );
|
$stage_breakdown = $cost_reporter->get_spend_by_stage( $first_of_month, $today );
|
||||||
?>
|
?>
|
||||||
<div class="wrap prautoblogger-metrics">
|
<div class="wrap prautoblogger-metrics">
|
||||||
<h1><?php esc_html_e( 'PRAutoBlogger — Metrics & Costs', 'prautoblogger' ); ?></h1>
|
<h1><?php esc_html_e( 'PRAutoBlogger — Metrics & Costs', 'prautoblogger' ); ?></h1>
|
||||||
|
|||||||
@@ -14,8 +14,8 @@ if ( ! defined( 'ABSPATH' ) ) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$active_tab = isset( $_GET['tab'] ) ? sanitize_key( $_GET['tab'] ) : 'prautoblogger_api';
|
$active_tab = isset( $_GET['tab'] ) ? sanitize_key( $_GET['tab'] ) : 'prautoblogger_api';
|
||||||
$cost_tracker = new PRAutoBlogger_Cost_Tracker();
|
$cost_reporter = new PRAutoBlogger_Cost_Reporter();
|
||||||
$monthly_spend = $cost_tracker->get_monthly_spend();
|
$monthly_spend = $cost_reporter->get_monthly_spend();
|
||||||
$budget = (float) get_option( 'prautoblogger_monthly_budget_usd', 50.00 );
|
$budget = (float) get_option( 'prautoblogger_monthly_budget_usd', 50.00 );
|
||||||
$utilization = $budget > 0 ? ( $monthly_spend / $budget ) * 100.0 : 0;
|
$utilization = $budget > 0 ? ( $monthly_spend / $budget ) * 100.0 : 0;
|
||||||
$next_run = wp_next_scheduled( 'prautoblogger_daily_generation' );
|
$next_run = wp_next_scheduled( 'prautoblogger_daily_generation' );
|
||||||
|
|||||||
93
tests/unit/Core/CostReporterTest.php
Normal file
93
tests/unit/Core/CostReporterTest.php
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Tests for PRAutoBlogger_Cost_Reporter.
|
||||||
|
*
|
||||||
|
* Validates monthly spend, daily spend trends, spend-by-stage breakdowns,
|
||||||
|
* and budget utilization reporting methods.
|
||||||
|
*
|
||||||
|
* @package PRAutoBlogger\Tests\Core
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace PRAutoBlogger\Tests\Core;
|
||||||
|
|
||||||
|
use PRAutoBlogger\Tests\BaseTestCase;
|
||||||
|
use Brain\Monkey\Functions;
|
||||||
|
|
||||||
|
class CostReporterTest extends BaseTestCase {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var \PHPUnit\Framework\MockObject\MockObject Mock $wpdb instance.
|
||||||
|
*/
|
||||||
|
private $wpdb;
|
||||||
|
|
||||||
|
protected function setUp(): void {
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
|
$this->wpdb = $this->create_mock_wpdb();
|
||||||
|
$GLOBALS['wpdb'] = $this->wpdb;
|
||||||
|
|
||||||
|
// CostReporter methods call get_option for budget settings.
|
||||||
|
$this->stub_get_option( [
|
||||||
|
'prautoblogger_monthly_budget_usd' => '50.00',
|
||||||
|
] );
|
||||||
|
|
||||||
|
// Stub current_time used in date-based queries.
|
||||||
|
$this->stub_current_time( '2026-04-12 10:00:00' );
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function tearDown(): void {
|
||||||
|
unset( $GLOBALS['wpdb'] );
|
||||||
|
parent::tearDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test get_monthly_spend returns float.
|
||||||
|
*/
|
||||||
|
public function test_get_monthly_spend_returns_float(): void {
|
||||||
|
$this->wpdb->method( 'prepare' )->willReturn( 'prepared' );
|
||||||
|
$this->wpdb->method( 'get_var' )->willReturn( '10.50' );
|
||||||
|
|
||||||
|
$reporter = new \PRAutoBlogger_Cost_Reporter();
|
||||||
|
$spend = $reporter->get_monthly_spend();
|
||||||
|
|
||||||
|
$this->assertIsFloat( $spend );
|
||||||
|
$this->assertGreaterThanOrEqual( 0.0, $spend );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test get_daily_spend returns array.
|
||||||
|
*/
|
||||||
|
public function test_get_daily_spend_returns_array(): void {
|
||||||
|
$this->wpdb->method( 'prepare' )->willReturn( 'prepared' );
|
||||||
|
$this->wpdb->method( 'get_results' )->willReturn( [] );
|
||||||
|
|
||||||
|
$reporter = new \PRAutoBlogger_Cost_Reporter();
|
||||||
|
$daily = $reporter->get_daily_spend( 30 );
|
||||||
|
|
||||||
|
$this->assertIsArray( $daily );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test get_spend_by_stage returns array.
|
||||||
|
*/
|
||||||
|
public function test_get_spend_by_stage_returns_array(): void {
|
||||||
|
$this->wpdb->method( 'prepare' )->willReturn( 'prepared' );
|
||||||
|
$this->wpdb->method( 'get_results' )->willReturn( [] );
|
||||||
|
|
||||||
|
$reporter = new \PRAutoBlogger_Cost_Reporter();
|
||||||
|
$spend = $reporter->get_spend_by_stage( '2026-04-01', '2026-04-30' );
|
||||||
|
|
||||||
|
$this->assertIsArray( $spend );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test get_budget_utilization returns float between 0 and 100+.
|
||||||
|
*/
|
||||||
|
public function test_get_budget_utilization_returns_float(): void {
|
||||||
|
$reporter = new \PRAutoBlogger_Cost_Reporter();
|
||||||
|
$utilization = $reporter->get_budget_utilization();
|
||||||
|
|
||||||
|
$this->assertIsFloat( $utilization );
|
||||||
|
$this->assertGreaterThanOrEqual( 0.0, $utilization );
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -68,20 +68,6 @@ class CostTrackerTest extends BaseTestCase {
|
|||||||
$this->assertFalse( $tracker->is_budget_exceeded() );
|
$this->assertFalse( $tracker->is_budget_exceeded() );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Test get_monthly_spend returns float.
|
|
||||||
*/
|
|
||||||
public function test_get_monthly_spend_returns_float(): void {
|
|
||||||
$this->wpdb->method( 'prepare' )->willReturn( 'prepared' );
|
|
||||||
$this->wpdb->method( 'get_var' )->willReturn( '10.50' );
|
|
||||||
|
|
||||||
$tracker = new \PRAutoBlogger_Cost_Tracker();
|
|
||||||
$spend = $tracker->get_monthly_spend();
|
|
||||||
|
|
||||||
$this->assertIsFloat( $spend );
|
|
||||||
$this->assertGreaterThanOrEqual( 0.0, $spend );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test get_current_run_cost returns float.
|
* Test get_current_run_cost returns float.
|
||||||
*/
|
*/
|
||||||
@@ -98,43 +84,6 @@ class CostTrackerTest extends BaseTestCase {
|
|||||||
$this->assertGreaterThanOrEqual( 0.0, $cost );
|
$this->assertGreaterThanOrEqual( 0.0, $cost );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Test get_daily_spend returns array.
|
|
||||||
*/
|
|
||||||
public function test_get_daily_spend_returns_array(): void {
|
|
||||||
$this->wpdb->method( 'prepare' )->willReturn( 'prepared' );
|
|
||||||
$this->wpdb->method( 'get_results' )->willReturn( [] );
|
|
||||||
|
|
||||||
$tracker = new \PRAutoBlogger_Cost_Tracker();
|
|
||||||
$daily = $tracker->get_daily_spend( 30 );
|
|
||||||
|
|
||||||
$this->assertIsArray( $daily );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test get_spend_by_stage returns array.
|
|
||||||
*/
|
|
||||||
public function test_get_spend_by_stage_returns_array(): void {
|
|
||||||
$this->wpdb->method( 'prepare' )->willReturn( 'prepared' );
|
|
||||||
$this->wpdb->method( 'get_results' )->willReturn( [] );
|
|
||||||
|
|
||||||
$tracker = new \PRAutoBlogger_Cost_Tracker();
|
|
||||||
$spend = $tracker->get_spend_by_stage( '2026-04-01', '2026-04-30' );
|
|
||||||
|
|
||||||
$this->assertIsArray( $spend );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test get_budget_utilization returns float between 0 and 1.
|
|
||||||
*/
|
|
||||||
public function test_get_budget_utilization_returns_float(): void {
|
|
||||||
$tracker = new \PRAutoBlogger_Cost_Tracker();
|
|
||||||
$utilization = $tracker->get_budget_utilization();
|
|
||||||
|
|
||||||
$this->assertIsFloat( $utilization );
|
|
||||||
$this->assertGreaterThanOrEqual( 0.0, $utilization );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test log_api_call with mock database.
|
* Test log_api_call with mock database.
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user