How do I fake the client IP address in a unit test for a Mojolicious app?
Asked Answered
E

1

13

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.

Emigration answered 26/10, 2017 at 17:44 Comment(0)
E
13

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
Emigration answered 26/10, 2017 at 18:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.