File: /home/xedaptot/ai.naniguide.com/tests/Unit/Sending/SendMetricsRecorderTest.php
<?php
/**
* SendMetricsRecorderTest — verifies the per-message timing accumulator
* computes the right averages and writes the expected debug() shape.
*
* The recorder is purely arithmetic over recorded timestamps, plus one
* Campaign::debug(closure) flush at the end. The campaign mock records what
* the closure produces so we can assert the persisted dict shape.
*/
use App\Library\Sending\Metrics\SendMetricsRecorder;
use App\Library\Sending\SendContext;
use App\Model\Campaign;
use App\Model\Subscriber;
use Tests\TestCase;
uses(TestCase::class);
it('flushes a single debug() write with averages computed against the previous count', function () {
$stored = null;
$campaign = Mockery::mock(Campaign::class);
$campaign->shouldReceive('getAttribute')->with('uid')->andReturn('camp-uid');
$campaign->shouldReceive('debug')->once()->andReturnUsing(function ($callback) use (&$stored) {
// Simulate the cache-backed dict starting from a previous send having recorded count=2 with 1.0s avg.
$stored = $callback([
'start_at' => now()->subMinute()->toString(),
'send_message_count' => 2,
'send_message_avg_time' => 1.0,
'send_message_prepare_avg_time' => 0.5,
'send_message_lock_avg_time' => 0.1,
'send_message_delivery_avg_time' => 0.4,
'send_message_min_time' => 1.0,
'send_message_max_time' => 1.0,
]);
return $stored;
});
$subscriber = Mockery::mock(Subscriber::class);
$subscriber->shouldReceive('getEmail')->andReturn('[email protected]');
$ctx = new SendContext(campaign: $campaign, subscriber: $subscriber, servers: null);
$recorder = new SendMetricsRecorder();
$recorder->markPreparingDone();
$recorder->markGotLock();
$recorder->markComposed();
$recorder->markDelivered();
$recorder->flush($ctx);
expect($stored)->toBeArray();
expect($stored['send_message_count'])->toBe(3); // incremented from 2
expect($stored['send_message_avg_time'])->toBeFloat();
expect($stored['last_message_sent_at'])->toBeString();
expect($stored['last_activity_at'])->toBeString();
expect($stored['messages_sent_per_second'])->toBeFloat();
});
it('initialises averages on the first flush (count=0 -> first sample becomes the avg)', function () {
$stored = null;
$campaign = Mockery::mock(Campaign::class);
$campaign->shouldReceive('getAttribute')->with('uid')->andReturn('camp-uid');
$campaign->shouldReceive('debug')->andReturnUsing(function ($callback) use (&$stored) {
$stored = $callback([
'start_at' => null,
'send_message_count' => 0,
'send_message_avg_time' => null,
'send_message_prepare_avg_time' => null,
'send_message_lock_avg_time' => null,
'send_message_delivery_avg_time' => null,
'send_message_min_time' => null,
'send_message_max_time' => null,
]);
return $stored;
});
$subscriber = Mockery::mock(Subscriber::class);
$subscriber->shouldReceive('getEmail')->andReturn('[email protected]');
$ctx = new SendContext(campaign: $campaign, subscriber: $subscriber, servers: null);
$recorder = new SendMetricsRecorder();
$recorder->markPreparingDone();
$recorder->markGotLock();
$recorder->markComposed();
$recorder->markDelivered();
$recorder->flush($ctx);
expect($stored['send_message_count'])->toBe(1);
expect($stored['send_message_avg_time'])->not->toBeNull();
expect($stored['send_message_min_time'])->toBe($stored['send_message_max_time']);
});
it('flushes safely when no marks were called (degraded path: missed all timestamps)', function () {
$stored = null;
$campaign = Mockery::mock(Campaign::class);
$campaign->shouldReceive('getAttribute')->with('uid')->andReturn('camp-uid');
$campaign->shouldReceive('debug')->andReturnUsing(function ($callback) use (&$stored) {
$stored = $callback([
'start_at' => null,
'send_message_count' => 0,
'send_message_avg_time' => null,
'send_message_prepare_avg_time' => null,
'send_message_lock_avg_time' => null,
'send_message_delivery_avg_time' => null,
'send_message_min_time' => null,
'send_message_max_time' => null,
]);
return $stored;
});
$subscriber = Mockery::mock(Subscriber::class);
$subscriber->shouldReceive('getEmail')->andReturn('[email protected]');
$ctx = new SendContext(campaign: $campaign, subscriber: $subscriber, servers: null);
(new SendMetricsRecorder())->flush($ctx);
expect($stored)->toBeArray();
expect($stored['send_message_count'])->toBe(1);
});