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/ai.naniguide.com/tests/Feature/SendingServerWebhookHttpTest.php
<?php

use App\Model\BounceLog;
use App\Model\Contact;
use App\Model\Customer;
use App\Model\MailList;
use App\Model\SendingServer;
use App\Model\Subscriber;
use App\Model\TrackingLog;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Support\Facades\Event;
use Tests\TestCase;

uses(TestCase::class, DatabaseTransactions::class);

/**
 * HTTP-level test for the webhook receive endpoint:
 *   POST /webhook/{driverType}/{serverUid}
 *
 * Verifies the full chain:
 *   1. Route resolves to SendingServerWebhookController::handle.
 *   2. Server uid lookup + cross-tenant guard (type mismatch → 404).
 *   3. Driver instanceof ReceivesWebhooks check.
 *   4. driver->verifyWebhook + driver->parseWebhook dispatched correctly.
 *   5. Each parsed event fires on the Laravel event bus.
 */

function makeSendGridSrvForHttp(): SendingServer
{
    $contact = Contact::factory()->create();
    $customer = Customer::factory()->create([
        'contact_id' => $contact->id,
        'uid'        => 'whcust' . uniqid(),
    ]);

    $server = SendingServer::factory()->create([
        'type' => 'sendgrid-api',
        'customer_id' => $customer->id,
    ]);

    return $server;
}

test('POST /webhook/{type}/{uid} returns 200 + dispatches BounceReceived event', function () {
    Event::fake([\App\SendingServers\Webhooks\BounceReceived::class]);

    $server = makeSendGridSrvForHttp();
    $payload = [
        ['event' => 'bounce', 'runtime_message_id' => '[email protected]'],
    ];

    $response = $this->postJson("/webhook/sendgrid-api/{$server->uid}", $payload);

    $response->assertOk()->assertJson(['ok' => true]);
    Event::assertDispatched(\App\SendingServers\Webhooks\BounceReceived::class);
});

test('POST /webhook/wrong-type/{uid} returns 404 (cross-tenant guard)', function () {
    $server = makeSendGridSrvForHttp();

    $response = $this->postJson("/webhook/mailgun-api/{$server->uid}", []);

    $response->assertNotFound();
});

test('POST /webhook/{type}/nonexistent-uid returns 404', function () {
    $response = $this->postJson('/webhook/sendgrid-api/srv-does-not-exist', []);

    $response->assertNotFound();
});

test('POST /webhook for driver without ReceivesWebhooks (Smtp variant) returns 404', function () {
    // SMTP driver does NOT implement ReceivesWebhooks — webhook URL is only
    // valid for Api variants. Posting to Smtp uid → 404.
    $contact = Contact::factory()->create();
    $customer = Customer::factory()->create([
        'contact_id' => $contact->id,
        'uid'        => 'whsmtp' . uniqid(),
    ]);
    $smtpServer = SendingServer::factory()->create([
        'type' => 'smtp',
        'customer_id' => $customer->id,
    ]);

    $response = $this->postJson("/webhook/smtp/{$smtpServer->uid}", ['payload' => 'whatever']);

    $response->assertNotFound();
});

test('POST /webhook with multiple events fires each one (multi-event payload)', function () {
    Event::fake([
        \App\SendingServers\Webhooks\BounceReceived::class,
        \App\SendingServers\Webhooks\ComplaintReceived::class,
        \App\SendingServers\Webhooks\IgnorableWebhookEvent::class,
    ]);

    $server = makeSendGridSrvForHttp();
    $payload = [
        ['event' => 'bounce',     'runtime_message_id' => '[email protected]'],
        ['event' => 'spamreport', 'runtime_message_id' => '[email protected]'],
        ['event' => 'open',       'runtime_message_id' => '[email protected]'],   // ignorable
    ];

    $this->postJson("/webhook/sendgrid-api/{$server->uid}", $payload)->assertOk();

    Event::assertDispatched(\App\SendingServers\Webhooks\BounceReceived::class, 1);
    Event::assertDispatched(\App\SendingServers\Webhooks\ComplaintReceived::class, 1);
    Event::assertDispatched(\App\SendingServers\Webhooks\IgnorableWebhookEvent::class, 1);
});