<?xml version="1.0" encoding="UTF-8"?> <rss version="2.0"
xmlns:content="http://purl.org/rss/1.0/modules/content/"
xmlns:wfw="http://wellformedweb.org/CommentAPI/"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:atom="http://www.w3.org/2005/Atom"
xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
><channel><title>Francisco Souza</title> <atom:link href="http://f.souza.cc/feed/" rel="self" type="application/rss+xml" /><link>http://f.souza.cc</link> <description></description> <lastBuildDate>Sun, 15 Jan 2012 13:55:56 +0000</lastBuildDate> <language>en</language> <sy:updatePeriod>hourly</sy:updatePeriod> <sy:updateFrequency>1</sy:updateFrequency> <generator>http://wordpress.org/?v=3.3.1</generator> <item><title>Setting up a Django production environment: compiling and configuring nginx</title><link>http://f.souza.cc/2011/11/setting-up-a-django-production-environment-compiling-and-configuring-nginx/</link> <comments>http://f.souza.cc/2011/11/setting-up-a-django-production-environment-compiling-and-configuring-nginx/#comments</comments> <pubDate>Sun, 06 Nov 2011 02:15:04 +0000</pubDate> <dc:creator>Francisco Souza</dc:creator> <category><![CDATA[web development]]></category> <category><![CDATA[django]]></category> <category><![CDATA[fabric]]></category> <category><![CDATA[gunicorn]]></category> <category><![CDATA[nginx]]></category> <category><![CDATA[open source]]></category> <category><![CDATA[python]]></category> <category><![CDATA[virtualenv]]></category><guid isPermaLink="false">http://f.souza.cc/?p=622</guid> <description><![CDATA[Here is another series of posts: now I’m going to write about setting up a Django production environment using nginx and Green Unicorn in a virtual environment. The subject in this first post is nginx, which is my favorite web server.]]></description> <content:encoded><![CDATA[<p><img src="http://c.souza.cc/s/2011/11/nginx-logo.png" alt="nginx" title="nginx" width="295" height="92" class="alignright size-full wp-image-628" />Here is another series of posts: now I&#8217;m going to write about setting up a <a href="http://djangoproject.com" title="Django" target="_blank" rel="nofollow">Django</a> production environment using <a href="http://nginx.org" title="nginx" target="_blank" rel="nofollow">nginx</a> and <a href="http://gunicorn.org/" title="gunicorn" target="_blank" rel="nofollow">Green Unicorn</a> in a <a href="http://virtualenv.org" title="virtualenv" target="_blank" rel="nofollow">virtual environment</a>. The subject in this first post is nginx, which is my favorite web server.</p><p>This post explains how to install nginx from sources, compiling it (on Linux). You might want to use <em>apt</em>, <em>zif</em>, <em>yum</em> or <em>ports</em>, but I prefer building from sources. So, to build from sources, make sure you have all development dependencies (C headers, including the PCRE library headers, nginx rewrite module uses it). If you want to build nginx with SSL support, keep in mind that you will need the libssl headers too.<span id="more-622"></span></p><p>Build nginx from source is a straightforward process: all you need to do is download it from the official site and build with some simple options. In our setup, we&#8217;re going to install nginx under <code class="codecolorer text default"><span class="text">/opt/nginx</span></code>, and use it with the <code class="codecolorer text default"><span class="text">nginx</span></code> system user. So, let&#8217;s download and extract the latest stable version (1.0.9) from nginx website:</p><div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$ curl -O http://nginx.org/download/nginx-1.0.9.tar.gz<br /> $ tar -xzf nginx-1.0.9.tar.gz</div></div><p>Once you have extracted it, just configure, compile and install:</p><div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$ ./configure --prefix=/opt/nginx --user=nginx --group=nginx<br /> $ make<br /> # make install</div></div><p>As you can see, we provided the <em>/opt/nginx</em> to configure, make sure the /opt directory exists. Also, make sure that there is a user and a group called <em>nginx</em>, if they don&#8217;t exist, add them:</p><div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$ [sudo] adduser --system --no-create-home --disabled-login --disabled-password --group nginx</div></div><p>After that, you can start nginx using the command line above:</p><div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$ [sudo] /opt/nginx/sbin/nginx</div></div><blockquote><p>Linode provides an <a href="http://library.linode.com/assets/634-init-deb.sh" title="Linode init script" target="_blank" rel="nofollow">init script</a> that uses <a href="http://man.he.net/man8/start-stop-daemon" title="start-stop-daemon man page entry" target="_blank" rel="nofollow">start-stop-daemon</a>, you might want to use it.</p></blockquote><h3>nginx configuration</h3><p>nginx comes with a default <code class="codecolorer text default"><span class="text">nginx.conf</span></code> file, let&#8217;s change it to reflect the following configuration requirements:</p><ul><li>nginx should start workers with the <code class="codecolorer text default"><span class="text">nginx</span></code> user</li><li>nginx should have two worker processes</li><li>the PID should be stored in the <em>/opt/nginx/log/nginx.pid</em> file</li><li>nginx must have an access log in <em>/opt/nginx/logs/access.log</em></li><li>the configuration for the Django project we&#8217;re going to develop should be versioned with the entire code, so it must be <em>included</em> in the nginx.conf file (assume that the <em>library</em> project is in the directory <em>/opt/projects</em>).</li></ul><p>So here is the <code class="codecolorer text default"><span class="text">nginx.conf</span></code> for the requirements above:</p><div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">user &nbsp;nginx;<br /> worker_processes &nbsp;2;<br /> <br /> pid logs/nginx.pid;<br /> <br /> events {<br /> &nbsp; &nbsp; worker_connections &nbsp;1024;<br /> }<br /> <br /> http {<br /> &nbsp; &nbsp; include &nbsp; &nbsp; &nbsp; mime.types;<br /> &nbsp; &nbsp; default_type &nbsp;application/octet-stream;<br /> <br /> &nbsp; &nbsp; log_format &nbsp;main &nbsp;'$remote_addr - $remote_user [$time_local] &quot;$request&quot; '<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;'$status $body_bytes_sent &quot;$http_referer&quot; '<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;'&quot;$http_user_agent&quot; &quot;$http_x_forwarded_for&quot;';<br /> <br /> &nbsp; &nbsp; access_log &nbsp;logs/access.log &nbsp;main;<br /> <br /> &nbsp; &nbsp; sendfile &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; on;<br /> &nbsp; &nbsp; keepalive_timeout &nbsp;65;<br /> <br /> &nbsp; &nbsp; include /opt/projects/showcase/nginx.conf;<br /> }</div></div><p>Now we just need to write the configuration for our Django project. I&#8217;m using an old sample project written while I was working at Giran: the name is <em>lojas giranianas</em>, a nonsense portuguese joke with a famous brazilian store. It&#8217;s an unfinished showcase of products, it&#8217;s like an e-commerce project, but it can&#8217;t sell, so it&#8217;s just a product catalog. The code is available at <a href="https://github.com/fsouza/fast-track-django" title="lojas giranianas" target="_blank" rel="nofollow">Github</a>. The <em>nginx.conf</em> file for the repository is here:</p><div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">server {<br /> &nbsp; &nbsp; listen 80;<br /> &nbsp; &nbsp; server_name localhost;<br /> <br /> &nbsp; &nbsp; charset utf-8;<br /> <br /> &nbsp; &nbsp; location / {<br /> &nbsp; &nbsp; &nbsp; &nbsp; proxy_set_header &nbsp; &nbsp;X-Real-IP &nbsp; $remote_addr;<br /> &nbsp; &nbsp; &nbsp; &nbsp; proxy_set_header &nbsp; &nbsp;Host &nbsp; &nbsp; &nbsp; &nbsp;$http_host;<br /> &nbsp; &nbsp; &nbsp; &nbsp; proxy_set_header &nbsp; &nbsp;X-Forwarded-For $proxy_add_x_forwarded_for;<br /> <br /> &nbsp; &nbsp; &nbsp; &nbsp; proxy_pass http://localhost:8000;<br /> &nbsp; &nbsp; }<br /> <br /> &nbsp; &nbsp; location /static {<br /> &nbsp; &nbsp; &nbsp; &nbsp; root /opt/projects/showcase/;<br /> &nbsp; &nbsp; &nbsp; &nbsp; expires 1d;<br /> &nbsp; &nbsp; }<br /> }</div></div><p>The server listens on port 80, responds for the <em>localhost</em> hostname (<a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html" title="HTTP 1.1 headers" target="_blank">read more about the Host header</a>). The <code class="codecolorer text default"><span class="text">location /static</span></code> directive says that nginx will serve the static files of the project. It also includes an <code class="codecolorer text default"><span class="text">expires</span></code> directive for caching control. The <code class="codecolorer text default"><span class="text">location /</span></code> directive makes a <a href="http://wiki.nginx.org/HttpProxyModule#proxy_pass" title="nginx proxy_pass" target="_blank">proxy_pass</a>, forwarding all requisitions to an upstream server listening on port 8000, this server is the subject of the next post of the series: the Green Unicorn (gunicorn) server.</p><p>Not only the HTTP request itself is forwarded to the gunicorn server, but also some headers, that helps to properly deal with the request:</p><ul><li><strong>X-Real-IP</strong>: forwards the remote address to the upstream server, so it can know the real IP of the user. When nginx forwards the request to gunicorn, without this header, all gunicorn will know is that there is a request coming from localhost (or wherever the nginx server is), the remote address is always the IP address of the machine where nginx is running (who actually make the request to gunicorn)</li><li><strong>Host</strong>: the <em>Host</em> header is forwarded so gunicorn can treat different requests for different hosts. Without this header, it will be impossible to Gunicorn to have these constraints</li><li><strong>X-Forwarded-For</strong>: also known as XFF, this header provide more precise information about the real IP who makes the request. Imagine there are 10 proxies between the user machine and your webserver, the XFF header will all these proxies comma separated. In order to not turn a proxy into an anonymizer, it&#8217;s a good practice to always forward this header.</li></ul><p>So that is it, in the next post we&#8217;re going to install and run gunicorn. In other posts, we&#8217;ll see how to make automated deploys using <a href="http://fabfile.org" title="Fabric" target="_blank">Fabric</a>, and some tricks on caching (using the <a href="http://wiki.nginx.org/HttpProxyModule#proxy_cache" title="nginx proxy_cache" target="_blank" rel="nofollow">proxy_cache</a> directive and integrating <a href="http://f.souza.cc/tag/django" title="Posts about Django">Django</a>, nginx and <a href="http://f.souza.cc/tag/memcached" title="Posts about memcached">memcached</a>).</p><p>See you in the next posts :)</p> ]]></content:encoded> <wfw:commentRss>http://f.souza.cc/2011/11/setting-up-a-django-production-environment-compiling-and-configuring-nginx/feed/</wfw:commentRss> <slash:comments>3</slash:comments> </item> <item><title>Go solution of the Dining philosophers problem</title><link>http://f.souza.cc/2011/10/go-solution-of-the-dining-philosophers-problem/</link> <comments>http://f.souza.cc/2011/10/go-solution-of-the-dining-philosophers-problem/#comments</comments> <pubDate>Sun, 30 Oct 2011 23:26:15 +0000</pubDate> <dc:creator>Francisco Souza</dc:creator> <category><![CDATA[software development]]></category> <category><![CDATA[concurrency]]></category> <category><![CDATA[golang]]></category> <category><![CDATA[the little book of semaphores]]></category><guid isPermaLink="false">http://f.souza.cc/?p=600</guid> <description><![CDATA[Solution for the dining philosophers problem using the Go programming language.]]></description> <content:encoded><![CDATA[<p><img src="http://c.souza.cc/s/2011/10/dining-philosophers-problem.png" alt="Dining philosophers problem" title="Dining philosophers problem" width="160" height="154" class="alignright size-full wp-image-612" />I spent part of the sunday solving the <a href="http://en.wikipedia.org/wiki/Dining_philosophers_problem" title="Dining philosophers problem" target="_blank" rel="nofollow">Dining Philosophers</a> using <a href="http://golang.org" title="Go Programming Language" target="_blank" rel="nofollow">Go</a>. The given solution is based in the description for the problem present in <a href="http://greenteapress.com/semaphores/" title="The Little Book of Semaphores" target="_blank" rel="nofollow">The Little Book of Semaphores</a>:</p><p><em>The Dining Philosophers Problem was proposed by Dijkstra in 1965, when dinosaurs ruled the earth. It appears in a number of variations, but the standard features are a table with ﬁve plates, ﬁve forks (or chopsticks) and a big bowl of spaghetti.</em></p><p>There are some constraints:</p><ul><li>Only one philosopher can hold a fork at a time</li><li>It must be impossible for a deadlock to occur</li><li>It must be impossible for a philosopher to starve waiting for a fork</li><li>It must be possible for more than one philosopher to eat at the same time</li></ul><p><span id="more-600"></span></p><p>No more talk, here is my solution for the problem:</p><div class="codecolorer-container go default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><div class="go codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #b1b100; font-weight: bold;">package</span> main<br /> <br /> <span style="color: #b1b100; font-weight: bold;">import</span> <span style="color: #339933;">(</span><br /> &nbsp; &nbsp; <span style="color: #cc66cc;">&quot;fmt&quot;</span><br /> &nbsp; &nbsp; <span style="color: #cc66cc;">&quot;sync&quot;</span><br /> &nbsp; &nbsp; <span style="color: #cc66cc;">&quot;time&quot;</span><br /> <span style="color: #339933;">)</span><br /> <br /> <span style="color: #b1b100; font-weight: bold;">type</span> Fork <span style="color: #993333;">struct</span> <span style="color: #339933;">{</span><br /> &nbsp; &nbsp; <span style="color: #003399;">sync.<span style="">Mutex</span></span><br /> <span style="color: #339933;">}</span><br /> <br /> <span style="color: #b1b100; font-weight: bold;">type</span> Table <span style="color: #993333;">struct</span> <span style="color: #339933;">{</span><br /> &nbsp; &nbsp; philosophers <span style="color: #993333;">chan</span> Philosopher<br /> &nbsp; &nbsp; forks <span style="color: #339933;">[]</span><span style="color: #339933;">*</span>Fork<br /> <span style="color: #339933;">}</span><br /> <br /> <span style="color: #993333;">func</span> NewTable<span style="color: #339933;">(</span>forks <span style="color: #993333;">int</span><span style="color: #339933;">)</span> <span style="color: #339933;">*</span>Table <span style="color: #339933;">{</span><br /> &nbsp; &nbsp; t <span style="color: #339933;">:=</span> <span style="color: #000066;">new</span><span style="color: #339933;">(</span>Table<span style="color: #339933;">)</span><br /> &nbsp; &nbsp; t<span style="color: #339933;">.</span>philosophers <span style="color: #339933;">=</span> <span style="color: #000066;">make</span><span style="color: #339933;">(</span><span style="color: #993333;">chan</span> Philosopher<span style="color: #339933;">,</span> forks <span style="color: #339933;">-</span> <span style="color: #cc66cc;">1</span><span style="color: #339933;">)</span><br /> &nbsp; &nbsp; t<span style="color: #339933;">.</span>forks <span style="color: #339933;">=</span> <span style="color: #000066;">make</span><span style="color: #339933;">([]</span><span style="color: #339933;">*</span>Fork<span style="color: #339933;">,</span> forks<span style="color: #339933;">)</span><br /> &nbsp; &nbsp; <span style="color: #b1b100; font-weight: bold;">for</span> <span style="">i</span> <span style="color: #339933;">:=</span> <span style="color: #cc66cc;">0</span><span style="color: #339933;">;</span> <span style="">i</span> &lt; forks<span style="color: #339933;">;</span> <span style="">i</span><span style="color: #339933;">++</span> <span style="color: #339933;">{</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; t<span style="color: #339933;">.</span>forks<span style="color: #339933;">[</span><span style="">i</span><span style="color: #339933;">]</span> <span style="color: #339933;">=</span> <span style="color: #000066;">new</span><span style="color: #339933;">(</span>Fork<span style="color: #339933;">)</span><br /> &nbsp; &nbsp; <span style="color: #339933;">}</span><br /> &nbsp; &nbsp; <span style="color: #b1b100; font-weight: bold;">return</span> t<br /> <span style="color: #339933;">}</span><br /> <br /> <span style="color: #993333;">func</span> <span style="color: #339933;">(</span>t <span style="color: #339933;">*</span>Table<span style="color: #339933;">)</span> PushPhilosopher<span style="color: #339933;">(</span>p Philosopher<span style="color: #339933;">)</span> <span style="color: #339933;">{</span><br /> &nbsp; &nbsp; p<span style="color: #339933;">.</span>table <span style="color: #339933;">=</span> t<br /> &nbsp; &nbsp; t<span style="color: #339933;">.</span>philosophers &lt;<span style="color: #339933;">-</span> p<br /> <span style="color: #339933;">}</span><br /> <br /> <span style="color: #993333;">func</span> <span style="color: #339933;">(</span>t <span style="color: #339933;">*</span>Table<span style="color: #339933;">)</span> PopPhilosopher<span style="color: #339933;">()</span> Philosopher <span style="color: #339933;">{</span><br /> &nbsp; &nbsp; p <span style="color: #339933;">:=</span> &lt;<span style="color: #339933;">-</span>t<span style="color: #339933;">.</span>philosophers<br /> &nbsp; &nbsp; p<span style="color: #339933;">.</span>table <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">nil</span><br /> &nbsp; &nbsp; <span style="color: #b1b100; font-weight: bold;">return</span> p<br /> <span style="color: #339933;">}</span><br /> <br /> <span style="color: #993333;">func</span> <span style="color: #339933;">(</span>t <span style="color: #339933;">*</span>Table<span style="color: #339933;">)</span> RightFork<span style="color: #339933;">(</span>philosopherIndex <span style="color: #993333;">int</span><span style="color: #339933;">)</span> <span style="color: #339933;">*</span>Fork <span style="color: #339933;">{</span><br /> &nbsp; &nbsp; f <span style="color: #339933;">:=</span> t<span style="color: #339933;">.</span>forks<span style="color: #339933;">[</span>philosopherIndex<span style="color: #339933;">]</span><br /> &nbsp; &nbsp; <span style="color: #b1b100; font-weight: bold;">return</span> f<br /> <span style="color: #339933;">}</span><br /> <br /> <span style="color: #993333;">func</span> <span style="color: #339933;">(</span>t <span style="color: #339933;">*</span>Table<span style="color: #339933;">)</span> LeftFork<span style="color: #339933;">(</span>philosopherIndex <span style="color: #993333;">int</span><span style="color: #339933;">)</span> <span style="color: #339933;">*</span>Fork <span style="color: #339933;">{</span><br /> &nbsp; &nbsp; f <span style="color: #339933;">:=</span> t<span style="color: #339933;">.</span>forks<span style="color: #339933;">[(</span>philosopherIndex <span style="color: #339933;">+</span> <span style="color: #cc66cc;">1</span><span style="color: #339933;">)</span> <span style="color: #339933;">%</span> <span style="color: #000066;">len</span><span style="color: #339933;">(</span>t<span style="color: #339933;">.</span>forks<span style="color: #339933;">)]</span><br /> &nbsp; &nbsp; <span style="color: #b1b100; font-weight: bold;">return</span> f<br /> <span style="color: #339933;">}</span><br /> <br /> <span style="color: #b1b100; font-weight: bold;">type</span> Philosopher <span style="color: #993333;">struct</span> <span style="color: #339933;">{</span><br /> &nbsp; &nbsp; name <span style="color: #993333;">string</span><br /> &nbsp; &nbsp; index <span style="color: #993333;">int</span><br /> &nbsp; &nbsp; table <span style="color: #339933;">*</span>Table<br /> &nbsp; &nbsp; fed <span style="color: #993333;">chan</span> <span style="color: #993333;">int</span><br /> <span style="color: #339933;">}</span><br /> <br /> <span style="color: #993333;">func</span> <span style="color: #339933;">(</span>p Philosopher<span style="color: #339933;">)</span> Think<span style="color: #339933;">()</span> <span style="color: #339933;">{</span><br /> &nbsp; &nbsp; fmt<span style="color: #339933;">.</span>Printf<span style="color: #339933;">(</span><span style="color: #cc66cc;">&quot;%s is thinking...<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span> p<span style="color: #339933;">.</span>name<span style="color: #339933;">)</span><br /> &nbsp; &nbsp; time<span style="color: #339933;">.</span>Sleep<span style="color: #339933;">(</span><span style="">3e9</span><span style="color: #339933;">)</span><br /> &nbsp; &nbsp; p<span style="color: #339933;">.</span>table<span style="color: #339933;">.</span>PushPhilosopher<span style="color: #339933;">(</span>p<span style="color: #339933;">)</span><br /> <span style="color: #339933;">}</span><br /> <br /> <span style="color: #993333;">func</span> <span style="color: #339933;">(</span>p Philosopher<span style="color: #339933;">)</span> Eat<span style="color: #339933;">()</span> <span style="color: #339933;">{</span><br /> &nbsp; &nbsp; p<span style="color: #339933;">.</span>GetForks<span style="color: #339933;">()</span><br /> &nbsp; &nbsp; fmt<span style="color: #339933;">.</span>Printf<span style="color: #339933;">(</span><span style="color: #cc66cc;">&quot;%s is eating...<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span> p<span style="color: #339933;">.</span>name<span style="color: #339933;">)</span><br /> &nbsp; &nbsp; time<span style="color: #339933;">.</span>Sleep<span style="color: #339933;">(</span><span style="">3e9</span><span style="color: #339933;">)</span><br /> &nbsp; &nbsp; p<span style="color: #339933;">.</span>PutForks<span style="color: #339933;">()</span><br /> &nbsp; &nbsp; p<span style="color: #339933;">.</span>table<span style="color: #339933;">.</span>PopPhilosopher<span style="color: #339933;">()</span><br /> &nbsp; &nbsp; p<span style="color: #339933;">.</span>fed &lt;<span style="color: #339933;">-</span> <span style="color: #cc66cc;">1</span><br /> <span style="color: #339933;">}</span><br /> <br /> <span style="color: #993333;">func</span> <span style="color: #339933;">(</span>p Philosopher<span style="color: #339933;">)</span> GetForks<span style="color: #339933;">()</span> <span style="color: #339933;">{</span><br /> &nbsp; &nbsp; rightFork <span style="color: #339933;">:=</span> p<span style="color: #339933;">.</span>table<span style="color: #339933;">.</span>RightFork<span style="color: #339933;">(</span>p<span style="color: #339933;">.</span>index<span style="color: #339933;">)</span><br /> &nbsp; &nbsp; rightFork<span style="color: #339933;">.</span>Lock<span style="color: #339933;">()</span><br /> <br /> &nbsp; &nbsp; leftFork <span style="color: #339933;">:=</span> p<span style="color: #339933;">.</span>table<span style="color: #339933;">.</span>LeftFork<span style="color: #339933;">(</span>p<span style="color: #339933;">.</span>index<span style="color: #339933;">)</span><br /> &nbsp; &nbsp; leftFork<span style="color: #339933;">.</span>Lock<span style="color: #339933;">()</span><br /> <span style="color: #339933;">}</span><br /> <br /> <span style="color: #993333;">func</span> <span style="color: #339933;">(</span>p Philosopher<span style="color: #339933;">)</span> PutForks<span style="color: #339933;">()</span> <span style="color: #339933;">{</span><br /> &nbsp; &nbsp; rightFork <span style="color: #339933;">:=</span> p<span style="color: #339933;">.</span>table<span style="color: #339933;">.</span>RightFork<span style="color: #339933;">(</span>p<span style="color: #339933;">.</span>index<span style="color: #339933;">)</span><br /> &nbsp; &nbsp; rightFork<span style="color: #339933;">.</span>Unlock<span style="color: #339933;">()</span><br /> <br /> &nbsp; &nbsp; leftFork <span style="color: #339933;">:=</span> p<span style="color: #339933;">.</span>table<span style="color: #339933;">.</span>LeftFork<span style="color: #339933;">(</span>p<span style="color: #339933;">.</span>index<span style="color: #339933;">)</span><br /> &nbsp; &nbsp; leftFork<span style="color: #339933;">.</span>Unlock<span style="color: #339933;">()</span><br /> <span style="color: #339933;">}</span><br /> <br /> <span style="color: #993333;">func</span> main<span style="color: #339933;">()</span> <span style="color: #339933;">{</span><br /> &nbsp; &nbsp; table <span style="color: #339933;">:=</span> NewTable<span style="color: #339933;">(</span><span style="color: #cc66cc;">5</span><span style="color: #339933;">)</span><br /> &nbsp; &nbsp; philosophers <span style="color: #339933;">:=</span> <span style="color: #339933;">[]</span>Philosopher<span style="color: #339933;">{</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; Philosopher<span style="color: #339933;">{</span><span style="color: #cc66cc;">&quot;Thomas Nagel&quot;</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">0</span><span style="color: #339933;">,</span> table<span style="color: #339933;">,</span> <span style="color: #000066;">make</span><span style="color: #339933;">(</span><span style="color: #993333;">chan</span> <span style="color: #993333;">int</span><span style="color: #339933;">)},</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; Philosopher<span style="color: #339933;">{</span><span style="color: #cc66cc;">&quot;Elizabeth Anscombe&quot;</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">1</span><span style="color: #339933;">,</span> table<span style="color: #339933;">,</span> <span style="color: #000066;">make</span><span style="color: #339933;">(</span><span style="color: #993333;">chan</span> <span style="color: #993333;">int</span><span style="color: #339933;">)},</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; Philosopher<span style="color: #339933;">{</span><span style="color: #cc66cc;">&quot;Martin Heidegger&quot;</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">2</span><span style="color: #339933;">,</span> table<span style="color: #339933;">,</span> <span style="color: #000066;">make</span><span style="color: #339933;">(</span><span style="color: #993333;">chan</span> <span style="color: #993333;">int</span><span style="color: #339933;">)},</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; Philosopher<span style="color: #339933;">{</span><span style="color: #cc66cc;">&quot;Peter Lombard&quot;</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">3</span><span style="color: #339933;">,</span> table<span style="color: #339933;">,</span> <span style="color: #000066;">make</span><span style="color: #339933;">(</span><span style="color: #993333;">chan</span> <span style="color: #993333;">int</span><span style="color: #339933;">)},</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; Philosopher<span style="color: #339933;">{</span><span style="color: #cc66cc;">&quot;Gottfried Leibniz&quot;</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">4</span><span style="color: #339933;">,</span> table<span style="color: #339933;">,</span> <span style="color: #000066;">make</span><span style="color: #339933;">(</span><span style="color: #993333;">chan</span> <span style="color: #993333;">int</span><span style="color: #339933;">)},</span><br /> &nbsp; &nbsp; <span style="color: #339933;">}</span><br /> <br /> &nbsp; &nbsp; <span style="color: #b1b100; font-weight: bold;">for</span> <span style="color: #339933;">{</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100; font-weight: bold;">for</span> _<span style="color: #339933;">,</span> p <span style="color: #339933;">:=</span> <span style="color: #b1b100; font-weight: bold;">range</span> philosophers <span style="color: #339933;">{</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100; font-weight: bold;">go</span> <span style="color: #993333;">func</span><span style="color: #339933;">(</span>p Philosopher<span style="color: #339933;">){</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; p<span style="color: #339933;">.</span>Think<span style="color: #339933;">()</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; p<span style="color: #339933;">.</span>Eat<span style="color: #339933;">()</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #339933;">}(</span>p<span style="color: #339933;">)</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #339933;">}</span><br /> <br /> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100; font-weight: bold;">for</span> _<span style="color: #339933;">,</span> p <span style="color: #339933;">:=</span> <span style="color: #b1b100; font-weight: bold;">range</span> philosophers <span style="color: #339933;">{</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;<span style="color: #339933;">-</span>p<span style="color: #339933;">.</span>fed<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fmt<span style="color: #339933;">.</span>Printf<span style="color: #339933;">(</span><span style="color: #cc66cc;">&quot;%s was fed.<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span> p<span style="color: #339933;">.</span><span style="">name</span><span style="color: #339933;">)</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #339933;">}</span><br /> &nbsp; &nbsp; <span style="color: #339933;">}</span><br /> <br /> <span style="color: #339933;">}</span></div></div><p>Any feedback is very welcome :)</p> ]]></content:encoded> <wfw:commentRss>http://f.souza.cc/2011/10/go-solution-of-the-dining-philosophers-problem/feed/</wfw:commentRss> <slash:comments>2</slash:comments> </item> <item><title>Don&#8217;t rely on caching</title><link>http://f.souza.cc/2011/10/dont-rely-on-caching/</link> <comments>http://f.souza.cc/2011/10/dont-rely-on-caching/#comments</comments> <pubDate>Thu, 06 Oct 2011 23:29:31 +0000</pubDate> <dc:creator>Francisco Souza</dc:creator> <category><![CDATA[software development]]></category> <category><![CDATA[cache]]></category> <category><![CDATA[django]]></category> <category><![CDATA[memcached]]></category> <category><![CDATA[python]]></category><guid isPermaLink="false">http://f.souza.cc/?p=586</guid> <description><![CDATA[Don’t rely on cache. Cache doesn’t exist to make applications work, it exists to make them faster and/or more scalable.]]></description> <content:encoded><![CDATA[<p>Extracted from <a href="http://f.souza.cc/tag/django" title="Posts about Django">Django</a> docs: <em>&#8220;memory isn&#8217;t intended for permanent data storage, so don&#8217;t rely on memory-based caching as your only data storage. Without a doubt, none of the Django caching backends should be used for permanent storage&#8221;</em>.</p><p>Here is the lesson: don&#8217;t rely on caching. Cache doesn&#8217;t exist to make applications work, it exists to make them faster and/or more scalable. Use a cache system as permanent storage is such a bad idea, except when you&#8217;re not using it for caching (what is not the case here). Cache is a shortcut for a path that might be painful to follow, but you still should not rely on cache. You must be able to traverse the path without the cache.</p> ]]></content:encoded> <wfw:commentRss>http://f.souza.cc/2011/10/dont-rely-on-caching/feed/</wfw:commentRss> <slash:comments>4</slash:comments> </item> <item><title>Speaking at PythonBrasil[7]</title><link>http://f.souza.cc/2011/09/speaking-at-pythonbrasil7/</link> <comments>http://f.souza.cc/2011/09/speaking-at-pythonbrasil7/#comments</comments> <pubDate>Sat, 24 Sep 2011 03:43:01 +0000</pubDate> <dc:creator>Francisco Souza</dc:creator> <category><![CDATA[conferences]]></category> <category><![CDATA[django]]></category> <category><![CDATA[python]]></category> <category><![CDATA[scalability]]></category> <category><![CDATA[talks]]></category><guid isPermaLink="false">http://f.souza.cc/?p=568</guid> <description><![CDATA[Next weekend I’ll be talking about scaling Django applications at Python Brasil, the brazilian Python conference. It will be my first time at the conference, which is one of the greatest Python conferences in Latin America. Some international dudes are also attending to the conference.]]></description> <content:encoded><![CDATA[<p><img src="http://c.souza.cc/s/2011/09/python-brasil.png" alt="PythonBrasil[7]" title="PythonBrasil[7]" width="179" height="150" class="alignleft size-full wp-image-572" />Next weekend I&#8217;ll be talking about scaling Django applications at <a href="http://www.pythonbrasil.org.br" title="PythonBrasil[7]" target="_blank" rel="nofollow">Python Brasil</a>, the brazilian Python conference. It will be my first time at the conference, which is one of the greatest <a href="http://f.souza.cc/tag/python" title="Posts about Python">Python</a> conferences in Latin America.</p><p>Some international dudes are also attending to the conference: <a href="http://cyberwebconsulting.com/" title="Wesley Chun" target="_blank" rel="nofollow">Wesley Chun</a> is going to talk about Python 3 and Google App Engine; <a href="http://www.enfoldsystems.com/" title="Alan Runyan" target="_blank" rel="nofollow">Alan Runyan</a> will talk about free and open source software, and <a href="http://holdenweb.com/" title="Steve Holden" target="_blank" rel="nofollow">Steve Holden</a> will be talking about the issues involved in trying to build a global Python user group.<span id="more-568"></span></p><p>There is also <a href="https://twitter.com/#!/fijall" title="Maciej Fijalkowski" target="_blank">Maciej Fijalkowski</a>, PyPy core developer, talking about little things PyPy makes possible.</p><p>As I pointed before, I&#8217;m going to talk about scalability, based in some experiences aquired scaling Django applications at <a href="http://globo.com" title="Globo.com" target="_blank" rel="nofollow">Globo.com</a>, like <a href="http://g1.globo.com" title="G1" target="_blank" rel="nofollow">G1</a>, the greatest news portal in the Latin America.</p> ]]></content:encoded> <wfw:commentRss>http://f.souza.cc/2011/09/speaking-at-pythonbrasil7/feed/</wfw:commentRss> <slash:comments>1</slash:comments> </item> <item><title>Creating HTML 5 slide presentations using landslide</title><link>http://f.souza.cc/2011/09/creating-html-5-slide-presentations-using-landslide/</link> <comments>http://f.souza.cc/2011/09/creating-html-5-slide-presentations-using-landslide/#comments</comments> <pubDate>Wed, 21 Sep 2011 00:58:31 +0000</pubDate> <dc:creator>Francisco Souza</dc:creator> <category><![CDATA[talks]]></category> <category><![CDATA[html5]]></category> <category><![CDATA[landslide]]></category> <category><![CDATA[presentations]]></category> <category><![CDATA[python]]></category><guid isPermaLink="false">http://f.souza.cc/?p=511</guid> <description><![CDATA[Recently I found landslide, which is a Python tool for creating HTML 5 slide presentations.It’s based in a famous slide presentation. It’s a simple script that generates HTML from a source file, which can be formatted using reStructuredText, Textile or Markdown.]]></description> <content:encoded><![CDATA[<p><img class="size-full wp-image-529 alignright" title="HTML 5 slide" src="http://c.souza.cc/s/2011/09/slide.jpg" alt="HTML 5 slide" width="250" height="156" />Recently I found <a title="landslide is a tool for creating HTML 5 slide presentations" href="https://github.com/adamzap/landslide" rel="nofollow" target="_blank">landslide</a>, which is a <a title="Posts about Python" href="http://f.souza.cc/tag/python">Python</a> tool for creating HTML 5 slide presentations.</p><p>It&#8217;s based in a <a title="HTML 5 slide presentation" href="http://slides.html5rocks.com/" rel="nofollow" target="_blank">famous slide presentation</a>. It&#8217;s a simple script that generates HTML from a source file, which can be formatted using <a title="reStructuredText" href="http://docutils.sourceforge.net/docs/ref/rst/introduction.html" rel="nofollow" target="_blank">reStructuredText</a>, <a title="Textile" href="http://www.textism.com/tools/textile/" rel="nofollow" target="_blank">Textile</a> or <a title="Markdown" href="http://daringfireball.net/projects/markdown/" rel="nofollow" target="_blank">Markdown</a>.</p><p>Let&#8217;s make a very simple presentation as a proof of concept: we&#8217;re going to create a &#8220;Python flow control&#8221; presentation, showing some basic structures of the language: if, for and while. We need a cover, a slide for each structure (with some topics and code examples) and the last slide for questions and answers. Here is the RST code for it:<span id="more-511"></span></p><div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">Python<br /> ======<br /> <br /> --------------<br /> <br /> If<br /> ==<br /> <br /> * Please don't use ()<br /> * Never forget the ``:`` at the end of the line<br /> <br /> Check this code:<br /> <br /> .. sourcecode:: python<br /> <br /> &nbsp; &nbsp; x, y = 1, 2<br /> &nbsp; &nbsp; if x &gt; y:<br /> &nbsp; &nbsp; &nbsp; &nbsp; print 'x is greater'<br /> <br /> --------------<br /> <br /> For<br /> ===<br /> <br /> * ``for`` iterates over a sequence<br /> * Never forget the ``:`` at the end of the line<br /> <br /> Check this code:<br /> <br /> .. sourcecode:: python<br /> <br /> &nbsp; &nbsp; numbers = [1, 2, 3, 4, 5,]<br /> &nbsp; &nbsp; for number in numbers:<br /> &nbsp; &nbsp; &nbsp; &nbsp; print number<br /> <br /> --------------<br /> <br /> While<br /> =====<br /> <br /> * ``while`` is like ``if``, but executes while the codition is ``True``<br /> * please don't use ()<br /> * never forget the ``:`` at the end of the line<br /> <br /> Check this code:<br /> <br /> .. sourcecode:: python<br /> <br /> &nbsp; &nbsp; from random import randint<br /> <br /> &nbsp; &nbsp; args = (1, 10,)<br /> &nbsp; &nbsp; x = randint(*args)<br /> &nbsp; &nbsp; while x != 6:<br /> &nbsp; &nbsp; &nbsp; &nbsp; x = randint(*args)<br /> <br /> --------------<br /> <br /> Thank you!<br /> ==========</div></div><p>As you can see it&#8217;s very simple. If you&#8217;re familiar with RST syntax, you can guess what landslide does: it converts the entire content to HTML and then split it by <code class="codecolorer text default"><span class="text">&lt;hr /&gt;</span></code> tag. Each slide will contain two sections: a header and a body. The header contains only an <code class="codecolorer text default"><span class="text">&lt;h1&gt;&lt;/h1&gt;</span></code> element and the body contains everything.</p><p>We can generate the HTML output by calling the <code class="codecolorer bash default"><span class="bash">landslide</span></code> command in the terminal:</p><div class="codecolorer-container bash default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #666666;">$ </span>landslide python.rst</div></div><p>To use <code class="codecolorer bash default"><span class="bash">landslide</span></code> command, you need to install it. I suggest you do this via pip:</p><div class="codecolorer-container bash default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #666666;">$ </span><span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #c20cb9; font-weight: bold;">sudo</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> pip <span style="color: #c20cb9; font-weight: bold;">install</span> landslide</div></div><p>landslide supports theming, so you can customize it by creating your own theme. Your theme should contain two CSS files: screen.css (for the HTML version of slides) and print.css (for the PDF version of the slides). You might also customize the HTML (base.html) and JS files (slides.js), but you <strong>have</strong> to customize the CSS files in your theme. You specify the theme using the <code class="codecolorer text default"><span class="text">--theme</span></code> directive. You might want to check all options available in the command line utility using <code class="codecolorer text default"><span class="text">--help</span></code>:</p><div class="codecolorer-container bash default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #666666;">$ </span>landslide <span style="color: #660033;">--help</span></div></div><p>It&#8217;s quite easy to extend landslide changing its theme or adding new macros. Check the <a title="landslide at Github" href="https://github.com/adamzap/landslide" target="_blank" rel="nofollow">official repository at Github</a>. This example, and a <a title="Markdown version for the slide presentation" href="https://github.com/fsouza/landslide-example/blob/master/python.markdown" target="_blank">markdown version</a> for the same example are available in a <a title="landslide example" href="https://github.com/fsouza/landslide-example" target="_blank">repository</a> in <a title="Francisco Souza at github" href="http://github.com/fsouza" target="_blank">my github profile</a>.</p><p>You can also see the <a href="http://p.souza.cc/landslide-example/" title="landslide example" target="_blank">slides live</a>!</p> ]]></content:encoded> <wfw:commentRss>http://f.souza.cc/2011/09/creating-html-5-slide-presentations-using-landslide/feed/</wfw:commentRss> <slash:comments>3</slash:comments> </item> <item><title>Splinter sprint on FISL</title><link>http://f.souza.cc/2011/06/splinter-sprint-on-fisl/</link> <comments>http://f.souza.cc/2011/06/splinter-sprint-on-fisl/#comments</comments> <pubDate>Tue, 28 Jun 2011 16:53:39 +0000</pubDate> <dc:creator>Francisco Souza</dc:creator> <category><![CDATA[software development]]></category> <category><![CDATA[django]]></category> <category><![CDATA[open source]]></category> <category><![CDATA[python]]></category> <category><![CDATA[splinter]]></category> <category><![CDATA[sprints]]></category><guid isPermaLink="false">http://www.franciscosouza.com/?p=465</guid> <description><![CDATA[We are going to start tomorrow, on FISL, another splinter sprint. "From June 29 through July 2, 2011, fisl12 will be hosted at the PUC Events Center, in Porto Alegre, Rio Grande do Sul, Brazil.". But don't worry about the location: anyone in anywhere can join us in this sprint. There is an entry in splinter wiki about this sprint, and I'm just replicating the information here...]]></description> <content:encoded><![CDATA[<p><img class="alignleft" title="FISL" src="http://c.souza.cc/s/2011/06/fisl-logo1.jpg" alt="FISL" width="200" height="199" />We are going to start tomorrow, on <a title="FISL" href="http://fisl.softwarelivre.org" target="_blank">FISL</a>, another <a title="Splinter" href="http://splinter.cobrateam.info" target="_blank">splinter</a> sprint. <em>&#8220;From June 29 through July 2, 2011, fisl12 will be hosted at the PUC Events Center, in Porto Alegre, Rio Grande do Sul, Brazil&#8221; </em>(copied from FISL website :P). But don&#8217;t worry about the location: anyone in anywhere can join us in this sprint. There is an <a title="splinter sprint on FISL" href="https://github.com/cobrateam/splinter/wiki/sprint29jun2011" target="_blank">entry</a> in splinter wiki about this sprint, and I&#8217;m just replicating the information here&#8230;</p><p><span id="more-465"></span></p><h3>What is a splinter sprint?</h3><p>Basically, a splinter sprint is an excuse for people to focus their undivided attention, for a set time frame, on improving splinter. It&#8217;s a focused, scheduled effort to fix bugs, add new features and improve documentation.</p><p>Anybody, anywhere around the world, can participate and contribute. If you&#8217;ve never contributed to splinter before, this is the perfect chance for you to chip in.</p><h3>How to contribute</h3><ol><li>Choose an <a title="splinter issues" href="https://github.com/cobrateam/splinter/issues" target="_blank">issue</a></li><li>Create a fork</li><li>Send a pull request</li></ol><p><em>Remember: all new features should be well tested and documented. An issue can&#8217;t be closed if there isn&#8217;t docs for the solution code.</em></p><h3>Preparing for the sprint</h3><p>Get a <a title="IRC" href="http://en.wikipedia.org/wiki/Internet_Relay_Chat" target="_blank">IRC</a> client, so that you can join us in the channel <a title="cobrateam" href="http://cobrateam.info" target="_blank">#cobrateam</a> on Freenode.</p><p>See all you there :)</p> ]]></content:encoded> <wfw:commentRss>http://f.souza.cc/2011/06/splinter-sprint-on-fisl/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>Testing jQuery plugins with Jasmine</title><link>http://f.souza.cc/2011/05/testing-jquery-plugins-with-jasmine/</link> <comments>http://f.souza.cc/2011/05/testing-jquery-plugins-with-jasmine/#comments</comments> <pubDate>Sat, 28 May 2011 22:16:07 +0000</pubDate> <dc:creator>Francisco Souza</dc:creator> <category><![CDATA[software development]]></category> <category><![CDATA[bdd]]></category> <category><![CDATA[jasmine]]></category> <category><![CDATA[javascript]]></category> <category><![CDATA[jquery]]></category> <category><![CDATA[tdd]]></category><guid isPermaLink="false">http://www.franciscosouza.com/?p=352</guid> <description><![CDATA[Learn how to test your jQuery plugins using Jasmine, a JavaScript BDD framework.]]></description> <content:encoded><![CDATA[<p><img class="alignright size-full wp-image-364" title="Jasmine" src="http://c.souza.cc/s/2011/05/jasmine_logo.png" alt="Jasmine" width="150" height="48" />Since I started working at <a title="Globo.com" rel="nofollow" href="http://globo.com" target="_blank">Globo.com</a>, I developed some jQuery plugins (for internal use) with my team, and we are starting to test these plugins using <a title="Jasmine" rel="nofollow" href="http://pivotal.github.com/jasmine/" target="_blank">Jasmine</a>, <em>&#8220;a behavior-driven development framework for testing your JavaScript code&#8221;</em>. In this post, I&#8217;ll show how to develop a very simple jQuery plugin (based on an example that I learned with <a title="Richard D. Worth" href="http://rdworth.org/" target="_blank">Ricard D. Worth</a>): zebrafy. This plugin &#8220;zebrafies&#8221; a table, applying different classes to odd and even lines. Let&#8217;s start setting up a Jasmine environment&#8230;<span id="more-352"></span></p><p>First step is download the <a title="Download standalone Jasmine" href="http://pivotal.github.com/jasmine/download.html" target="_blank">standalone version of Jasmine</a>, then extract it and edit the runner. The runner is a simple HTML file, that loads Jasmine and all JavaScript files you want to test. But, wait&#8230; why not test using node.js or something like this? Do I really need the browser on this test? You don&#8217;t *need*, but I think it is important to test a plugin that works with the DOM using a real browser. Let&#8217;s delete some files and lines from <em>SpecRunner.html</em> file, so we adapt it for our plugin. This is how the structure is going to look like:</p><pre>.
├── SpecRunner.html
├── lib
│   ├── jasmine-1.0.2
│   │   ├── MIT.LICENSE
│   │   ├── jasmine-html.js
│   │   ├── jasmine.css
│   │   └── jasmine.js
│   └── jquery-1.6.1.min.js
├── spec
│   └── ZebrafySpec.js
└── src
    └── jquery.zebrafy.js</pre><p>You can create the files <em>jquery.zebrafy.js</em> and <em>ZebrafySpec.js</em>, but remember: it is <a href="http://www.franciscosouza.com/tag/bdd" title="Posts about BDD">BDD</a>, we need to describe first the behavior we want, then write the code. So let&#8217;s start to write the specs in <em>ZebrafySpec.js</em> file using Jasmine. If you are familiar with RSpec syntax, it&#8217;s easy to understand how to write spec withs Jasmine, if you aren&#8217;t, here is the clue: Jasmine is a lib with some functions used for writing tests in an easier way. I&#8217;m going to explain each function &#8220;on demmand&#8221;, when we need something, we learn how to use it! ;)</p><p>First of all, we need to start a new test suite. Jasmine provides the <em>describe</em> function for that, this function receives a string and another function. The string describes the test suite and the function is a callback that delimites the scope of the test suite. Here is the <em>Zebrafy</em>suite:</p><div class="codecolorer-container javascript default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">describe<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'Zebrafy'</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span> <span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br /> <br /> <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></div><p>Let&#8217;s start describing the behavior we want to get from the plugin. The most basic is: we want different CSS classes for odd an even lines in a table. Jasmine provides the <em>it</em> function for writing the tests. It also receives a string and a callback: the string is a description for the test and the callback is the function executed as test. Here is the test:</p><div class="codecolorer-container javascript default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">it<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'should apply classes zebrafy-odd and zebrafy-even to each other table lines'</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span> <span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br /> &nbsp; &nbsp; <span style="color: #003366; font-weight: bold;">var</span> table <span style="color: #339933;">=</span> $<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;#zebra-table&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br /> &nbsp; &nbsp; table.<span style="color: #660066;">zebrafy</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br /> &nbsp; &nbsp; expect<span style="color: #009900;">&#40;</span>table<span style="color: #009900;">&#41;</span>.<span style="color: #660066;">toBeZebrafyied</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br /> <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></div><p><img src="http://c.souza.cc/s/2011/05/jquery_logo.png" alt="jQuery" title="jQuery" width="150" height="37" class="alignleft size-full wp-image-412" />Okay, here we go: in the first line of the callback, we are using jQuery to select a table using the <em>#zebra-table</em> selector, which will look up for a table with the ID attribute equals to &#8220;zebra-table&#8221;, but we don&#8217;t have this table in the DOM. What about add a new table to the DOM in a hook executed <em>before</em> the test run and remove the table in another hook that runs <em>after</em> the the test? Jasmine provide two functions: <em>beforeEach</em> and <em>afterEach</em>. Both functions receive a callback function to be executed and, as the names suggest, the <em>beforeEach</em> callback is called before each test run, and the <em>afterEach</em> callback is called after the test run. And here are the hooks:</p><div class="codecolorer-container javascript default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">beforeEach<span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span> <span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br /> &nbsp; &nbsp; $<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'&lt;table id=&quot;zebra-table&quot;&gt;&lt;/table&gt;'</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">appendTo</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'body'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br /> &nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">for</span> <span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">var</span> i<span style="color: #339933;">=</span><span style="color: #CC0000;">0</span><span style="color: #339933;">;</span> i <span style="color: #339933;">&lt;</span> <span style="color: #CC0000;">10</span><span style="color: #339933;">;</span> i<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; $<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'&lt;tr&gt;&lt;/tr&gt;'</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">append</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'&lt;td&gt;&lt;/td&gt;'</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">append</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'&lt;td&gt;&lt;/td&gt;'</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">append</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'&lt;td&gt;&lt;/td&gt;'</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">appendTo</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'#zebra-table'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br /> &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span><br /> <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br /> <br /> afterEach<span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span> <span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br /> &nbsp; &nbsp; $<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;#zebra-table&quot;</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">remove</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br /> <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></div><p>The <em>beforeEach</em> callback uses jQuery to create a table with 10 rows and 3 columns and add it to the DOM. In <em>afterEach</em> callback, we just remove that table using jQuery again. Okay, now the table exists, let&#8217;s go back to the test:</p><div class="codecolorer-container javascript default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">it<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'should apply classes zebrafy-odd and zebrafy-even to each other table lines'</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span> <span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br /> &nbsp; &nbsp; <span style="color: #003366; font-weight: bold;">var</span> table <span style="color: #339933;">=</span> $<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;#zebra-table&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br /> &nbsp; &nbsp; table.<span style="color: #660066;">zebrafy</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br /> &nbsp; &nbsp; expect<span style="color: #009900;">&#40;</span>table<span style="color: #009900;">&#41;</span>.<span style="color: #660066;">toBeZebrafyied</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br /> <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></div><p>In second line, we call our plugin, that is not ready yet, so let&#8217;s forward to the next line, where we used the <em>expect</em> function. Jasmine provides this function, that receives an object and executes a <em>matcher</em> against it, there are a lot of built-in matchers on Jasmine, but <em>toBeZebrafyied</em> is not a built-in matcher. Here is where we know another Jasmine feature: the capability to write custom matchers, but how to do this? You can call the <em>beforeEach</em> again, and use the <em>addMatcher</em> method of Jasmine object:</p><div class="codecolorer-container javascript default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">beforeEach<span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span> <span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br /> &nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">this</span>.<span style="color: #660066;">addMatchers</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#123;</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; toBeZebrafyied<span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #003366; font-weight: bold;">var</span> isZebrafyied <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">true</span><span style="color: #339933;">;</span><br /> <br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">this</span>.<span style="color: #660066;">actual</span>.<span style="color: #660066;">find</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;tr:even&quot;</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">each</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span> <span style="color: #009900;">&#40;</span>index<span style="color: #339933;">,</span> tr<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; isZebrafyied <span style="color: #339933;">=</span> $<span style="color: #009900;">&#40;</span>tr<span style="color: #009900;">&#41;</span>.<span style="color: #660066;">hasClass</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'zebrafy-odd'</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">===</span> <span style="color: #003366; font-weight: bold;">false</span> <span style="color: #339933;">&amp;&amp;</span> $<span style="color: #009900;">&#40;</span>tr<span style="color: #009900;">&#41;</span>.<span style="color: #660066;">hasClass</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'zebrafy-even'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>isZebrafyied<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">return</span><span style="color: #339933;">;</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br /> <br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">this</span>.<span style="color: #660066;">actual</span>.<span style="color: #660066;">find</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;tr:odd&quot;</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">each</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span> <span style="color: #009900;">&#40;</span>index<span style="color: #339933;">,</span> tr<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; isZebrafyied <span style="color: #339933;">=</span> $<span style="color: #009900;">&#40;</span>tr<span style="color: #009900;">&#41;</span>.<span style="color: #660066;">hasClass</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'zebrafy-odd'</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">&amp;&amp;</span> $<span style="color: #009900;">&#40;</span>tr<span style="color: #009900;">&#41;</span>.<span style="color: #660066;">hasClass</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'zebrafy-even'</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">===</span> <span style="color: #003366; font-weight: bold;">false</span><span style="color: #339933;">;</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>isZebrafyied<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">return</span><span style="color: #339933;">;</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br /> <br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">return</span> isZebrafyied<span style="color: #339933;">;</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br /> &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br /> <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></div><p>The method <em>addMatchers</em> receives an object where each property is a matcher. Your matcher can receive arguments if you want. The object being matched can be accessed using <em>this.actual</em>, so here is what the method above does: it takes all odd <em>&lt;tr&gt;</em> elements of the table (<em>this.actual</em>) and check if them have the CSS class <em>zebrafy-odd</em> and don&#8217;t have the CSS class <em>zebrafy-even</em>, then do the same checking with even <em>&lt;tr&gt;</em> lines.</p><p>Now we have wrote the test, it&#8217;s time to write the plugin. Here some jQuery code:</p><div class="codecolorer-container javascript default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span> <span style="color: #009900;">&#40;</span>$<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br /> &nbsp; &nbsp; $.<span style="color: #660066;">fn</span>.<span style="color: #660066;">zebrafy</span> <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">function</span> <span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">this</span>.<span style="color: #660066;">find</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;tr:even&quot;</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">addClass</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;zebrafy-even&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">this</span>.<span style="color: #660066;">find</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;tr:odd&quot;</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">addClass</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;zebrafy-odd&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br /> &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span><br /> <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#40;</span>jQuery<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></div><p>I&#8217;m not going to explain <a href="http://docs.jquery.com/Plugins/Authoring" title="jQuery plugin authoring" rel="nofollow" target="_blank">how to implement a jQuery plugin</a> neither <a href="http://benalman.com/news/2010/11/immediately-invoked-function-expression/" rel="nofollow" title="Immediately-invoked function expression" target="_blank">what are those brackets on function</a>, this post aims to show how to use Jasmine to test jQuery plugins.</p><p>By convention, jQuery plugins are &#8220;chainable&#8221;, so let&#8217;s make sure the zebrafy plugin is chainable using a spec:</p><div class="codecolorer-container javascript default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">it<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'zebrafy should be chainable'</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br /> &nbsp; &nbsp; <span style="color: #003366; font-weight: bold;">var</span> table <span style="color: #339933;">=</span> $<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;#zebra-table&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br /> &nbsp; &nbsp; table.<span style="color: #660066;">zebrafy</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">addClass</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'black-bg'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br /> &nbsp; &nbsp; expect<span style="color: #009900;">&#40;</span>table.<span style="color: #660066;">hasClass</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'black-bg'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">toBeTruthy</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br /> <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></div><p>As you can see, we used the built-in matcher <em>toBeTruthy</em>, which asserts that an object or expression is <em>true</em>. All we need to do ir return the jQuery object in the plugin and the test will pass:</p><div class="codecolorer-container javascript default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span> <span style="color: #009900;">&#40;</span>$<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br /> &nbsp; &nbsp; $.<span style="color: #660066;">fn</span>.<span style="color: #660066;">zebrafy</span> <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">function</span> <span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">return</span> <span style="color: #000066; font-weight: bold;">this</span>.<span style="color: #660066;">each</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span> <span style="color: #009900;">&#40;</span>index<span style="color: #339933;">,</span> table<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $<span style="color: #009900;">&#40;</span>table<span style="color: #009900;">&#41;</span>.<span style="color: #660066;">find</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;tr:even&quot;</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">addClass</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;zebrafy-even&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $<span style="color: #009900;">&#40;</span>table<span style="color: #009900;">&#41;</span>.<span style="color: #660066;">find</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;tr:odd&quot;</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">addClass</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;zebrafy-odd&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br /> &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span><br /> <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#40;</span>jQuery<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></div><p>So, the plugin is tested and ready to release! :) You can check the entire code and test with more spec in a <a href="https://github.com/fsouza/jquery-testing-jasmine" rel="nofollow" title="Zebrafy jQuery plugin" target="_blank">Github repository</a>.</p> ]]></content:encoded> <wfw:commentRss>http://f.souza.cc/2011/05/testing-jquery-plugins-with-jasmine/feed/</wfw:commentRss> <slash:comments>6</slash:comments> </item> <item><title>Splinter: Python tool for acceptance tests on web applications</title><link>http://f.souza.cc/2011/05/splinter-python-tool-for-acceptance-tests-on-web-applications/</link> <comments>http://f.souza.cc/2011/05/splinter-python-tool-for-acceptance-tests-on-web-applications/#comments</comments> <pubDate>Sat, 14 May 2011 19:04:39 +0000</pubDate> <dc:creator>Francisco Souza</dc:creator> <category><![CDATA[software development]]></category> <category><![CDATA[acceptance tests]]></category> <category><![CDATA[django]]></category> <category><![CDATA[python]]></category> <category><![CDATA[selenium]]></category> <category><![CDATA[splinter]]></category> <category><![CDATA[web development]]></category><guid isPermaLink="false">http://www.franciscosouza.com/?p=239</guid> <description><![CDATA[Know Splinter, a Python framework for acceptance testing on web applications.]]></description> <content:encoded><![CDATA[<p><a title="Capybara" rel="nofollow" href="https://github.com/jnicklas/capybara" target="_blank">Capybara</a> and <a title="Webrat" rel="nofollow" href="https://github.com/brynary/webrat" target="_blank">Webrat</a> are great Ruby tools for acceptance tests. A few months ago, we started a great tool for acceptance tests<img class="alignright size-full wp-image-275" title="Splinter" src="http://c.souza.cc/s/2011/05/splinter1.jpg" alt="Splinter" width="210" height="171" /> on <a title="Posts about Python" href="http://www.franciscosouza.com/tag/python" target="_self">Python</a> web applications, called <a title="Splinter" href="http://splinter.cobrateam.info" target="_blank">Splinter</a>. There are many acceptance test tools on Python world: <a title="Selenium" rel="nofollow" href="http://seleniumhq.org" target="_blank">Selenium</a>, <a title="Alfajor" rel="nofollow" href="https://github.com/idealistdev/alfajor" target="_blank">Alfajor</a>, <a title="Windmill" rel="nofollow" href="http://www.getwindmill.com/" target="_blank">Windmill</a>, <a title="Mechanize" rel="nofollow" href="http://wwwsearch.sourceforge.net/mechanize/" target="_blank">Mechanize</a>, <a title="zope.testbrowser" rel="nofollow" href="http://pypi.python.org/pypi/zope.testbrowser" target="_blank">zope.testbrowser</a>, etc. Splinter was not created to be another acceptance tool, but an abstract layer over other tools, its goal is provide a unique API that make acceptance testing easier and funnier :)</p><p>In this post, I will show some basic usage of Splinter for simple web application tests. <a title="Splinter" rel="nofollow" href="http://github.com/cobrateam/splinter" target="_blank">Splinter</a> is a tool useful on tests of any web application. You can even test a Java web application using Splinter. This post example is a &#8220;test&#8221; of a Facebook feature, just because I want to focus on how to use Splinter, not on how to write a web application. The feature to be tested is the creation of an event (the Splinter sprint), following all the flow: first the user will login on Facebook, then click on &#8220;Events&#8221; menu item, then click on &#8220;Create an Event button&#8221;, enter all event informations and click on &#8220;Create event&#8221; button. So, let&#8217;s do it&#8230;<span id="more-239"></span></p><p>First step is create a <a title="Browser class" rel="nofollow" href="https://github.com/cobrateam/splinter/blob/master/splinter/browser.py#L18" target="_blank">Browser</a> instance, which will provide method for interactions with browser (where the browser is: Firefox, Chrome, etc.). The code we need for it is very simple:</p><div class="codecolorer-container python default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">browser <span style="color: #66cc66;">=</span> Browser<span style="color: black;">&#40;</span><span style="color: #483d8b;">'webdriver.firefox'</span><span style="color: black;">&#41;</span></div></div><p>Browser is a class and its constructor receives the driver to be used with that instance. Nowadays, there are three drivers for Splinter: firefox.webdriver, chrome.webdriver and zope.testbrowser. We are using Firefox, and you can easily use Chrome by simply changing the driver from <em>webdriver.firefox</em> to <em>webdriver.chrome</em>. It&#8217;s also very simple to add another driver to Splinter, and I plan to cover how to do that on another blog post here.</p><p>A new browser session is started when we got the <em>browser</em> object, and this is the object used for Firefox interactions. Let&#8217;s start a new event on Facebook, the <em>Splinter Sprint</em>. First of all, we need to <em>visit</em> the Facebook homepage. There is a <em>visit</em> method on Browser class, so we can use it:</p><div class="codecolorer-container python default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">browser.<span style="color: black;">visit</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;http://www.facebook.com&quot;</span><span style="color: black;">&#41;</span></div></div><p><em>visit</em> method is blocking: it waits for page to load, then we can navigate, click on links, fill forms, etc. Now we have Facebook homepage opened on browser, and you probably know that we need to login on Facebook page, but what if we are already logged in? So, let&#8217;s create a method that login on Facebook with provided authentication data only the user is not logged in (imagine we are on a TestCase class):</p><div class="codecolorer-container python default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">def</span> do_login_if_need<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: #66cc66;">,</span> username<span style="color: #66cc66;">,</span> password<span style="color: black;">&#41;</span>:<br /> &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">self</span>.<span style="color: black;">browser</span>.<span style="color: black;">is_element_present_by_css</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'div.menu_login_container'</span><span style="color: black;">&#41;</span>:<br /> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">self</span>.<span style="color: black;">browser</span>.<span style="color: black;">fill</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'email'</span><span style="color: #66cc66;">,</span> username<span style="color: black;">&#41;</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">self</span>.<span style="color: black;">browser</span>.<span style="color: black;">fill</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'pass'</span><span style="color: #66cc66;">,</span> password<span style="color: black;">&#41;</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">self</span>.<span style="color: black;">browser</span>.<span style="color: black;">find_by_css</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'div.menu_login_container input[type=&quot;submit&quot;]'</span><span style="color: black;">&#41;</span>.<span style="color: black;">first</span>.<span style="color: black;">click</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">assert</span> <span style="color: #008000;">self</span>.<span style="color: black;">browser</span>.<span style="color: black;">is_element_present_by_css</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'li#navAccount'</span><span style="color: black;">&#41;</span></div></div><p>What was made here? First of all, the method checks if there is an element present on the page, using a CSS selector. It checks for the div that contains the <em>username</em> and <em>password</em> fields. If that div is present, we tell the browser object to fill those fields, then find the <em>submit</em> button and click on it. The last line is an <em>assert</em> to guarantee that the login was successful and the current page is the Facebook homepage (by checking the presence of &#8220;Account&#8221; li).</p><p>We could also find elements by its texts, labels or whatever appears on screen, but remember: Facebook is an internationalized web application, and we can&#8217;t test it using only a specific language.</p><p>Okay, now we know how to visit a webpage, check if an element is present, fill a form and click on a button. We&#8217;re also logged in on Facebook and can finally go ahead create the <em>Splinter sprint</em> event. So, here is the event creation flow, for a user:</p><ol><li>On Facebook homepage, click on &#8220;Events&#8221; link, of left menu</li><li>The &#8220;Events&#8221; page will load, so click on &#8220;Create an Event&#8221; button</li><li>The user see a page with a form to create an event</li><li>Fill the date and chose the time</li><li>Define what is the name of the event, where it will happen and write a short description for it</li><li>Invite some guests</li><li>Upload a picture for the event</li><li>Click on &#8220;Create Event&#8221; button</li></ol><p>We are going to do all these steps, except the 6th, because the Splinter Sprint will just be a public event and we don&#8217;t need to invite anybody :) There are some boring AJAX requests on Facebook that we need to deal, so there is not only Splinter code for those steps above. First step is click on &#8220;Events&#8221; link. All we need to do is <em>find</em> the link and <em>click</em> on it:</p><div class="codecolorer-container python default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">browser.<span style="color: black;">find_by_css</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'li#navItem_events a'</span><span style="color: black;">&#41;</span>.<span style="color: black;">first</span>.<span style="color: black;">click</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></div></div><p>The <em>find_by_css</em> method takes a CSS selector and returns a ElementList. So, we get the first element of the list (even when the selector returns only an element, the return type is still a <em>list</em>) and click on it. Like <em>visit</em> method, clicking in a link is a blocking action: the driver will only listen for new actions when the request is finished (the page is loaded).</p><p>We&#8217;re finally on &#8220;new event&#8221; page, and there is a form on screen waiting for data of the <em>Splinter Sprint</em>. Let&#8217;s fill the form. Here is the code for it:</p><div class="codecolorer-container python default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">browser.<span style="color: black;">fill</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'event_startIntlDisplay'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'5/21/2011'</span><span style="color: black;">&#41;</span><br /> browser.<span style="color: #dc143c;">select</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'start_time_min'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'480'</span><span style="color: black;">&#41;</span><br /> browser.<span style="color: black;">fill</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'name'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'Splinter sprint'</span><span style="color: black;">&#41;</span><br /> browser.<span style="color: black;">fill</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'location'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'Rio de Janeiro, Brazil'</span><span style="color: black;">&#41;</span><br /> browser.<span style="color: black;">fill</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'desc'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'For more info, check out the #cobratem channel on freenode!'</span><span style="color: black;">&#41;</span></div></div><p>That is it: the event is going to happen on May 21th 2011, at 8:00 in the morning (480 minutes). As we know, the event name is <em>Splinter sprint</em>, and we are going to join some guys down here in Brazil. We filled out the form using <em>fill</em> and <em>select</em> methods.</p><p>The <em>fill</em> method is used to fill a field (a textarea, an input, or whatever you can fill). It receives two strings: the first is the name of the field to fill and the second is the value that will fill the field. The <em>select</em> method is used to select an option in a select element (a &#8220;combo box&#8221;). It also receives two string parameters: the first is the <em>name</em> of the select element, and the second is the <em>value</em> of the option being selected.</p><p>Imagine you have the following select element:</p><div class="codecolorer-container html4strict default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><div class="html4strict codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">select</span> <span style="color: #000066;">name</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;gender&quot;</span>&gt;</span><br /> &nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">option</span> <span style="color: #000066;">value</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;m&quot;</span>&gt;</span>Male<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">option</span>&gt;</span><br /> &nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">option</span> <span style="color: #000066;">value</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;f&quot;</span>&gt;</span>Female<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">option</span>&gt;</span><br /> <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">select</span>&gt;</span></div></div><p>To select &#8220;Male&#8221;, you would call the <em>select</em> method this way:</p><div class="codecolorer-container python default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">browser.<span style="color: #dc143c;">select</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;gender&quot;</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">&quot;m&quot;</span><span style="color: black;">&#41;</span></div></div><p>The last action before click on &#8220;Create Event&#8221; button is upload a picture for the event. On new event page, Facebook loads the file field for picture uploading inside a <em>iframe</em>, so we need to switch to this frame and interact with the form present inside the frame. To show the frame, we need to click on &#8220;Add Event Photo&#8221; button and then switch to it, we already know how click on a link:</p><div class="codecolorer-container python default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">browser.<span style="color: black;">find_by_css</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'div.eventEditUpload a.uiButton'</span><span style="color: black;">&#41;</span>.<span style="color: black;">first</span>.<span style="color: black;">click</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></div></div><p>When we click this link, Facebook makes a asynchronous request, which means the driver doesn&#8217;t stay blocked waiting the request ends, so if we try to interact with the frame BEFORE it appears, we will get a <em>ElementDoesNotExist</em> exception. Splinter provides a <em>is_element_present</em> method that receives an argument called <em>wait_time</em>, which is the time Splinter will be waiting for the element to appear on the screen. If the element doesn&#8217;t appear on screen, we can&#8217;t go on, so we can assume the test failed (remember we are testing a Facebook feature):</p><div class="codecolorer-container python default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> browser.<span style="color: black;">is_element_present_by_css</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'iframe#upload_pic_frame'</span><span style="color: #66cc66;">,</span> wait_time<span style="color: #66cc66;">=</span><span style="color: #ff4500;">10</span><span style="color: black;">&#41;</span>:<br /> &nbsp; &nbsp; fail<span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;The upload pic iframe did'n't appear :(&quot;</span><span style="color: black;">&#41;</span></div></div><p>The <em>is_element_present_by_css</em> method takes a CSS selector and tries to find an element using it. It also receives a <em>wait_time</em> parameter that indicates a timeout for the search of the element. So, if the <em>iframe</em> element with <em>ID=&#8221;upload_pic_frame&#8221;</em> is not present or doesn&#8217;t appears on screen in 10 seconds, the method returns <em>False</em>, otherwise it returns <em>True</em>.</p><blockquote><p><strong>Important:</strong> The <em>fail</em> method is a pseudocode sample and doesn&#8217;t exist (if you&#8217;re using <em>unittest</em> library, you can invoke <em>self.fail</em> in a TestCase, exactly what I did in <a href="https://github.com/cobrateam/splinter/blob/master/samples/test_facebook_events.py" rel="nofollow" target="_blank" title="Snippet for creating a new event on Facebook using Splinter">complete snippet for this example</a>, available at Github).</p></blockquote><p>Now we see the <em>iframe</em> element on screen and we can finally upload the picture. Imagine we have a variable that contains the path of the picture (and not a file object, <em>StringIO</em>, or something like this), and this variable name is <em>picture_path</em>, this is the code we need:</p><div class="codecolorer-container python default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">with</span> browser.<span style="color: black;">get_iframe</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'upload_pic_frame'</span><span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">as</span> frame:<br /> &nbsp; &nbsp; frame.<span style="color: black;">attach_file</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'pic'</span><span style="color: #66cc66;">,</span> picture_path<span style="color: black;">&#41;</span><br /> &nbsp; &nbsp; <span style="color: #dc143c;">time</span>.<span style="color: black;">sleep</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">10</span><span style="color: black;">&#41;</span></div></div><p>Splinter provides the <em>get_iframe</em> method that change the context and returns another objet to interact  with the content of the frame. So we call the <em>attach_file</em> method, who also receives two strings: the first is the <em>name</em> of the input element and the second is the absolute path of the file being sent. Facebook also uploads the picture asynchronously, but there&#8217;s no way to wait some element to appear on screen, so I just put Python to sleep 10 seconds on last line.</p><p>After follow all these steps, we can finally click on &#8220;Create Event&#8221; button and asserts that Facebook created it:</p><div class="codecolorer-container python default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">browser.<span style="color: black;">find_by_css</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'label.uiButton input[type=&quot;submit&quot;]'</span><span style="color: black;">&#41;</span>.<span style="color: black;">first</span>.<span style="color: black;">click</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br /> title <span style="color: #66cc66;">=</span> browser.<span style="color: black;">find_by_css</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'h1 span'</span><span style="color: black;">&#41;</span>.<span style="color: black;">first</span>.<span style="color: black;">text</span><br /> <span style="color: #ff7700;font-weight:bold;">assert</span> title <span style="color: #66cc66;">==</span> <span style="color: #483d8b;">'Splinter sprint'</span></div></div><p>After create an event, Facebook redirects the browser to the event page, so we can check if it really happened by asserting the header of the page. That&#8217;s what the code above does: in new event page, it click on submit button, and after the redirect, get the text of a <em>span</em> element and asserts that this text equals to <em>&#8220;Splinter sprint&#8221;</em>.</p><p>That is it! This post was an overview on Splinter API. Check out the <a href="https://github.com/cobrateam/splinter/blob/master/samples/test_facebook_events.py" rel="nofollow" title="Testing the creation of an event on Facebook" target="_blank">complete snippet</a>, written as a test case and also check out <a href="https://github.com/cobrateam/splinter/" rel="nofollow" target="_blank" title="splinter at github">Splinter repository at Github</a>.</p> ]]></content:encoded> <wfw:commentRss>http://f.souza.cc/2011/05/splinter-python-tool-for-acceptance-tests-on-web-applications/feed/</wfw:commentRss> <slash:comments>11</slash:comments> </item> <item><title>Killer Java applications server with nginx and memcached</title><link>http://f.souza.cc/2010/12/killer-java-applications-server-with-nginx-and-memcached/</link> <comments>http://f.souza.cc/2010/12/killer-java-applications-server-with-nginx-and-memcached/#comments</comments> <pubDate>Sun, 12 Dec 2010 04:40:44 +0000</pubDate> <dc:creator>Francisco Souza</dc:creator> <category><![CDATA[software development]]></category> <category><![CDATA[java]]></category> <category><![CDATA[memcached]]></category> <category><![CDATA[nginx]]></category> <category><![CDATA[tomcat]]></category> <category><![CDATA[vraptor]]></category><guid isPermaLink="false">http://www.franciscosouza.com/?p=143</guid> <description><![CDATA[Post showing how to configure a Java application server integrated with nginx and memcached.]]></description> <content:encoded><![CDATA[<p>Last days I worked setting up a new web serving structure for <a title="Wine" rel="nofollow" href="http://www.wine.com.br" target="_blank">Wine</a>, the largest wine&#8217;s e-commerce in Latin America. After testing, studying and learning a lot, we built a nice solution based on <a title="nginx" rel="nofollow" href="http://nginx.org" target="_blank">nginx</a> and <a title="memcached" rel="nofollow" href="http://memcached.org" target="_blank">memcached</a>. I will use a picture to describe the architecture (sorry, I&#8217;m not so good with pictures =P):</p><p><img class="aligncenter size-full wp-image-168" title="nginx, tomcat and memcached" src="http://c.souza.cc/s/2010/12/nginx-tomcat-memcached-e1292107045545.png" alt="nginx, tomcat and memcached" width="458" height="271" /></p><p style="text-align: left;">As you can see, when a client do a request to the nginx server, it first checks on memcached if the response is already cached. If the response was not found on cache server, then nginx forward the request to <a title="Apache Tomcat" href="http://tomcat.apache.org" target="_blank">Tomcat</a>, which process the request, cache the response on memcached and returns it to nginx. Tomcat works only for the first client, and all other clients requesting the same resource will get the cached response on RAM. My objective with this post is to show how we built this architecture.<span id="more-143"></span></p><p style="text-align: left;"><strong>nginx</strong></p><p style="text-align: left;">nginx was compiled following <a title="Linode nginx installation instructions" href="http://library.linode.com/web-servers/nginx/installation/ubuntu-9.10-karmic#installing_nginx_from_the_source_distribution" target="_blank">Linode instructions for nginx installation from source</a>. The only difference is that we added the <a title="nginx memcached module" href="http://wiki.nginx.org/HttpMemcachedModule" target="_blank">nginx memcached module</a>. So, first I downloaded the memc_module source from Github and then built nginx with it. Here is the commands for compiling nginx with memcached module:</p><div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$ ./configure --prefix=/opt/nginx --user=nginx --group=nginx --with-http_ssl_module --add-module={your memc_module source path}<br /> $ make<br /> $ sudo make install</div></div><p>After install nginx and <a title="Create an init script to manage nginx" href="http://library.linode.com/web-servers/nginx/installation/ubuntu-9.10-karmic#create_an_init_script_to_manage_nginx" target="_blank">create an init script for it</a>, we can work on its settings for integration with Tomcat. Just for working with separate settings, we changed the <em>nginx.conf</em> file (located in <em>/opt/nginx/conf</em> directory), and it now looks like this:</p><div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">user &nbsp;nginx;<br /> worker_processes &nbsp;1;<br /> <br /> error_log &nbsp;logs/error.log;<br /> <br /> events {<br /> &nbsp; &nbsp; worker_connections &nbsp;1024;<br /> }<br /> <br /> http {<br /> &nbsp; &nbsp; include &nbsp; &nbsp; &nbsp; mime.types;<br /> &nbsp; &nbsp; default_type &nbsp;application/octet-stream;<br /> <br /> &nbsp; &nbsp; log_format &nbsp;main &nbsp;'$remote_addr - $remote_user [$time_local] &quot;$request&quot; '<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; '$status $body_bytes_sent &quot;$http_referer&quot; '<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; '&quot;$http_user_agent&quot; &quot;$http_x_forwarded_for&quot;';<br /> <br /> &nbsp; &nbsp; access_log &nbsp;logs/access.log &nbsp;main;<br /> <br /> &nbsp; &nbsp; sendfile &nbsp; &nbsp; &nbsp; &nbsp;on;<br /> &nbsp; &nbsp; #tcp_nopush &nbsp; &nbsp; on;<br /> <br /> &nbsp; &nbsp; #keepalive_timeout &nbsp;0;<br /> &nbsp; &nbsp; keepalive_timeout &nbsp;65;<br /> <br /> &nbsp; &nbsp; #gzip &nbsp;on;<br /> <br /> &nbsp; &nbsp; include /opt/nginx/sites-enabled/*;<br /> }</div></div><p>See the last line on <em>http</em> directive: this line tells nginx to include all settings present in the <em>/opt/nginx/sites-enabled</em> directory. So, now, let&#8217;s create a default file in this directory, with this content:</p><div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">server {<br /> &nbsp; &nbsp; listen &nbsp; &nbsp; &nbsp; 80;<br /> &nbsp; &nbsp; server_name &nbsp;localhost;<br /> <br /> &nbsp; &nbsp; default_type &nbsp;text/html;<br /> <br /> &nbsp; &nbsp; location / {<br /> &nbsp; &nbsp; &nbsp; &nbsp; proxy_set_header &nbsp; &nbsp;X-Real-IP &nbsp; $remote_addr;<br /> &nbsp; &nbsp; &nbsp; &nbsp; proxy_set_header &nbsp; &nbsp;Host &nbsp; &nbsp; &nbsp; &nbsp;$http_host;<br /> &nbsp; &nbsp; &nbsp; &nbsp; proxy_set_header &nbsp; &nbsp;X-Forwarded-For $proxy_add_x_forwarded_for;<br /> <br /> &nbsp; &nbsp; &nbsp; &nbsp; if ($request_method = POST) {<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; proxy_pass &nbsp; &nbsp; &nbsp;http://localhost:8080;<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br /> &nbsp; &nbsp; &nbsp; &nbsp; }<br /> <br /> &nbsp; &nbsp; &nbsp; &nbsp; set $memcached_key &nbsp; &quot;$uri&quot;;<br /> &nbsp; &nbsp; &nbsp; &nbsp; memcached_pass &nbsp; &nbsp; &nbsp;127.0.0.1:11211;<br /> <br /> &nbsp; &nbsp; &nbsp; &nbsp; error_page &nbsp;501 404 502 = /fallback$uri;<br /> &nbsp; &nbsp; }<br /> <br /> &nbsp; &nbsp; location /fallback/ {<br /> &nbsp; &nbsp; &nbsp; &nbsp; internal; &nbsp; &nbsp;<br /> <br /> &nbsp; &nbsp; &nbsp; &nbsp; proxy_set_header &nbsp; &nbsp;X-Real-IP &nbsp; $remote_addr;<br /> &nbsp; &nbsp; &nbsp; &nbsp; proxy_set_header &nbsp; &nbsp;Host &nbsp; &nbsp; &nbsp; &nbsp;$http_host;<br /> &nbsp; &nbsp; &nbsp; &nbsp; proxy_set_header &nbsp; &nbsp;X-Forwarded-For $proxy_add_x_forwarded_for;<br /> &nbsp; &nbsp; &nbsp; &nbsp; proxy_redirect &nbsp; &nbsp; &nbsp;off;<br /> <br /> &nbsp; &nbsp; &nbsp; &nbsp; proxy_pass &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;http://localhost:8080;<br /> &nbsp; &nbsp; }<br /> <br /> }</div></div><p>Some stuffs must be explained here: the <em>default_type</em> directive is necessary for proper serving of cached responses (if you are cache other content types like <em>application/json</em> or <em>application/xml</em>, you should take a look at nginx documentation and deal conditionally with content types). The <em>location /</em> scope defines some settings for proxy, like IP and host. We just do it because we need to pass the right information to our backend (Tomcat or memcached). See more about <em>proxy_set_header</em> at <a title="nginx docs" rel="nofollow" href="http://wiki.nginx.org/HttpProxyModule#proxy_set_header" target="_blank">nginx documentation</a>. After that, there is a simple verification on the request method. We don&#8217;t want to cache POST requests.</p><p>Now we get the magic: first we set the <em>$memcached_key</em> and then we use the <em>memcached_pass</em> directive, the <em>$memcached_key</em> is the URI. <em>memcached_pass</em> directive is very similar to <em>proxy_pass</em>, nginx &#8220;proxies&#8221; memcached to get the response. So we can get some HTTP status code, like 200, 404 or 502. We define two error handlers for two status codes:</p><ul><li>404: memcached module returns a 404 error when the key is not on memcached server</li><li>502: memcached module returns a 502 error when it can&#8217;t found memcached server (it is a bad gateway error, the same you get if you start nginx withou start Tomcat ;D)</li></ul><p>So, when nginx gets any of those errors, it should forward the request to Tomcat, creating another proxy. We configured it out on <em>fallback</em>, an <a title="nginx docs for internal locations" rel="nofollow" href="http://wiki.nginx.org/HttpCoreModule#internal" target="_blank">internal location</a> that builds a proxy between nginx and Tomcat (listening on port 8080). Everything is set up with nginx. As you can see in the picture or in the nginx configuration file, nginx doesn&#8217;t put anything on cache, it only gets cached items. The application should put everything on cache. Let&#8217;s do it :)</p><p style="text-align: left;"><strong>Java application</strong></p><p>Now is the time to write some code :) I chose an application written by a friend. It&#8217;s a very simple CRUD of users, written by <a title="Washington Botelho" rel="nofollow" href="http://wbotelhos.com" target="_blank">Washington Botelho</a> with the goal of introducing <a title="VRaptor" rel="nofollow" href="http://vraptor.org" target="_blank">VRaptor</a>, a powerful and fast development focused web framework. Washington also wrote a blog post explaining the application, if you don&#8217;t know VRaptor or want to know how the application was built, check the blog post <a title="Getting started with VRaptor 3" rel="nofollow" href="http://www.wbotelhos.com/2010/11/24/getting-started-with-vraptor-3/" target="_blank">&#8220;Getting started with VRaptor 3&#8243;</a>. I <a title="check my fork out" rel="nofollow" href="https://github.com/fsouza/starting-with-vraptor-3" target="_blank">forked</a> the application, made some minor changes and added a magic filter for caching. All Java code that I want to show here is the filter code:</p><div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">package</span> <span style="color: #006699;">com.franciscosouza.memcached.filter</span><span style="color: #339933;">;</span><br /> <br /> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">java.io.IOException</span><span style="color: #339933;">;</span><br /> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">java.io.PrintWriter</span><span style="color: #339933;">;</span><br /> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">java.io.StringWriter</span><span style="color: #339933;">;</span><br /> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">java.net.InetSocketAddress</span><span style="color: #339933;">;</span><br /> <br /> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">javax.servlet.Filter</span><span style="color: #339933;">;</span><br /> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">javax.servlet.FilterChain</span><span style="color: #339933;">;</span><br /> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">javax.servlet.FilterConfig</span><span style="color: #339933;">;</span><br /> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">javax.servlet.ServletException</span><span style="color: #339933;">;</span><br /> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">javax.servlet.ServletOutputStream</span><span style="color: #339933;">;</span><br /> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">javax.servlet.ServletRequest</span><span style="color: #339933;">;</span><br /> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">javax.servlet.ServletResponse</span><span style="color: #339933;">;</span><br /> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">javax.servlet.http.HttpServletRequest</span><span style="color: #339933;">;</span><br /> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">javax.servlet.http.HttpServletResponse</span><span style="color: #339933;">;</span><br /> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">javax.servlet.http.HttpServletResponseWrapper</span><span style="color: #339933;">;</span><br /> <br /> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">net.spy.memcached.MemcachedClient</span><span style="color: #339933;">;</span><br /> <br /> <span style="color: #008000; font-style: italic; font-weight: bold;">/**<br /> &nbsp;* Servlet Filter implementation class MemcachedFilter<br /> &nbsp;*/</span><br /> <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> MemcachedFilter <span style="color: #000000; font-weight: bold;">implements</span> Filter <span style="color: #009900;">&#123;</span><br /> <br /> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> MemcachedClient mmc<span style="color: #339933;">;</span><br /> <br /> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">static</span> <span style="color: #000000; font-weight: bold;">class</span> MemcachedHttpServletResponseWrapper <span style="color: #000000; font-weight: bold;">extends</span> HttpServletResponseWrapper <span style="color: #009900;">&#123;</span><br /> <br /> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #003399;">StringWriter</span> sw <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">StringWriter</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br /> <br /> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> MemcachedHttpServletResponseWrapper<span style="color: #009900;">&#40;</span>HttpServletResponse response<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">super</span><span style="color: #009900;">&#40;</span>response<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br /> <br /> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #003399;">PrintWriter</span> getWriter<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">throws</span> <span style="color: #003399;">IOException</span> <span style="color: #009900;">&#123;</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">return</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">PrintWriter</span><span style="color: #009900;">&#40;</span>sw<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br /> <br /> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> ServletOutputStream getOutputStream<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">throws</span> <span style="color: #003399;">IOException</span> <span style="color: #009900;">&#123;</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">throw</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">UnsupportedOperationException</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br /> <br /> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #003399;">String</span> toString<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">return</span> sw.<span style="color: #006633;">toString</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br /> &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br /> <br /> &nbsp; &nbsp; <span style="color: #008000; font-style: italic; font-weight: bold;">/**<br /> &nbsp; &nbsp; &nbsp;* Default constructor.<br /> &nbsp; &nbsp; &nbsp;*/</span><br /> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> MemcachedFilter<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br /> &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br /> <br /> &nbsp; &nbsp; <span style="color: #008000; font-style: italic; font-weight: bold;">/**<br /> &nbsp; &nbsp; &nbsp;* @see Filter#destroy()<br /> &nbsp; &nbsp; &nbsp;*/</span><br /> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> destroy<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br /> &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br /> <br /> &nbsp; &nbsp; <span style="color: #008000; font-style: italic; font-weight: bold;">/**<br /> &nbsp; &nbsp; &nbsp;* @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)<br /> &nbsp; &nbsp; &nbsp;*/</span><br /> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> doFilter<span style="color: #009900;">&#40;</span>ServletRequest request, ServletResponse response, FilterChain chain<span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">throws</span> <span style="color: #003399;">IOException</span>, ServletException <span style="color: #009900;">&#123;</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; MemcachedHttpServletResponseWrapper wrapper <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> MemcachedHttpServletResponseWrapper<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#40;</span>HttpServletResponse<span style="color: #009900;">&#41;</span> response<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; chain.<span style="color: #006633;">doFilter</span><span style="color: #009900;">&#40;</span>request, wrapper<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br /> <br /> &nbsp; &nbsp; &nbsp; &nbsp; HttpServletRequest inRequest <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span>HttpServletRequest<span style="color: #009900;">&#41;</span> request<span style="color: #339933;">;</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; HttpServletResponse inResponse <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span>HttpServletResponse<span style="color: #009900;">&#41;</span> response<span style="color: #339933;">;</span><br /> <br /> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #003399;">String</span> content <span style="color: #339933;">=</span> wrapper.<span style="color: #006633;">toString</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br /> <br /> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #003399;">PrintWriter</span> out <span style="color: #339933;">=</span> inResponse.<span style="color: #006633;">getWriter</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; out.<span style="color: #006633;">print</span><span style="color: #009900;">&#40;</span>content<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br /> <br /> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>inRequest.<span style="color: #006633;">getMethod</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">equals</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;POST&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #003399;">String</span> key <span style="color: #339933;">=</span> inRequest.<span style="color: #006633;">getRequestURI</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; mmc.<span style="color: #006633;">set</span><span style="color: #009900;">&#40;</span>key, <span style="color: #cc66cc;">5</span>, content<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br /> &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br /> <br /> &nbsp; &nbsp; <span style="color: #008000; font-style: italic; font-weight: bold;">/**<br /> &nbsp; &nbsp; &nbsp;* @see Filter#init(FilterConfig)<br /> &nbsp; &nbsp; &nbsp;*/</span><br /> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> init<span style="color: #009900;">&#40;</span>FilterConfig fConfig<span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">throws</span> ServletException <span style="color: #009900;">&#123;</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">try</span> <span style="color: #009900;">&#123;</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; mmc <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> MemcachedClient<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> InetSocketAddress<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;localhost&quot;</span>, <span style="color: #cc66cc;">11211</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span> <span style="color: #000000; font-weight: bold;">catch</span> <span style="color: #009900;">&#40;</span><span style="color: #003399;">IOException</span> e<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; e.<span style="color: #006633;">printStackTrace</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">throw</span> <span style="color: #000000; font-weight: bold;">new</span> ServletException<span style="color: #009900;">&#40;</span>e<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br /> &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br /> <br /> <span style="color: #009900;">&#125;</span></div></div><p>First, the dependency: for memcached communication, we used <a title="spymemcached" rel="nofollow" href="http://code.google.com/p/spymemcached/" target="_blank">spymemcached</a> client. It is a simple and easy to use memcached library. I won&#8217;t explain all the code, line by line, but I can tell the idea behind the code: first, call <em>doFilter</em> method on <em>FilterChain</em>, because we want to get the response and work with that. Look the <em>MemcachedHttpServletResponseWrapper</em> object, it encapsulates the response and makes easier to play with response content.</p><p>We get the content, write it on response writer and put it in cache using the MemcachedClient provided by spymemcached. The request URI is the key and timeout is 5 seconds.</p><p style="text-align: left;"><strong>web.xml</strong></p><p>Last step is to add the filter on <em>web.xml</em> file of the project, map it before the VRaptor filter is very important for proper working:</p><div class="codecolorer-container xml default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><div class="xml codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;?xml</span> <span style="color: #000066;">version</span>=<span style="color: #ff0000;">&quot;1.0&quot;</span> <span style="color: #000066;">encoding</span>=<span style="color: #ff0000;">&quot;UTF-8&quot;</span><span style="color: #000000; font-weight: bold;">?&gt;</span></span><br /> <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;web-app</span> <span style="color: #000066;">xmlns:xsi</span>=<span style="color: #ff0000;">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span> <span style="color: #000066;">xmlns</span>=<span style="color: #ff0000;">&quot;http://java.sun.com/xml/ns/javaee&quot;</span> <span style="color: #000066;">xmlns:web</span>=<span style="color: #ff0000;">&quot;http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd&quot;</span> <span style="color: #000066;">xsi:schemaLocation</span>=<span style="color: #ff0000;">&quot;http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd&quot;</span> <span style="color: #000066;">id</span>=<span style="color: #ff0000;">&quot;WebApp_ID&quot;</span> <span style="color: #000066;">version</span>=<span style="color: #ff0000;">&quot;2.5&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br /> &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;display-name<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>memcached sample<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/display-name<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br /> <br /> &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;filter<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br /> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;filter-name<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>vraptor<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/filter-name<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br /> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;filter-class<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>br.com.caelum.vraptor.VRaptor<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/filter-class<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br /> &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/filter<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br /> &nbsp; &nbsp; <br /> &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;filter<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br /> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;filter-name<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>memcached<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/filter-name<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br /> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;filter-class<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>com.franciscosouza.memcached.filter.MemcachedFilter<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/filter-class<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br /> &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/filter<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br /> &nbsp; &nbsp; <br /> &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;filter-mapping<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br /> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;filter-name<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>memcached<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/filter-name<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br /> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;url-pattern<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>/*<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/url-pattern<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br /> &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/filter-mapping<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br /> <br /> &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;filter-mapping<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br /> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;filter-name<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>vraptor<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/filter-name<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br /> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;url-pattern<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>/*<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/url-pattern<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br /> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;dispatcher<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>FORWARD<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/dispatcher<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br /> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;dispatcher<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>REQUEST<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/dispatcher<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br /> &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/filter-mapping<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br /> <br /> <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/web-app<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></div></div><p>That is it! Now you can just run Tomcat on port 8080 and nginx on port 80, and access http://localhost on your browser. Try some it: raise up the cache timeout, navigate on application and turn off Tomcat. You will still be able to navigate on some pages that use GET request method (users list, home and users form).</p><p>Check the entire code out on Github: <a title="Get the code on Github" rel="nofollow" href="https://github.com/fsouza/starting-with-vraptor-3" target="_blank">https://github.com/fsouza/starting-with-vraptor-3</a>. If you have any questions, troubles or comments, please let me know! ;)</p> ]]></content:encoded> <wfw:commentRss>http://f.souza.cc/2010/12/killer-java-applications-server-with-nginx-and-memcached/feed/</wfw:commentRss> <slash:comments>17</slash:comments> </item> <item><title>Using an exclusive Firefox profile for Selenium WebDriver</title><link>http://f.souza.cc/2010/10/using-an-exclusive-firefox-profile-for-selenium-webdriver/</link> <comments>http://f.souza.cc/2010/10/using-an-exclusive-firefox-profile-for-selenium-webdriver/#comments</comments> <pubDate>Wed, 27 Oct 2010 22:19:00 +0000</pubDate> <dc:creator>Francisco Souza</dc:creator> <category><![CDATA[software development]]></category> <category><![CDATA[acceptance tests]]></category> <category><![CDATA[python]]></category> <category><![CDATA[selenium]]></category> <category><![CDATA[tdd]]></category><guid isPermaLink="false">http://www.franciscosouza.com/?p=17</guid> <description><![CDATA[Use a exclusive Firefox profile for Selenium WebDriver.]]></description> <content:encoded><![CDATA[<p>One of stuffs that I really hate when working with Selenium and Ubuntu is that sometimes Selenium just starts Firefox in offline mode (or something like that). I used to create an exclusive Firefox profile for Selenium when working with Selenium RC, and just started Selenium with the <em>-firefoxProfileTemplate</em> parameter, but now I am almost free of Selenium 1.x, and enjoying Selenium 2 with Firefox WebDriver. The question is: how can I specify the Firefox profile to be used in a WebDriver execution? That is really easy&#8230;<span id="more-17"></span></p><p>You can just pass a parameter <em>profile</em> when getting the driver, so you will use the created profile. Here is a Python code example:</p><div class="codecolorer-container python default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:650px;"><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">from</span> selenium <span style="color: #ff7700;font-weight:bold;">import</span> get_driver<span style="color: #66cc66;">,</span> FIREFOX<br /> <br /> browser <span style="color: #66cc66;">=</span> get_driver<span style="color: black;">&#40;</span>FIREFOX<span style="color: #66cc66;">,</span> <span style="color: #dc143c;">profile</span><span style="color: #66cc66;">=</span><span style="color: #483d8b;">'selenium'</span><span style="color: black;">&#41;</span><br /> <br /> <span style="color: #ff7700;font-weight:bold;">try</span>:<br /> &nbsp; &nbsp; browser.<span style="color: black;">get</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'http://www.google.com'</span><span style="color: black;">&#41;</span><br /> &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">assert</span> browser.<span style="color: black;">get_title</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> <span style="color: #66cc66;">==</span> <span style="color: #483d8b;">'Google'</span><br /> <span style="color: #ff7700;font-weight:bold;">finally</span>:<br /> &nbsp; &nbsp; browser.<span style="color: black;">close</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></div></div><p>Look that I also wrote a stupid title assertion :) Selenium will search for the provided profile on Firefox profile.ini file. If you don&#8217;t know how to create a good Firefox profile for Selenium, check this link out: <a title="Creating Firefox profile for your Selenium RC tests" rel="nofollow" href="http://girliemangalo.wordpress.com/2009/02/05/creating-firefox-profile-for-your-selenium-rc-tests/" target="_blank">http://girliemangalo.wordpress.com/2009/02/05/creating-firefox-profile-for-your-selenium-rc-tests/</a>.</p><p>That is a very simple tip, and I hope it could help someone. I also hope that I can back to write here :)</p> ]]></content:encoded> <wfw:commentRss>http://f.souza.cc/2010/10/using-an-exclusive-firefox-profile-for-selenium-webdriver/feed/</wfw:commentRss> <slash:comments>5</slash:comments> </item> </channel> </rss>
