File: /home/xedaptot/ai.naniguide.com/tests/Unit/RemoteSubscription/RemoteSyncCommandTest.php
<?php
namespace Tests\Unit\RemoteSubscription;
use Tests\TestCase;
use Mockery;
use App\Library\DTOs\RemoteSyncResult;
use App\Model\PaymentGateway;
use App\Services\Subscription\SubscriptionManagementService;
class RemoteSyncCommandTest extends TestCase
{
public function test_sync_requires_gateway_or_subscription()
{
$subscriptionService = Mockery::mock(SubscriptionManagementService::class);
$subscriptionService->shouldReceive('getRemoteGateways')->andReturn([]);
$this->app->instance(SubscriptionManagementService::class, $subscriptionService);
$this->artisan('remote:sync')
->expectsOutputToContain('No active remote subscription gateways found')
->assertExitCode(1);
}
public function test_sync_with_invalid_gateway_shows_error()
{
$gateway = Mockery::mock(PaymentGateway::class)->makePartial();
$gateway->uid = 'gw_abc';
$gateway->name = 'Stripe Test';
$gateway->type = 'stripe-subscription';
$subscriptionService = Mockery::mock(SubscriptionManagementService::class);
$subscriptionService->shouldReceive('findRemoteGateway')->with('bad_uid')
->andThrow(new \Exception("Gateway with UID 'bad_uid' not found"));
$subscriptionService->shouldReceive('getRemoteGateways')->andReturn([$gateway]);
$this->app->instance(SubscriptionManagementService::class, $subscriptionService);
$this->artisan('remote:sync --gateway=bad_uid')
->expectsOutputToContain('not found')
->assertExitCode(1);
}
public function test_sync_gateway_with_no_subscriptions()
{
$gateway = Mockery::mock(PaymentGateway::class)->makePartial();
$gateway->uid = 'gw_abc';
$gateway->name = 'Stripe Test';
$gateway->type = 'stripe-subscription';
$subscriptionService = Mockery::mock(SubscriptionManagementService::class);
$subscriptionService->shouldReceive('findRemoteGateway')->with('gw_abc')->andReturn($gateway);
$subscriptionService->shouldReceive('syncRemoteSubscriptionsForGateway')->with($gateway, 0)->andReturn([]);
$this->app->instance(SubscriptionManagementService::class, $subscriptionService);
$this->artisan('remote:sync --gateway=gw_abc')
->expectsOutputToContain('No subscriptions to sync')
->assertExitCode(0);
}
public function test_sync_gateway_with_results_shows_summary()
{
$gateway = Mockery::mock(PaymentGateway::class)->makePartial();
$gateway->uid = 'gw_abc';
$gateway->name = 'Stripe Test';
$gateway->type = 'stripe-subscription';
// Return one in_sync result only (command fetches Subscription from DB for display,
// so we test with empty results to avoid DB dependency)
$results = [];
$subscriptionService = Mockery::mock(SubscriptionManagementService::class);
$subscriptionService->shouldReceive('findRemoteGateway')->with('gw_abc')->andReturn($gateway);
$subscriptionService->shouldReceive('syncRemoteSubscriptionsForGateway')->with($gateway, 0)->andReturn($results);
$this->app->instance(SubscriptionManagementService::class, $subscriptionService);
$this->artisan('remote:sync --gateway=gw_abc')
->expectsOutputToContain('No subscriptions to sync')
->assertExitCode(0);
}
public function test_sync_with_stale_hours_option()
{
$gateway = Mockery::mock(PaymentGateway::class)->makePartial();
$gateway->uid = 'gw_abc';
$gateway->name = 'Stripe Test';
$gateway->type = 'stripe-subscription';
$subscriptionService = Mockery::mock(SubscriptionManagementService::class);
$subscriptionService->shouldReceive('findRemoteGateway')->with('gw_abc')->andReturn($gateway);
$subscriptionService->shouldReceive('syncRemoteSubscriptionsForGateway')->with($gateway, 6)->andReturn([]);
$this->app->instance(SubscriptionManagementService::class, $subscriptionService);
$this->artisan('remote:sync --gateway=gw_abc --stale-hours=6')
->assertExitCode(0);
}
public function test_sync_scheduled_implies_stale_hours()
{
$gateway = Mockery::mock(PaymentGateway::class)->makePartial();
$gateway->uid = 'gw_abc';
$gateway->name = 'Stripe Test';
$gateway->type = 'stripe-subscription';
$subscriptionService = Mockery::mock(SubscriptionManagementService::class);
$subscriptionService->shouldReceive('findRemoteGateway')->with('gw_abc')->andReturn($gateway);
// scheduled implies at least stale-hours=1
$subscriptionService->shouldReceive('syncRemoteSubscriptionsForGateway')
->with($gateway, Mockery::on(fn($v) => $v >= 1))
->andReturn([]);
$this->app->instance(SubscriptionManagementService::class, $subscriptionService);
$this->artisan('remote:sync --gateway=gw_abc --scheduled')
->assertExitCode(0);
}
public function test_sync_all_gateways()
{
$gateway = Mockery::mock(PaymentGateway::class)->makePartial();
$gateway->uid = 'gw_abc';
$gateway->name = 'Stripe Test';
$gateway->type = 'stripe-subscription';
$subscriptionService = Mockery::mock(SubscriptionManagementService::class);
$subscriptionService->shouldReceive('getRemoteGateways')->andReturn([$gateway]);
$subscriptionService->shouldReceive('syncAllRemoteSubscriptions')->with(0)->once()->andReturn([
'gw_abc' => [
'gateway_name' => 'Stripe Test',
'gateway_type' => 'stripe-subscription',
'results' => [],
],
]);
$this->app->instance(SubscriptionManagementService::class, $subscriptionService);
$this->artisan('remote:sync --all')
->assertExitCode(0);
}
public function test_sync_all_with_scheduled_uses_stale_hours()
{
$gateway = Mockery::mock(PaymentGateway::class)->makePartial();
$gateway->uid = 'gw_abc';
$gateway->name = 'Stripe Test';
$gateway->type = 'stripe-subscription';
$subscriptionService = Mockery::mock(SubscriptionManagementService::class);
$subscriptionService->shouldReceive('getRemoteGateways')->andReturn([$gateway]);
$subscriptionService->shouldReceive('syncAllRemoteSubscriptions')
->with(Mockery::on(fn($v) => $v >= 1))
->once()
->andReturn([]);
$this->app->instance(SubscriptionManagementService::class, $subscriptionService);
$this->artisan('remote:sync --all --scheduled')
->assertExitCode(0);
}
public function test_sync_all_shows_gateway_error()
{
$gateway = Mockery::mock(PaymentGateway::class)->makePartial();
$gateway->uid = 'gw_broken';
$gateway->name = 'Broken GW';
$gateway->type = 'stripe-subscription';
$subscriptionService = Mockery::mock(SubscriptionManagementService::class);
$subscriptionService->shouldReceive('getRemoteGateways')->andReturn([$gateway]);
$subscriptionService->shouldReceive('syncAllRemoteSubscriptions')->with(0)->once()->andReturn([
'gw_broken' => [
'gateway_name' => 'Broken GW',
'gateway_type' => 'stripe-subscription',
'error' => 'Connection refused',
'results' => [],
],
]);
$this->app->instance(SubscriptionManagementService::class, $subscriptionService);
$this->artisan('remote:sync --all')
->expectsOutputToContain('Connection refused')
->assertExitCode(0);
}
protected function tearDown(): void
{
Mockery::close();
parent::tearDown();
}
}