Fw: Use Test::Nginx with etcproxy and/or valgrind (Was Re: Test::Nginx::LWP vs. Test::Nginx::Socket)
Antoine Bonavita (personal)
antoine.bonavita at gmail.com
Tue Mar 15 18:13:00 MSK 2011
Hi agentzh,
I managed to migrate all my tests from my original python approach to
using Test::Nginx. I guess this is good news. However, I must say some
of it was a bit painful.
The main thing is probably a lack of documentation/examples on the
data sections accepted by Test::Nginx. Especially for people who are
not familiar with Test::Base (like me). I understand you don't want to
duplicate the work done by the guys at Test::Base but at least
pointers to some useful tricks like filters and --- ONLY would help
the beginners.
As a side note to this, I don't see any benefit in having the
"request_eval" section. To me (at least in the tests I wrote)
"request_eval" can be replaced by "request eval" (so, applying eval to
the data). May be you should get rid of the _eval versions or maybe
I'm missing something....
I actually wrote a few posts on the migration to Test::Nginx:
* http://www.nginx-discovery.com/2011/03/day-32-moving-to-testnginx.html
* http://www.nginx-discovery.com/2011/03/day-33-testnginx-pipelinedrequests.html
Another thing that annoyed me is the use of shuffle to "on" by
default. I find it more misleading than anything else (especially on
your first runs).
After going through this exercise (and learning quite a few things in
the process), the things that I really think should be improved are:
* Being able to share one config amongst multiple tests.
* Being able to run multiple requests in one test. The
pipelined_requests use the same connection which might not be what I
want. I was thinking of something more natural like : send request 1,
wait for response 1, check response 1, send request 2, wait for
response 2, check response 2, etc.
Of course, I am willing to help with these improvements but I do not
want to start running all over the place without discussing it with
you as I'm likely to miss out something really big.
Antoine.
--
Antoine Bonavita.
Follow my progress with nginx at: http://www.nginx-discovery.com
On Tue, Mar 15, 2011 at 3:43 PM, Antoine BONAVITA
<antoine_bonavita at yahoo.com> wrote:
>> From: Antoine BONAVITA <antoine_bonavita at yahoo.com>
>> To: agentzh <agentzh at gmail.com>
>> Cc: nginx-devel at nginx.org
>> Sent: Thu, March 3, 2011 2:57:44 PM
>> Subject: Re: Use Test::Nginx with etcproxy and/or valgrind (Was Re:
>>Test::Nginx::LWP vs. Test::Nginx::Socket)
>>
>> 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
>>s
>> >
>> >
>> > 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/
>> >
>>
>>
>>
>>
>> _______________________________________________
>> nginx-devel mailing list
>> nginx-devel at nginx.org
>> http://nginx.org/mailman/listinfo/nginx-devel
>>
>
>
>
More information about the nginx-devel
mailing list