I am working on a HTTP API client based on Mojo::UserAgent and writing tests including handling HTTP connection problems. When making my mock server drop the connection $tx->res->to_string is a imaginary HTTP 404 response including HTTP headers.
HTTP/1.1 404 Not Found
Content-Length: 0
Date: Mon, 15 Dec 2025 08:43:51 GMT
This made debugging my app & tests quite hard and it feels a bit similar to AI hallucination. I see the Mojo::Message::Response has a default status of 404 and sets these headers in fix_headers(). Can Mojo::UserAgent be changed that it doesn’t return a Transaction with a response in this state?
A simplified test:
use Mojo::Base -signatures;
use Test2::V0;
use Mojo::UserAgent;
use Mojolicious::Lite;
use Test::Mojo;
my $abort_connection;
hook before_dispatch => sub ($c) {
if ( $abort_connection )
{ # abort immediately to simulate HTTP connection problem
my $id = $c->tx->connection or return;
Mojo::IOLoop->stream($id )->close;
}
};
post '/' => sub ($c) {
$c->render(status => 200, json => {});
};
my $t = Test::Mojo->new();
my $ua = $t->ua;
ok my $tx = $ua->post('/');
diag $tx->res->to_string; # correct representation of actual HTTP response
is $tx->res->body => '{}', "body";
is $tx->res->code => 200;
$abort_connection = 1;
ok $tx = $ua->post('/');
diag $tx->res->to_string; # imaginary HTTP 404 response!
is $tx->res->body => '{}', "body"; # fails because body is empty string
is $tx->res->code => 200; # fails because code is undef
done_testing;
Test output:
$ prove -v t/abort.t
t/abort.t ..
# Seeded srand with seed '20251215' from local date.
[2025-12-15 09:43:51.87173] [4082754] [trace] [EXjANFplB4xQ] POST "/"
[2025-12-15 09:43:51.87209] [4082754] [trace] [EXjANFplB4xQ] Routing to a callback
[2025-12-15 09:43:51.87238] [4082754] [trace] [EXjANFplB4xQ] 200 OK (0.000643s, 1555.210/s)
ok 1
# HTTP/1.1 200 OK
# Content-Length: 2
# Content-Type: application/json;charset=UTF-8
# Date: Mon, 15 Dec 2025 08:43:51 GMT
# Server: Mojolicious (Perl)
#
# {}
ok 2 - body
ok 3
[2025-12-15 09:43:51.87564] [4082754] [trace] [IT9qoVFF6kyK] POST "/"
[2025-12-15 09:43:51.87584] [4082754] [trace] [IT9qoVFF6kyK] Routing to a callback
[2025-12-15 09:43:51.87604] [4082754] [trace] [IT9qoVFF6kyK] 200 OK (0.000399s, 2506.266/s)
ok 4
# HTTP/1.1 404 Not Found
# Content-Length: 0
# Date: Mon, 15 Dec 2025 08:43:51 GMT
#
not ok 5 - body
# Failed test 'body'
# at t/abort.t line 32.
# +-----+----+-------+
# | GOT | OP | CHECK |
# +-----+----+-------+
# | | eq | {} |
# +-----+----+-------+
(If this table is too small, you can use the TABLE_TERM_SIZE=### env var to set a larger size, detected size is '78')
not ok 6
# Failed test at t/abort.t line 33.
# +---------+-------+
# | GOT | CHECK |
# +---------+-------+
# | <UNDEF> | 200 |
# +---------+-------+
(If this table is too small, you can use the TABLE_TERM_SIZE=### env var to set a larger size, detected size is '78')
1..6
# Looks like you failed 2 tests of 6.
Dubious, test returned 2 (wstat 512, 0x200)
Failed 2/6 subtests
Test Summary Report
-------------------
t/abort.t (Wstat: 512 (exited 2) Tests: 6 Failed: 2)
Failed tests: 5-6
Non-zero exit status: 2
Files=1, Tests=6, 0 wallclock secs ( 0.02 usr 0.01 sys + 0.30 cusr 0.03 csys = 0.36 CPU)
Result: FAIL
I am working on a HTTP API client based on Mojo::UserAgent and writing tests including handling HTTP connection problems. When making my mock server drop the connection
$tx->res->to_stringis a imaginary HTTP 404 response including HTTP headers.This made debugging my app & tests quite hard and it feels a bit similar to AI hallucination. I see the Mojo::Message::Response has a default status of 404 and sets these headers in fix_headers(). Can Mojo::UserAgent be changed that it doesn’t return a Transaction with a response in this state?
A simplified test:
Test output: