Use Test::Nginx with etcproxy and/or valgrind (Was Re: Test::Nginx::LWP vs. Test::Nginx::Socket)

Antoine BONAVITA antoine_bonavita at yahoo.com
Thu Mar 3 16:57:44 MSK 2011


Agentzh,

Thanks a lot, again. I'm going on a ski trip for a week or so. I'll try that 
when I come back.

Antoine.




----- Original Message ----
> From: agentzh <agentzh at gmail.com>
> To: Antoine BONAVITA <antoine_bonavita at yahoo.com>
> Cc: nginx-devel at nginx.org
> Sent: Thu, March 3, 2011 4:49:17 AM
> Subject: Use Test::Nginx with etcproxy and/or valgrind (Was Re: 
>Test::Nginx::LWP vs. Test::Nginx::Socket)
> 
> On Thu, Mar 3, 2011 at 12:37 AM, Antoine BONAVITA
> <antoine_bonavita at yahoo.com>  wrote:
> > Following agentzh tips, I'm moving the test cases for my module  to 
>Test::Nginx
> > (instead of using my python unit  tests).
> >
> 
> There's a lot of undocumented features in  Test::Nginx::Socket. I'm
> sorry. I'd like to document a bit how to integrate  it with etcproxy
> and/or valgrind here because it's so useful ;)
> 
> Use  Test::Nginx::Socket with  etcproxy
> ============================
> 
> Test::Nginx automatically starts  an nginx instance (from the PATH env)
> rooted at t/servroot/ and the default  config template makes this nginx
> instance listen on the port 1984 by  default.
> 
> The default settings in etcproxy [1] makes this small TCP proxy  split
> the TCP packets into bytes and introduce 1ms latency among  them.
> 
> There's usually various TCP chains that we can put etcproxy into,  for example
> 
> Test::Nginx <=>  nginx
> ----------------------------
> 
>    $ ./etcproxy 1234  1984
> 
> Here we tell etcproxy to listen on port 1234 and to delegate all  the
> TCP traffic to the port 1984, the default port that Test::Nginx  makes
> nginx listen to.
> 
> And then we tell Test::Nginx to test against  the port 1234, where
> etcproxy listens on, rather than the port 1984 that  nginx directly
> listens on:
> 
>    $ TEST_NGINX_CLIENT_PORT=1234 prove  -r t/
> 
> Then the TCP chain now looks like this:
> 
>    Test::Nginx  <=> etcproxy (1234) <=> nginx (1984)
> 
> So etcproxy can  effectively emulate extreme network conditions and
> exercise "unusual" code  paths in your nginx server by your tests.
> 
> In practice, *tons* of weird  bugs can be captured by this setting.
> Even ourselves didn't expect that this  simple approach is so
> effective.
> 
> nginx <=>  memcached
> -----------------------------
> 
> We first start the memcached  server daemon on port 11211:
> 
>     memcached -p 11211  -vv
> 
> and then we another etcproxy instance to listen on port 11984 like  this
> 
>     $ ./etcproxy 11984 11211
> 
> Then we tell our  t/foo.t test script to connect to 11984 rather than 11211:
> 
>    #  foo.t
>    use Test::Nginx::Socket;
>    repeat_each(1);
>     plan tests => 2 * repeat_each() * blocks();
>     $ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211;  # make this env take  a
> default value
>    run_tests();
> 
>    __DATA__
> 
>     === TEST 1: sanity
>    --- config
>    location /foo {
>          set $memc_cmd set;
>         set  $memc_key foo;
>         set $memc_value bar;
>          memc_pass 127.0.0.1:$TEST_NGINX_MEMCACHED_PORT;
>     }
>    --- request
>        GET /foo
>    ---  response_body_like: STORED
> 
> The Test::Nginx library will automatically  expand the special macro
> "$TEST_NGINX_MEMCACHED_PORT" to the environment with  the same name.
> You can define your own $TEST_NGINX_BLAH_BLAH_PORT macros as  long as
> its prefix is TEST_NGINX_ and all in upper case letters.
> 
> And  now we can run your test script against the etcproxy port 11984:
> 
>      TEST_NGINX_MEMCACHED_PORT=11984 prove t/foo.t
> 
> Then the TCP chains  look like this:
> 
>     Test::Nginx <=> nginx (1984)  <=> etcproxy (11984) <=> memcached (11211)
> 
> If  TEST_NGINX_MEMCACHED_PORT is not set, then it will take the default
> value  11211, which is what we want when there's no  etcproxy
> configured:
> 
>     Test::Nginx <=> nginx (1984)  <=> memcached (11211)
> 
> This approach also works for proxied mysql  and postgres traffic.
> Please see the live test suite of ngx_drizzle and  ngx_postgres for
> more details.
> 
> Usually we set both  TEST_NGINX_CLIENT_PORT and
> TEST_NGINX_MEMCACHED_PORT (and etc) at the same  time, effectively
> yielding the following chain:
> 
>      Test::Nginx <=> etcproxy (1234) <=> nginx (1984) <=>  etcproxy
> (11984) <=> memcached (11211)
> 
> as long as you run two  separate etcproxy instances in two separate terminals.
> 
> It's easy to  verify if the traffic actually goes through your etcproxy
> server. Just check  if the terminal running etcproxy emits outputs. By
> default, etcproxy always  dump out the incoming and outgoing data to
> stdout/stderr.
> 
> Use  Test::Nginx::Socket with valgrind  memcheck
> ====================================
> 
> Test::Nginx has  integrated support for valgrind [2] even though by
> default it does not bother  running it with the tests because valgrind
> will significantly slow down the  test sutie.
> 
> First ensure that your valgrind executable visible in your  PATH env.
> And then run your test suite with the TEST_NGINX_USE_VALGRIND env  set
> to true:
> 
>     TEST_NGINX_USE_VALGRIND=1 prove -r  t
> 
> If you see false alarms, you do have a chance to skip them by  defining
> a ./valgrind.suppress file at the root of your module source tree,  as
> in
> 
>     
>https://github.com/chaoslawful/drizzle-nginx-module/blob/master/valgrind.suppress
>
> 
> This  is the suppression file for ngx_drizzle. Test::Nginx will
> automatically use  it to start nginx with valgrind memcheck if this
> file does exist at the  expected location.
> 
> If you do see a lot of "Connection refused" errors  while running the
> tests this way, then you probably have a slow machine (or a  very busy
> one) that the default waiting time is not sufficient for valgrind  to
> start. You can define the sleep time to a larger value by setting  the
> TEST_NGINX_SLEEP env:
> 
>     TEST_NGINX_SLEEP=1 prove -r  t
> 
> The time unit used here is "second". The default sleep setting  just
> fits my ThinkPad (Core2Duo T9600).
> 
> Applying the no-pool patch to  your nginx core is recommended while
> running nginx with  valgrind:
> 
>     https://github.com/shrimp/no-pool-nginx
> 
> The nginx  memory pool can prevent valgrind from spotting lots of
> invalid memory  reads/writes as well as certain double-free errors. We
> did find a lot more  memory issues in many of our modules when we first
> introduced the no-pool  patch in practice ;)
> 
> There's also more advanced features in Test::Nginx  that have never
> documented. I'd like to write more about them in the near  future ;)
> 
> Cheers,
> -agentzh
> 
> References
> 
> [1] etcproxy: https://github.com/chaoslawful/etcproxy
> [2] valgrind:  http://valgrind.org/
> 


      



More information about the nginx-devel mailing list