HEX
Server: LiteSpeed
System: Linux s1049.use1.mysecurecloudhost.com 4.18.0-477.27.2.lve.el8.x86_64 #1 SMP Wed Oct 11 12:32:56 UTC 2023 x86_64
User: xedaptot (3356)
PHP: 8.3.31
Disabled: NONE
Upload Files
File: /home/xedaptot/be.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();
    }
}