Migrate outbound HTTP calls from Guzzle to the Http facade

Replaces every raw GuzzleHttp\Client usage (Nominatim, web.archive.org,
webmention fetch/discover/send, Bridgy syndication, IndieAuth client_id
lookup, contact avatar/h-card fetch, profile image download, and the
CloudConvert screenshot pipeline) with Illuminate\Support\Facades\Http,
and enables Http::preventStrayRequests() globally in tests so any
un-faked outbound call now fails loudly instead of silently hitting the
network.

The CloudConvert retry-until-finished middleware in AppServiceProvider
is replaced by a plain polling loop in SaveScreenshot, which also fixes
a latent bug where the old middleware decoded a response object instead
of its body. Bridgy syndication jobs keep their tries=1/no-retry
semantics unchanged to avoid duplicate publishes. Guzzle's PSR-7 helpers
(Header, UriResolver, Utils) stay in SendWebMentions since Http has no
equivalent for them.

Every affected test file's Guzzle MockHandler/HandlerStack boilerplate
is replaced with Http::fake()/Http::sequence().

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P8j7cJhCiYDsGUgB7obKNQ
This commit is contained in:
Jonny Barnes 2026-07-26 09:12:01 +01:00
commit e08763c526
Signed by: jonny
SSH key fingerprint: SHA256:CTuSlns5U7qlD9jqHvtnVmfYV3Zwl2Z7WnJ4/dqOaL8
26 changed files with 337 additions and 630 deletions

View file

@ -9,12 +9,9 @@ use App\Jobs\ProcessWebMention;
use App\Jobs\SaveProfileImage;
use App\Models\Note;
use App\Models\WebMention;
use GuzzleHttp\Client;
use GuzzleHttp\Handler\MockHandler;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Psr7\Response;
use Illuminate\FileSystem\FileSystem;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Queue;
use Jonnybarnes\WebmentionsParser\Parser;
use PHPUnit\Framework\Attributes\Test;
@ -39,17 +36,15 @@ class ProcessWebMentionJobTest extends TestCase
$this->expectException(RemoteContentNotFoundException::class);
$parser = new Parser;
$mock = new MockHandler([
new Response(404),
Http::fake([
'*' => Http::response('', 404),
]);
$handler = HandlerStack::create($mock);
$client = new Client(['handler' => $handler]);
$note = Note::factory()->create();
$source = 'https://example.org/mention/1/';
$job = new ProcessWebMention($note, $source);
$job->handle($parser, $client);
$job->handle($parser);
}
#[Test]
@ -65,17 +60,15 @@ class ProcessWebMentionJobTest extends TestCase
</div>
HTML;
$html = str_replace('href="', 'href="'.config('app.url'), $html);
$mock = new MockHandler([
new Response(200, [], $html),
Http::fake([
'*' => Http::response($html, 200),
]);
$handler = HandlerStack::create($mock);
$client = new Client(['handler' => $handler]);
$note = Note::factory()->create();
$source = 'https://example.org/mention/1/';
$job = new ProcessWebMention($note, $source);
$job->handle($parser, $client);
$job->handle($parser);
Queue::assertPushed(SaveProfileImage::class);
$this->assertDatabaseHas('webmentions', [
@ -103,14 +96,12 @@ class ProcessWebMentionJobTest extends TestCase
<div class="e-content">Updated reply</div>
</div>
HTML;
$mock = new MockHandler([
new Response(200, [], $html),
Http::fake([
'*' => Http::response($html, 200),
]);
$handler = HandlerStack::create($mock);
$client = new Client(['handler' => $handler]);
$job = new ProcessWebMention($note, $source);
$job->handle($parser, $client);
$job->handle($parser);
Queue::assertPushed(SaveProfileImage::class);
$this->assertDatabaseHas('webmentions', [
@ -132,11 +123,9 @@ class ProcessWebMentionJobTest extends TestCase
<div class="e-content">Replying to someone else</div>
</div>
HTML;
$mock = new MockHandler([
new Response(200, [], $html),
Http::fake([
'*' => Http::response($html, 200),
]);
$handler = HandlerStack::create($mock);
$client = new Client(['handler' => $handler]);
$note = Note::factory()->create();
$source = 'https://example.org/reply/1';
@ -151,7 +140,7 @@ class ProcessWebMentionJobTest extends TestCase
]);
$job = new ProcessWebMention($note, $source);
$job->handle($parser, $client);
$job->handle($parser);
$this->assertDatabaseMissing('webmentions', [
'source' => $source,
@ -169,11 +158,9 @@ class ProcessWebMentionJobTest extends TestCase
<div class="e-content">I like someone else now</div>
</div>
HTML;
$mock = new MockHandler([
new Response(200, [], $html),
Http::fake([
'*' => Http::response($html, 200),
]);
$handler = HandlerStack::create($mock);
$client = new Client(['handler' => $handler]);
$note = Note::factory()->create();
$source = 'https://example.org/reply/1';
@ -188,7 +175,7 @@ class ProcessWebMentionJobTest extends TestCase
]);
$job = new ProcessWebMention($note, $source);
$job->handle($parser, $client);
$job->handle($parser);
$this->assertDatabaseMissing('webmentions', [
'source' => $source,
@ -208,18 +195,16 @@ class ProcessWebMentionJobTest extends TestCase
</div>
HTML;
$html = str_replace('href="', 'href="'.config('app.url'), $html);
$mock = new MockHandler([
new Response(200, [], $html),
Http::fake([
'*' => Http::response($html, 200),
]);
$handler = HandlerStack::create($mock);
$client = new Client(['handler' => $handler]);
$note = Note::factory()->create();
// Simulate a long brid.gy Bluesky source URL (well over 255 characters)
$source = 'https://brid.gy/comment/bluesky/did:plc:n3jhgiq2ykctnpgzlm6p6b25/at%253A%252F%252Fdid%253Aplc%253An3jhgiq2ykctnpgzlm6p6b25%252Fapp.bsky.feed.post%252F3mfekjuhykb2k/at%253A%252F%252Fdid%253Aplc%253Afsfuwigo5juzdwp23hyianzg%252Fapp.bsky.feed.post%252F3mfemw4rrvs2t';
$job = new ProcessWebMention($note, $source);
$job->handle($parser, $client);
$job->handle($parser);
$this->assertGreaterThan(255, strlen($source));
$this->assertDatabaseHas('webmentions', [
@ -238,11 +223,9 @@ class ProcessWebMentionJobTest extends TestCase
<div class="e-content">Reposting someone else</div>
</div>
HTML;
$mock = new MockHandler([
new Response(200, [], $html),
Http::fake([
'*' => Http::response($html, 200),
]);
$handler = HandlerStack::create($mock);
$client = new Client(['handler' => $handler]);
$note = Note::factory()->create();
$source = 'https://example.org/reply/1';
@ -257,7 +240,7 @@ class ProcessWebMentionJobTest extends TestCase
]);
$job = new ProcessWebMention($note, $source);
$job->handle($parser, $client);
$job->handle($parser);
$this->assertDatabaseMissing('webmentions', [
'source' => $source,