In my Mojolicious app I need to use the client's IP address ($c->tx->remote_address
) for rate limiting of a service. This works well.
I am now trying to build a unit test for this feature, but I am having trouble faking the client's IP in my tests.
First I thought that local_address
in Mojo::UserAgent might do what I want, but that's where the user agent binds the application locally, and changing it breaks everything because it cannot find the app any more.
I then tried using Sub::Override to replace the remote_address
in Mojo::Transaction, but that already applies to the client when I do $t->post_ok
, it tries sending a request to the IP that doesn't exist because the remote address on the client side is the server's address, and I am stuck with a waiting blocking request that will never succeed because the server it wants does not exist.
You can use the following MCVE to try around. The expected result is for the tests to pass.
use strict;
use warnings;
use Test::More;
use Test::Mojo;
use Mojolicious::Lite;
get '/foo' => sub { my $c = shift; $c->render( text => $c->tx->remote_address ) };
my $t = Test::Mojo->new;
$t->get_ok('/foo')->content_like(qr/\Q127.0.0.1/);
# TODO change client IP address to 10.1.1.1
# in a way that the /foo route sees it
$t->get_ok('/foo')->content_like(qr/\Q10.1.1.1/);
done_testing;
I know how to do this with Catalyst and Dancer (or other Test::Plack based systems), but those approaches don't work here.
The author of Mojolicious pointed out on IRC to look at the unit tests in the Mojo dist for the X-Forwarded-For
header implementation, so I did.
We need to set the $ENV{MOJO_REVERSE_PROXY}
to a true value in the unit test and restart the server, then send an X-Forwarded-For
header with the new IP address and things will just work.
use strict;
use warnings;
use Test::More;
use Test::Mojo;
use Mojolicious::Lite;
get '/foo' => sub { my $c = shift; $c->render( text => $c->tx->remote_address ) };
my $t = Test::Mojo->new;
$t->get_ok('/foo')->content_like(qr/\Q127.0.0.1/);
{
local $ENV{MOJO_REVERSE_PROXY} = 1;
$t->ua->server->restart;
$t->get_ok( '/foo' => { 'X-Forwarded-For' => '10.1.1.1' } )->content_like(qr/\Q10.1.1.1/);
}
done_testing;
The tests now pass.
ok 1 - GET /foo
ok 2 - content is similar
ok 3 - GET /foo
ok 4 - content is similar
1..4
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With