<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">

  <title><![CDATA[Belchak.com]]></title>
  <link href="http://belchak.com/atom.xml" rel="self"/>
  <link href="http://belchak.com/"/>
  <updated>2012-08-02T10:59:27-06:00</updated>
  <id>http://belchak.com/</id>
  <author>
    <name><![CDATA[Ben Belchak]]></name>
    
  </author>
  <generator uri="http://octopress.org/">Octopress</generator>

  
  <entry>
    <title type="html"><![CDATA[Making Sensu work with Graphite]]></title>
    <link href="http://belchak.com/2012/08/02/making-sensu-work-with-graphite/"/>
    <updated>2012-08-02T10:48:00-06:00</updated>
    <id>http://belchak.com/2012/08/02/making-sensu-work-with-graphite</id>
    <content type="html"><![CDATA[<p>Like many companies, I&#8217;m sure, we&#8217;re investigating using <a href="http://www.sonian.com/cloud-monitoring-sensu/">Sensu</a> for monitoring
and <a href="http://graphite.wikidot.com/">Graphite</a> for metrics collecting. The docs for making these two commuicate together over AMQP
are pretty good except for one thing.</p>

<p>Using the docs that I&#8217;ve read, when you start up Sensu first with its default options for AMQP, and then start up Graphite
to read from that queue, Graphite will crash every time it tries to create the exchange. The reason for this, after lots of
hair-pulling and debugging, is because Graphite is hard-coded to set up a durable exchange for its metrics, while Sensu&#8217;s default
is to set up a non-durable exchange. <a href="http://rabbitmq.com/">RabbitMQ</a> will not allow you to create an exchange with the same name
and different options, so whichever piece of software created the exchange will work, but the other will blow up all over your
face.</p>

<p>The solution to this is pretty simple, but I haven&#8217;t seen it documented anywhere. Simply add <code>"durable": true</code> to your exchange
configuration in your Sensu config.json like so:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
</pre></td><td class='code'><pre><code class='json'><span class='line'><span class="s2">&quot;handlers&quot;</span><span class="err">:</span> <span class="p">{</span>
</span><span class='line'>    <span class="nt">&quot;graphite&quot;</span><span class="p">:</span> <span class="p">{</span>
</span><span class='line'>      <span class="nt">&quot;exchange&quot;</span><span class="p">:</span> <span class="p">{</span>
</span><span class='line'>        <span class="nt">&quot;name&quot;</span><span class="p">:</span> <span class="s2">&quot;graphite&quot;</span><span class="p">,</span>
</span><span class='line'>        <span class="nt">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;topic&quot;</span><span class="p">,</span>
</span><span class='line'>        <span class="nt">&quot;key&quot;</span><span class="p">:</span> <span class="s2">&quot;metrics&quot;</span><span class="p">,</span>
</span><span class='line'>        <span class="nt">&quot;durable&quot;</span><span class="p">:</span> <span class="kc">true</span>
</span><span class='line'>      <span class="p">},</span>
</span><span class='line'>      <span class="nt">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;amqp&quot;</span><span class="p">,</span>
</span><span class='line'>      <span class="nt">&quot;send_only_check_output&quot;</span><span class="p">:</span> <span class="kc">true</span>
</span><span class='line'>    <span class="p">},</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>Hope that helps!</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Migrating from WordPress to Octopress]]></title>
    <link href="http://belchak.com/2012/07/31/migrating-from-wordpress-to-octopress/"/>
    <updated>2012-07-31T17:22:00-06:00</updated>
    <id>http://belchak.com/2012/07/31/migrating-from-wordpress-to-octopress</id>
    <content type="html"><![CDATA[<h2>WordPress is awesome, why&#8217;d you switch?</h2>

<p>So, I&#8217;ve been really hating WordPress as a blog engine lately. Tons of spam,
lots of emails from spam accounts signing up and trying to post comments, etc.
We had some discussion at the office recently about what blog engine to use for
our corporate blog, (we ended up using WordPress) but through the process I decided
to evaluate <a href="http://octopress.org">Octopress</a> as an approach to static content
serving for my personal blog.</p>

<p>On top of the security issues that I&#8217;ve been dealing with (constantly updating the
software, plugins and deleting spam), I host at <a href="http://dreamhost.com/">Dreamhost</a>.
They are not known as the fastest hosting company around, and I was finding that my
pages were loading so slowly that it was beginning to get frustrating.</p>

<p>Plus, I could never find a good WordPress theme that I wanted to look at and I never
have time to spend customizing a complex WordPress theme.</p>

<h2>Enter Octopress</h2>

<p>I evaluated Octopress for about 10 minutes and knew I was hooked. I loved the
simplicity and the beauty of its default theme (and since it&#8217;s themeable using
<a href="http://sass-lang.com/">SASS</a> I can easily customize it) and the ease of deployment
to any number of hosting platforms (rsync, <a href="http://pages.github.com">github pages</a>,
<a href="http://heroku.com">heroku</a>, etc) leaves no excuse not to use it! Also, since all
the content is generated dynamically on your machine and then uploaded as static content,
it is very fast to serve on the server, and is less prone to spam and security holes.</p>

<h2>How I did it</h2>

<p>I simply exported all of my posts and pages using the Export functionality in the WordPress
administration tool and then ran it through <a href="https://github.com/thomasf/exitwp/">exitwp</a>.
The result was phenomenal! I ended up with an export of all my pages and posts. Since
I was already using <a href="http://disqus.com">Disqus</a> all the comments came over automatically.</p>

<p>I did have to do some very basic formatting for some of my code snippets in order to get
the syntax highlighting to work properly, but that was a simple matter of just setting the
language in the generated markdown files.</p>

<h2>Deploying</h2>

<p>I use the Rsync deploy method to my Dreamhost shared server, but I am also considering
migrating to <a href="http://pages.github.com/">github pages</a> at some point. Deploying is as simple as:</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>$ rake generate
</span><span class='line'>$ rake deploy</span></code></pre></td></tr></table></div></figure>


<p>And that&#8217;s it! You can even streamline it more by only running one command:</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>$ rake gen_deploy</span></code></pre></td></tr></table></div></figure>


<p>Overall, the migration was even more simple than I had expected, and I&#8217;m very happy with the
results! Now the hard part is coming up with interesting content to put here!</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[JIRA and Campfire Integration]]></title>
    <link href="http://belchak.com/2012/01/21/jira-and-campfire-integration/"/>
    <updated>2012-01-21T05:25:22-07:00</updated>
    <id>http://belchak.com/2012/01/21/jira-and-campfire-integration</id>
    <content type="html"><![CDATA[<p>I have been working on migrating my company&#8217;s Pivotal Tracker to JIRA. We love most of the features of JIRA, but we were really missing the nice updates to our Campfire room to tell us what is going on with our issues.</p>

<p>Sure, we could use an RSS feed plugin for <a href="http://www.belchak.com/2011/06/24/campy-the-python-campfire-bot/">Campy</a>, but that is not real-time enough.</p>

<p>I didn&#8217;t want to write a huge plugin just to send messages to Campfire (it seems like such a simple thing to do!). I was poking around for solutions, and came across <a href="https://studio.plugins.atlassian.com/wiki/display/GRV/Script+Runner">this plugin</a>. It&#8217;s a plugin that runs scripts written in the <a href="http://groovy.codehaus.org/">Groovy</a> dynamic language for Java. One nice thing about this plugin is that it lets you execute Python (Jython) or Ruby (Jruby). The only problem is that you can&#8217;t write a listener using Python, so I ended up having to learn Groovy.</p>

<p>Here&#8217;s what I came up with. It requires you to install the <a href="http://groovy.codehaus.org/modules/http-builder/doc/index.html">HTTPBuilder</a> libraries for Groovy, and this script will require some customization to fit your environment. Right now it only supports sending messages when new issues are created and when a new comment is added to an existing issue, but other issue events would be easy enough to add - this is meant as an example.</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
<span class='line-number'>43</span>
<span class='line-number'>44</span>
<span class='line-number'>45</span>
<span class='line-number'>46</span>
<span class='line-number'>47</span>
<span class='line-number'>48</span>
</pre></td><td class='code'><pre><code class='groovy'><span class='line'><span class="kn">import</span> <span class="nn">com.atlassian.jira.event.issue.AbstractIssueEventListener</span>
</span><span class='line'><span class="kn">import</span> <span class="nn">com.atlassian.jira.event.issue.IssueEvent</span>
</span><span class='line'><span class="kn">import</span> <span class="nn">com.atlassian.jira.ComponentManager</span>
</span><span class='line'><span class="kn">import</span> <span class="nn">org.apache.log4j.Category</span>
</span><span class='line'><span class="kn">import</span> <span class="nn">groovyx.net.http.RESTClient</span>
</span><span class='line'><span class="kn">import</span> <span class="nn">static</span> <span class="n">groovyx</span><span class="o">.</span><span class="na">net</span><span class="o">.</span><span class="na">http</span><span class="o">.</span><span class="na">ContentType</span><span class="o">.</span><span class="na">JSON</span>
</span><span class='line'><span class="kn">import</span> <span class="nn">static</span> <span class="n">com</span><span class="o">.</span><span class="na">atlassian</span><span class="o">.</span><span class="na">jira</span><span class="o">.</span><span class="na">event</span><span class="o">.</span><span class="na">type</span><span class="o">.</span><span class="na">EventType</span><span class="o">.*</span>
</span><span class='line'>
</span><span class='line'><span class="kd">class</span> <span class="nc">CampfireListener</span> <span class="kd">extends</span> <span class="n">AbstractIssueEventListener</span> <span class="o">{</span>
</span><span class='line'>
</span><span class='line'>    <span class="nd">@Override</span>
</span><span class='line'>    <span class="kt">void</span> <span class="nf">workflowEvent</span><span class="o">(</span><span class="n">IssueEvent</span> <span class="n">event</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>        <span class="kt">def</span> <span class="n">Category</span> <span class="n">log</span> <span class="o">=</span> <span class="n">Category</span><span class="o">.</span><span class="na">getInstance</span><span class="o">(</span><span class="s2">&quot;com.onresolve.jira.groovy.PostFunction&quot;</span><span class="o">)</span>
</span><span class='line'>        <span class="kt">def</span> <span class="n">campfire</span> <span class="o">=</span> <span class="k">new</span> <span class="n">RESTClient</span><span class="o">(</span><span class="s1">&#39;https://CAMPFIREID.campfirenow.com/room/ROOMID/&#39;</span><span class="o">)</span>
</span><span class='line'>        <span class="kt">def</span> <span class="n">issueBaseUrl</span> <span class="o">=</span> <span class="s2">&quot;http://yourjirahost:8080/path-to-jira/browse/&quot;</span>
</span><span class='line'>        <span class="n">campfire</span><span class="o">.</span><span class="na">auth</span><span class="o">.</span><span class="na">basic</span> <span class="s1">&#39;CAMPFIRE AUTH TOKEN&#39;</span><span class="o">,</span> <span class="s1">&#39;X&#39;</span>
</span><span class='line'>        <span class="k">switch</span> <span class="o">(</span><span class="n">event</span><span class="o">.</span><span class="na">getEventTypeId</span><span class="o">())</span> <span class="o">{</span>
</span><span class='line'>            <span class="k">case</span> <span class="nl">ISSUE_COMMENTED_ID:</span>
</span><span class='line'>                <span class="kt">def</span> <span class="n">resp</span> <span class="o">=</span> <span class="n">campfire</span><span class="o">.</span><span class="na">post</span><span class="o">(</span> <span class="nl">path:</span> <span class="s1">&#39;speak.json&#39;</span><span class="o">,</span>
</span><span class='line'>                                      <span class="nl">body:</span> <span class="o">[</span> <span class="nl">message:</span> <span class="o">[</span> <span class="nl">type:</span> <span class="s2">&quot;TextMessage&quot;</span><span class="o">,</span> <span class="nl">body:</span>
</span><span class='line'>                                          <span class="n">String</span><span class="o">.</span><span class="na">format</span><span class="o">(</span><span class="s2">&quot;%s added a comment to %s (%s%s):&quot;</span><span class="o">,</span>
</span><span class='line'>                                              <span class="n">event</span><span class="o">.</span><span class="na">getUser</span><span class="o">().</span><span class="na">getDisplayName</span><span class="o">(),</span>
</span><span class='line'>                                              <span class="n">event</span><span class="o">.</span><span class="na">issue</span><span class="o">.</span><span class="na">getKey</span><span class="o">(),</span>
</span><span class='line'>                                              <span class="n">issueBaseUrl</span><span class="o">,</span>
</span><span class='line'>                                              <span class="n">event</span><span class="o">.</span><span class="na">issue</span><span class="o">.</span><span class="na">getKey</span><span class="o">())]</span> <span class="o">],</span>
</span><span class='line'>                                      <span class="nl">requestContentType:</span> <span class="n">JSON</span><span class="o">)</span>
</span><span class='line'>                <span class="n">resp</span> <span class="o">=</span> <span class="n">campfire</span><span class="o">.</span><span class="na">post</span><span class="o">(</span> <span class="nl">path:</span> <span class="s1">&#39;speak.json&#39;</span><span class="o">,</span>
</span><span class='line'>                                      <span class="nl">body:</span> <span class="o">[</span> <span class="nl">message:</span> <span class="o">[</span> <span class="nl">type:</span> <span class="s2">&quot;PasteMessage&quot;</span><span class="o">,</span> <span class="nl">body:</span>
</span><span class='line'>                                          <span class="n">String</span><span class="o">.</span><span class="na">format</span><span class="o">(</span><span class="s2">&quot;%s&quot;</span><span class="o">,</span> <span class="n">event</span><span class="o">.</span><span class="na">getComment</span><span class="o">().</span><span class="na">getBody</span><span class="o">())</span> <span class="o">]</span> <span class="o">],</span>
</span><span class='line'>                                      <span class="nl">requestContentType:</span> <span class="n">JSON</span><span class="o">)</span>
</span><span class='line'>                <span class="k">break</span>
</span><span class='line'>            <span class="k">case</span> <span class="nl">ISSUE_CREATED_ID:</span>
</span><span class='line'>                <span class="kt">def</span> <span class="n">resp</span> <span class="o">=</span> <span class="n">campfire</span><span class="o">.</span><span class="na">post</span><span class="o">(</span> <span class="nl">path:</span> <span class="s1">&#39;speak.json&#39;</span><span class="o">,</span>
</span><span class='line'>                        <span class="nl">body:</span> <span class="o">[</span> <span class="nl">message:</span> <span class="o">[</span> <span class="nl">type:</span> <span class="s2">&quot;TextMessage&quot;</span><span class="o">,</span> <span class="nl">body:</span>
</span><span class='line'>                            <span class="n">String</span><span class="o">.</span><span class="na">format</span><span class="o">(</span><span class="s1">&#39;%s created a new issue: &quot;%s&quot; (%s%s):&#39;</span><span class="o">,</span>
</span><span class='line'>                                <span class="n">event</span><span class="o">.</span><span class="na">getUser</span><span class="o">().</span><span class="na">getDisplayName</span><span class="o">(),</span>
</span><span class='line'>                                <span class="n">event</span><span class="o">.</span><span class="na">issue</span><span class="o">.</span><span class="na">getSummary</span><span class="o">(),</span>
</span><span class='line'>                                <span class="n">issueBaseUrl</span><span class="o">,</span>
</span><span class='line'>                                <span class="n">event</span><span class="o">.</span><span class="na">issue</span><span class="o">.</span><span class="na">getKey</span><span class="o">())</span> <span class="o">]</span> <span class="o">],</span>
</span><span class='line'>                        <span class="nl">requestContentType:</span> <span class="n">JSON</span><span class="o">)</span>
</span><span class='line'>                <span class="n">resp</span> <span class="o">=</span> <span class="n">campfire</span><span class="o">.</span><span class="na">post</span><span class="o">(</span> <span class="nl">path:</span> <span class="s1">&#39;speak.json&#39;</span><span class="o">,</span>
</span><span class='line'>                      <span class="nl">body:</span> <span class="o">[</span> <span class="nl">message:</span> <span class="o">[</span> <span class="nl">type:</span> <span class="s2">&quot;PasteMessage&quot;</span><span class="o">,</span> <span class="nl">body:</span>
</span><span class='line'>                          <span class="n">String</span><span class="o">.</span><span class="na">format</span><span class="o">(</span><span class="s2">&quot;%s&quot;</span><span class="o">,</span> <span class="n">event</span><span class="o">.</span><span class="na">getIssue</span><span class="o">().</span><span class="na">getDescription</span><span class="o">())</span> <span class="o">]</span> <span class="o">],</span>
</span><span class='line'>                      <span class="nl">requestContentType:</span> <span class="n">JSON</span><span class="o">)</span>
</span><span class='line'>                <span class="k">break</span>
</span><span class='line'>        <span class="o">}</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'><span class="o">}</span>
</span></code></pre></td></tr></table></div></figure>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Problems with IPv4/6 hosts in OSX Lion]]></title>
    <link href="http://belchak.com/2011/07/27/problems-with-ipv46-hosts-in-osx-lion/"/>
    <updated>2011-07-27T11:18:43-06:00</updated>
    <id>http://belchak.com/2011/07/27/problems-with-ipv46-hosts-in-osx-lion</id>
    <content type="html"><![CDATA[<p>If you&#8217;re like me, you end up doing a lot of testing in virtual machines. I run several VMs that do various different tasks for me so that I don&#8217;t have to sully my Mac with packages I rarely need, etc. So what I do is create a VM and give it a local hostname defined in my /etc/hosts file.</p>

<p>Recently, after my upgrade to OSX Lion, I started running into an issue where it would take over 5 seconds to connect to any of my VMs using any protocol (SSH, HTTP, etc). After several hours of troubleshooting, and several Wireshark sessions later, the truth of the matter was plain:</p>

<p><a href="http://www.belchak.com/wp-content/uploads/2011/07/kdxf5y8qtaxh.png"><img src="http://www.belchak.com/wp-content/uploads/2011/07/kdxf5y8qtaxh-300x15.png" alt="" /></a></p>

<p>OSX is now doing IPv6 by default with no way that I have found to disable it yet, and so that means that if you have hosts that you want to reference with locally defined hostnames, you are going to have to create an IPv6 entry for them as well.</p>

<p>Here is a great site that I found that helps with the conversion: <a href="http://www.subnetonline.com/pages/converters/ipv4-to-ipv6.php">SubnetOnline.com</a></p>

<p>I am sure that there are better ways to do this, but I just wanted to share this quick little hack that I found with you. If you have a better way, please let me know!</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Re-enabling Key Repeat in OSX Lion]]></title>
    <link href="http://belchak.com/2011/07/23/re-enabling-key-repeat-in-osx-lion/"/>
    <updated>2011-07-23T16:51:15-06:00</updated>
    <id>http://belchak.com/2011/07/23/re-enabling-key-repeat-in-osx-lion</id>
    <content type="html"><![CDATA[<p>I have recently upgraded to OSX Lion, and I have to say that I love everything about it. Except for one thing. In many apps, the key repeat has been disabled in favor of the new press-and-hold popup for getting alternative characters.</p>

<p>This is fine for most apps, but for apps like <a href="http://www.jetbrains.com/pycharm/">PyCharm</a> where I use vi key maps, it becomes very, very frustrating.</p>

<p>I came across this little tip to re-enable the key repeat, and my life is measurably better (first world problems, I know&#8230;).</p>

<p>Run the following in your Terminal.app:</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>$ defaults write -g ApplePressAndHoldEnabled -bool false</span></code></pre></td></tr></table></div></figure>


<p>Then reboot, and you should be good to go!</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Campy: the Python Campfire Bot]]></title>
    <link href="http://belchak.com/2011/06/24/campy-the-python-campfire-bot/"/>
    <updated>2011-06-24T05:06:13-06:00</updated>
    <id>http://belchak.com/2011/06/24/campy-the-python-campfire-bot</id>
    <content type="html"><![CDATA[<p>We use a <a href="http://www.campfirenow.com">Campfire</a> at <a href="http://www.needle.com">Needle</a> for our day-to-day communication between our tech team members and other business members. We really like Campfire&#8217;s ability to store files, conference call and keep transcripts even when you are not logged in. We get <a href="http://github.com">GitHub</a> commit messages, <a href="http://pivotaltracker.com">Pivotal Tracker</a> story updates and more scattered in our conversations.</p>

<p>These one-way updates are very nice, but I thought it would be nice to be able to have a bot that sat in the channel and could take commands from anybody and do more complex tasks for us without us ever having to leave Campfire. To solve this problem, I wrote <a href="http://www.github.com/bbelchak/campy">Campy</a>, a pure Python Campfire bot with an extensible plugin system.</p>

<p>The first plugin I wrote as a proof of concept is a Google image search plugin. You tell the bot some search parameters that you would like it to search for, and you get back an image inline in your chat transcript. Don&#8217;t worry, safe search is on by default so you don&#8217;t get any NSFW images back.</p>

<p>The second plugin I wrote was the all-important Pivotal Tracker plugin. This plugin lets you do the following:</p>

<ul>
<li><p>pt story create &#8220;Title&#8221; &#8220;Description&#8221; bug|feature|chore|release &#8211; Create a story</p></li>
<li><p>pt getmine started|finished|delivered|accepted|rejected|unstarted|unscheduled &#8211; Get a list of all stories that belong to you</p></li>
<li><p>pt start #story_id &#8211; Start a particular story.</p></li>
<li><p>pt start|tell next bug|feature|chore [mine] &#8211; Start or tell the next story of a given type. Optionally supply &#8216;mine&#8217; at the end of the message to only work on your own stories.</p></li>
</ul>


<p>The plugins system is very extensible, so you can create a plugin to do pretty much anything!</p>

<p>You can get Campy here:  <a href="https://github.com/bbelchak/campy">https://github.com/bbelchak/campy</a></p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Ergotron WorkFit-S Standing Desk Review ]]></title>
    <link href="http://belchak.com/2011/03/04/workfit-standing-desk/"/>
    <updated>2011-03-04T05:31:14-07:00</updated>
    <id>http://belchak.com/2011/03/04/workfit-standing-desk</id>
    <content type="html"><![CDATA[<p>A few months ago, I started investigating the health benefits of standing while I work at my computer. The benefits are myriad, and include:</p>

<ul>
<li><p><strong>More calories burned</strong>. Standing at a desk while you work can actually burn around 300 calories per day more than sitting.</p></li>
<li><p><strong>Standing at a desk helps people with back problems</strong>. Humans were not made for sitting, and doing so for long periods of time can be really hard on your hips and lower back.</p></li>
<li><p><strong>Improved posture. </strong>Standing can help improve your posture, which can relieve pain in your lower and upper back, and neck.</p></li>
<li><p><strong>More breaks. </strong>I find that I take more breaks, which makes me happier and healthier. While standing, it is easier to just walk away instead of hauling yourself out of a chair.</p></li>
</ul>


<p>After my research, I decided to convert my cheap IKEA desk into a standing desk by raising the legs up as far as they could go and then stacking books and Rubbermaid bins to get the height on the keyboard and monitors right. Here&#8217;s what I ended up with:</p>

<p><img class="left" src="http://www.belchak.com/wp-content/uploads/2011/03/IMG_0042.jpg" width="224" height="224"></p>

<p>As you can see, it is less than ideal. It forced me to stand 100% of the time, and in order to take a break from standing, I needed to disconnect my laptop from everything and take it to a chair. Not awesome.</p>

<p>I reverted back to a sitting desk, and kept wishing for a standing option that would allow me to quickly change to a sitting position if I got tired, without having to deal with completely rearranging my work area.</p>

<p>Then, I discovered the Ergotron WorkFit-S while searching around for standing desk options. I loved the youtube video I found here:</p>

<p>I bought the WorkFit-S Combo (laptop + LCD) on Amazon with overnight shipping with my Amazon Prime account, and it arrived very quickly. I was a bit worried because the tech specs indicated that the maximum monitor size is 20&#8221; while using a laptop. I spoke with one of their marketing people on Twitter, and they were very helpful, checking with their support staff and product managers to provide me with any tips that they could dig up while I anxiously awaited the FedEx delivery guy.</p>

<p>When I received it, I immediately installed it on my desk. It took approximately 15 minutes to get it built and installed on my desk. My 24&#8221; LCD fit perfectly on the right, with my laptop on the left. I think the concern with the size of the monitor is not necessarily the size, but the weight. I could probably fit a 27&#8221; on here without a problem if it was light enough. My LCD and laptop are probably right on the edge of the maximum weight. Since the up and down motion is achieved with a pulley system, I had to adjust the tension a bit to get the balance right.</p>

<p><img src="http://www.belchak.com/wp-content/uploads/2011/03/IMG_0253-224x300.jpg"></p>

<p>I did have to move it after I&#8217;d installed it in the center of my corner desk because the mouse tray kept hitting the desk where it curves.</p>

<p>The thing will attach to virtually any surface, but they also make a wheeled cart that has similar features.</p>

<p><img src="http://www.belchak.com/wp-content/uploads/2011/03/IMG_0252-224x300.jpg"></p>

<p>I am very happy with it so far, and I look forward to reaping the benefits of standing, while having the option to sit!</p>

<p>The Ergotron WorkFit retails for around $399 and you can find them on <a href="http://www.amazon.com/s/ref=nb_sb_noss?url=search-alias%3Daps&amp;field-keywords=workfit-s&amp;x=0&amp;y=0">Amazon.com</a> or elsewhere.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Unit Testing Django with a NoSQL Backend]]></title>
    <link href="http://belchak.com/2011/02/07/unit-testing-django-with-a-nosql-backend/"/>
    <updated>2011-02-07T12:44:24-07:00</updated>
    <id>http://belchak.com/2011/02/07/unit-testing-django-with-a-nosql-backend</id>
    <content type="html"><![CDATA[<p>In my previous post about <a href="http://www.belchak.com/2011/02/05/unit-testing-your-django-application/">unit testing for django</a>, I laid the groundwork for how to unit test any django application. One nice feature that django includes with its test framework is the test database syncing. Even better is if you are using <a href="http://www.belchak.com/2011/01/27/django-database-migrations-with-south/">South</a> to do database migrations - it will run the migrations in  your test environment for you.</p>

<p>However, what if you are using a NoSQL database backend like MongoDB, Cassandra, CouchDB or something similar and you aren&#8217;t using the Django ORM? How do you handle setting up and tearing down the database environments?</p>

<p>The good news is that Python&#8217;s unittest framework makes this easy. You can override the <code>setUp()</code> and <code>tearDown()</code> on each TestCase that you build. Here is a snippet to get you started:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
</pre></td><td class='code'><pre><code class='python'><span class='line'><span class="kn">import</span> <span class="nn">pymongo</span>
</span><span class='line'><span class="kn">from</span> <span class="nn">django.test</span> <span class="kn">import</span> <span class="n">TestCase</span>
</span><span class='line'>
</span><span class='line'><span class="c"># It would be best to define this in a utility class somewhere</span>
</span><span class='line'><span class="k">def</span> <span class="nf">get_db</span><span class="p">(</span><span class="n">db_name</span><span class="o">=</span><span class="bp">None</span><span class="p">):</span>
</span><span class='line'>    <span class="sd">&quot;&quot;&quot; GetDB - simple function to wrap getting a database</span>
</span><span class='line'><span class="sd">    connection from the connection pool.</span>
</span><span class='line'><span class="sd">    &quot;&quot;&quot;</span>
</span><span class='line'>    <span class="k">return</span> <span class="n">pymongo</span><span class="o">.</span><span class="n">Connection</span><span class="p">(</span>
</span><span class='line'>            <span class="n">host</span><span class="o">=</span><span class="n">settings</span><span class="o">.</span><span class="n">MONGO_HOST</span><span class="p">,</span>
</span><span class='line'>            <span class="n">port</span><span class="o">=</span><span class="n">settings</span><span class="o">.</span><span class="n">MONGO_PORT</span><span class="p">)[</span><span class="nb">getattr</span><span class="p">(</span>
</span><span class='line'>                <span class="n">settings</span><span class="p">,</span> <span class="s">&quot;MONGO_DBNAME_PREFIX&quot;</span><span class="p">,</span> <span class="s">&quot;&quot;</span><span class="p">)</span> <span class="o">+</span>
</span><span class='line'>                <span class="p">(</span><span class="n">db_name</span> <span class="ow">or</span> <span class="n">settings</span><span class="o">.</span><span class="n">MONGO_DBNAME</span><span class="p">)]</span>
</span><span class='line'>
</span><span class='line'><span class="k">class</span> <span class="nc">MyTestCase</span><span class="p">(</span><span class="n">TestCase</span><span class="p">):</span>
</span><span class='line'>    <span class="n">fixtures</span> <span class="o">=</span> <span class="p">[</span><span class="s">&#39;test_data.json&#39;</span><span class="p">]</span>
</span><span class='line'>    <span class="k">def</span> <span class="nf">setUp</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
</span><span class='line'>        <span class="bp">self</span><span class="o">.</span><span class="n">db</span> <span class="o">=</span> <span class="n">get_db</span><span class="p">(</span><span class="s">&#39;test&#39;</span><span class="p">)</span>
</span><span class='line'>        <span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">create_collection</span><span class="p">(</span><span class="s">&#39;mytestcollection&#39;</span><span class="p">)</span>
</span><span class='line'>
</span><span class='line'>    <span class="k">def</span> <span class="nf">test_doc_published</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
</span><span class='line'>        <span class="c"># Set up a document to save</span>
</span><span class='line'>        <span class="n">doc</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">(</span><span class="n">text</span><span class="o">=</span><span class="s">&quot;test&quot;</span><span class="p">,</span>
</span><span class='line'>                      <span class="n">user_id</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>
</span><span class='line'>        <span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">mytestcollection</span><span class="o">.</span><span class="n">save</span><span class="p">(</span><span class="n">doc</span><span class="p">)</span>
</span><span class='line'>        <span class="bp">self</span><span class="o">.</span><span class="n">assertEqual</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">mytestcollection</span><span class="o">.</span><span class="n">find_one</span><span class="p">(</span>
</span><span class='line'>            <span class="p">{</span><span class="s">&#39;user_id&#39;</span><span class="p">:</span><span class="mi">1</span><span class="p">})[</span><span class="s">&#39;text&#39;</span><span class="p">],</span> <span class="s">&#39;test&#39;</span><span class="p">)</span>
</span><span class='line'>
</span><span class='line'>    <span class="k">def</span> <span class="nf">tearDown</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
</span><span class='line'>        <span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">drop_collection</span><span class="p">(</span><span class="s">&#39;mytestcollection&#39;</span><span class="p">)</span>
</span></code></pre></td></tr></table></div></figure>


<p>What this does is <code>setUp()</code> a collection in the <code>mytestcollection</code> collection, runs the <code>my_doc_published</code> test and then tears down the test database environment by dropping the <code>mytestcollection</code> collection.</p>

<p>Things to remember for <code>setUp()</code> and <code>tearDown()</code>:</p>

<ul>
<li><p><code>setUp()</code> is called before every test method in your TestCase class.</p></li>
<li><p><code>tearDown()</code> is called after every test method in your TestCase class.</p></li>
<li><p><code>tearDown()</code> is called even if your test methods fail or error out.</p></li>
</ul>


<p>And there you have it! Django makes testing even non-ORM datasources a snap, if you know how to wire it up.
<strong>UPDATE:</strong> Some would say that database fixtures and setting up/tearing down database environments as part of your unit tests is not &#8220;unit testing&#8221;. This is not entirely accurate, because in order to do unit tests that rely on backend data, you <strong>must</strong> instantiate and tear down pristine database environments.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Unit Testing Your Django Application]]></title>
    <link href="http://belchak.com/2011/02/05/unit-testing-your-django-application/"/>
    <updated>2011-02-05T14:33:40-07:00</updated>
    <id>http://belchak.com/2011/02/05/unit-testing-your-django-application</id>
    <content type="html"><![CDATA[<p>Unit testing is a very important part of any software project. It helps you know that the new code you are deploying works, and isn&#8217;t going to blow up in your face. It also helps you feel good about changing large chunks of code without destroying everything you&#8217;ve done for the last 3 years.</p>

<p>Unit testing with django is as simple as pie. <a href="http://docs.djangoproject.com/en/dev/topics/testing/">The documentation</a> is very good, and you can learn a lot about more advanced testing methods from <a href="http://docs.python.org/library/unittest.html">the python documentation</a>. In this blog post, I aim to show a quick way to get up and running with testing your django application.</p>

<p>First, if you are just starting out, make sure you put a high emphasis on testing your application, otherwise you are going to end up with a bunch of code that has never been tested and you will find yourself writing code for weeks just to get partial coverage on the code you&#8217;ve already written. Starting off on the right foot is a much better approach, and you will find life much more enjoyable.</p>

<p>Let&#8217;s get started&#8230;</p>

<p>First of all, you need to define your models:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
</pre></td><td class='code'><pre><code class='python'><span class='line'><span class="kn">from</span> <span class="nn">django.db</span> <span class="kn">import</span> <span class="n">models</span>
</span><span class='line'><span class="kn">from</span> <span class="nn">django.contrib.auth.models</span> <span class="kn">import</span> <span class="n">User</span>
</span><span class='line'>
</span><span class='line'><span class="k">class</span> <span class="nc">Post</span><span class="p">(</span><span class="n">models</span><span class="o">.</span><span class="n">Model</span><span class="p">):</span>
</span><span class='line'>    <span class="n">title</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">max_length</span><span class="o">=</span><span class="mi">50</span><span class="p">)</span>
</span><span class='line'>    <span class="n">body</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">TextField</span><span class="p">()</span>
</span><span class='line'>    <span class="n">author</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">ForeignKey</span><span class="p">(</span><span class="n">User</span><span class="p">,</span> <span class="n">related_name</span><span class="o">=</span><span class="s">&quot;news_post&quot;</span><span class="p">)</span>
</span><span class='line'>    <span class="n">date</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">DateTimeField</span><span class="p">()</span>
</span><span class='line'>    <span class="n">users_read</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">ManyToManyField</span><span class="p">(</span><span class="n">User</span><span class="p">,</span> <span class="n">related_name</span><span class="o">=</span><span class="s">&quot;users&quot;</span><span class="p">,</span> <span class="n">blank</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
</span><span class='line'>
</span><span class='line'>    <span class="k">def</span> <span class="nf">__str__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
</span><span class='line'>        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">title</span>
</span></code></pre></td></tr></table></div></figure>


<p>What we have done here is created a news post item. Let&#8217;s test it!</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
</pre></td><td class='code'><pre><code class='python'><span class='line'><span class="k">class</span> <span class="nc">PostTestCase</span><span class="p">(</span><span class="n">TestCase</span><span class="p">):</span>
</span><span class='line'>    <span class="n">fixtures</span> <span class="o">=</span> <span class="p">[</span><span class="s">&#39;test_data.json&#39;</span><span class="p">]</span>
</span><span class='line'>    <span class="k">def</span> <span class="nf">setUp</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
</span><span class='line'>        <span class="bp">self</span><span class="o">.</span><span class="n">user</span> <span class="o">=</span> <span class="n">User</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">create_user</span><span class="p">(</span><span class="s">&#39;newsposter&#39;</span><span class="p">,</span>
</span><span class='line'>                                             <span class="s">&#39;newsposter@news.com&#39;</span><span class="p">,</span> <span class="s">&#39;newspass&#39;</span><span class="p">)</span>
</span><span class='line'>        <span class="bp">self</span><span class="o">.</span><span class="n">post</span> <span class="o">=</span> <span class="n">Post</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">create</span><span class="p">(</span><span class="n">title</span><span class="o">=</span><span class="s">&quot;Test Post #1&quot;</span><span class="p">,</span>
</span><span class='line'>                <span class="n">body</span><span class="o">=</span><span class="s">&quot;Test Post #1 Body&quot;</span><span class="p">,</span>
</span><span class='line'>                <span class="n">author</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">user</span><span class="p">,</span>
</span><span class='line'>                <span class="n">date</span><span class="o">=</span><span class="n">datetime</span><span class="o">.</span><span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">())</span>
</span><span class='line'>        <span class="bp">self</span><span class="o">.</span><span class="n">c</span> <span class="o">=</span> <span class="n">Client</span><span class="p">()</span>
</span><span class='line'>
</span><span class='line'>
</span><span class='line'>    <span class="k">def</span> <span class="nf">test_post_creation</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
</span><span class='line'>        <span class="sd">&quot;&quot;&quot;</span>
</span><span class='line'><span class="sd">        Tests that we can create a Post</span>
</span><span class='line'><span class="sd">        &quot;&quot;&quot;</span>
</span><span class='line'>        <span class="bp">self</span><span class="o">.</span><span class="n">assertEqual</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">post</span><span class="o">.</span><span class="n">title</span><span class="p">,</span> <span class="s">&quot;Test Post #1&quot;</span><span class="p">)</span>
</span><span class='line'>        <span class="bp">self</span><span class="o">.</span><span class="n">assertEqual</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">post</span><span class="o">.</span><span class="n">author</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">user</span><span class="p">)</span>
</span><span class='line'>
</span><span class='line'>    <span class="k">def</span> <span class="nf">test_user_can_read</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
</span><span class='line'>        <span class="sd">&quot;&quot;&quot;</span>
</span><span class='line'><span class="sd">        Tests that a user is allowed to read.</span>
</span><span class='line'><span class="sd">        &quot;&quot;&quot;</span>
</span><span class='line'>        <span class="bp">self</span><span class="o">.</span><span class="n">c</span><span class="o">.</span><span class="n">login</span><span class="p">(</span><span class="n">username</span><span class="o">=</span><span class="s">&#39;newsposter&#39;</span><span class="p">,</span> <span class="n">password</span><span class="o">=</span><span class="s">&#39;newspass&#39;</span><span class="p">)</span>
</span><span class='line'>        <span class="n">response</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">c</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">&#39;/news/get_post/1/&#39;</span><span class="p">)</span>
</span><span class='line'>        <span class="bp">self</span><span class="o">.</span><span class="n">assertEqual</span><span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">status_code</span><span class="p">,</span> <span class="mi">200</span><span class="p">)</span>
</span><span class='line'>        <span class="bp">self</span><span class="o">.</span><span class="n">assertNotEqual</span><span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">content</span><span class="p">,</span> <span class="s">&#39;{}&#39;</span><span class="p">)</span>
</span></code></pre></td></tr></table></div></figure>


<p>One of the really cool thing about testing with django is that it comes with a testing client that allows you to make requests just like a real user would. As you can see in our <code>test_user_can_read()</code> method, we have used the client to make a GET request against a URL. You can make a POST request just as easily:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
</pre></td><td class='code'><pre><code class='python'><span class='line'><span class="k">def</span> <span class="nf">test_i_read_this</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
</span><span class='line'>    <span class="sd">&quot;&quot;&quot;</span>
</span><span class='line'><span class="sd">    Tests a new user marking the story as read.</span>
</span><span class='line'><span class="sd">    &quot;&quot;&quot;</span>
</span><span class='line'>    <span class="bp">self</span><span class="o">.</span><span class="n">c</span><span class="o">.</span><span class="n">login</span><span class="p">(</span><span class="n">username</span><span class="o">=</span><span class="s">&#39;newsposter&#39;</span><span class="p">,</span> <span class="n">password</span><span class="o">=</span><span class="s">&#39;newspass&#39;</span><span class="p">)</span>
</span><span class='line'>    <span class="n">response</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">c</span><span class="o">.</span><span class="n">post</span><span class="p">(</span><span class="s">&#39;/news/read/1/&#39;</span><span class="p">,</span> <span class="p">{</span><span class="s">&#39;add&#39;</span><span class="p">:</span><span class="bp">True</span><span class="p">})</span>
</span><span class='line'>    <span class="bp">self</span><span class="o">.</span><span class="n">assertEqual</span><span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">status_code</span><span class="p">,</span> <span class="mi">200</span><span class="p">)</span>
</span><span class='line'>    <span class="bp">self</span><span class="o">.</span><span class="n">assertEquals</span><span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">content</span><span class="p">,</span> <span class="s">&#39;{</span><span class="se">\n</span><span class="s">    &quot;read&quot;: true</span><span class="se">\n</span><span class="s">}&#39;</span><span class="p">)</span>
</span></code></pre></td></tr></table></div></figure>


<p>In the previous code sample, the client sends a POST request to <code>/news/read/1/</code> with the <code>{'add':True}</code> data. This gets converted to form data and submitted via the POST. The request returns back JSON, which we match up against what we expect it to return.</p>

<p>Here are some things to remember when you are writing your test cases:</p>

<ul>
<li><p><code>setUp()</code> gets called before <strong>every</strong> test method in your TestCase.</p></li>
<li><p><code>tearDown()</code> gets called after <strong>every</strong> test method in your TestCase.</p></li>
<li><p>Test methods <strong>must</strong> start with &#8220;test&#8221; otherwise they will not be executed. It is safe to have other methods in your TestCase that do not begin with &#8220;test&#8221; if you want to abstract functionality for multiple test methods into a single function.</p></li>
<li><p>Django creates a test database for you, populates it, runs any south migrations (if you are using south), and then destroys it.</p></li>
<li><p>Do not expect that data that is available in one of your test methods will be available in another. Each test method starts with a blank data slate. If you need data instantiated before your tests are run, consider using the <code>setUp()</code> and <code>tearDown()</code> methods, or using fixtures. You can specify fixtures other than your initial_data fixtures by adding <code>fixtures = ['test_data.json']</code> to your TestCase class.</p></li>
</ul>


<p>Here is in-depth documentation about what assert methods are available to you in different versions of Python in <a href="http://docs.python.org/library/unittest.html#test-cases">the official Python unittest documentation</a>.</p>

<p>As you can see, testing with django is really really simple, but very powerful. In my next post, I will discuss how to test django with a MongoDB backend that does not use the ORM.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Code Completion (IntelliSense) in VIM]]></title>
    <link href="http://belchak.com/2011/01/31/code-completion-for-python-and-django-in-vim/"/>
    <updated>2011-01-31T01:58:05-07:00</updated>
    <id>http://belchak.com/2011/01/31/code-completion-for-python-and-django-in-vim</id>
    <content type="html"><![CDATA[<p><a href="http://www.vim.org/">VIM</a> has been my editor of choice for at least 15 years. I love how fast I can edit files, perform menial tasks, and wreak general havoc on any code project I am working on at any given moment. One of the things that I have missed about VIM from an IDE perspective has been code completion (a.k.a. &#8220;IntelliSense&#8221;). I have spent a lot of time on websites and man pages trying to figure out syntax and function names for several types of languages, and just recently discovered a long-included feature of VIM called omni completion, or Omnicomplete.</p>

<p>Since my life is mostly centered around <a href="http://www.djangoproject.com">django</a> these days, I will discuss how I&#8217;ve benefited from omnicomplete and how I&#8217;ve set it up in my own environment.</p>

<p>First, since django is a web development framework, I want to make sure that I can get omnicompletion for HTML, Python, JavaScript and CSS. Omnicompletion works for almost any programming language that VIM has syntax highlighting support for, and these languages are no exception.</p>

<p>Here&#8217;s what omnicomplete looks like for CSS files, for example:</p>

<p><img src="http://www.belchak.com/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-3.37.00-PM-1-30-11-300x213.png" width="300" title="&#34;omnicomplete for vim&#34;" alt="&#34;omnicomplete for vim&#34;"></p>

<p>Setting this up for your django project is simple as pie. It is helpful to have all your django projects in one parent directory for the following setup. You can obviously customize this to your needs, but this is the way I&#8217;ve set it up in my environment.</p>

<p>Add the following to a script in a directory of your choosing (~/bin/vim_wrapper is where mine is):</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'><span class="c">#!/bin/bash</span>
</span><span class='line'><span class="nb">export </span><span class="nv">PROJECT</span><span class="o">=</span><span class="sb">`</span>python -c <span class="s2">&quot;import os; print os.path.basename(os.getcwd())&quot;</span><span class="sb">`</span>
</span><span class='line'><span class="nb">export </span><span class="nv">PYTHONPATH</span><span class="o">=</span><span class="s2">&quot;/path/to/your/projects/parent/directory/&quot;</span>
</span><span class='line'><span class="nb">export </span><span class="nv">DJANGO_SETTINGS_MODULE</span><span class="o">=</span><span class="nv">$PROJECT</span>.settings vim
</span><span class='line'><span class="nv">$@</span>
</span></code></pre></td></tr></table></div></figure>


<p>Then add the following line to your ~/.bash_profile or equivalent:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'><span class="nb">alias </span><span class="nv">vi</span><span class="o">=</span><span class="s2">&quot;vim_wrapper&quot;</span>
</span></code></pre></td></tr></table></div></figure>


<p>Or, you can call your vim_wrapper script by hand. (<code>vim_wrapper file_to_edit.py</code>)</p>

<p>Next, add the following lines to your ~/.vimrc file:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'>filetype plugin on
</span><span class='line'>autocmd FileType python <span class="nb">set </span><span class="nv">omnifunc</span><span class="o">=</span>pythoncomplete#Complete
</span><span class='line'>autocmd FileType javascript <span class="nb">set </span><span class="nv">omnifunc</span><span class="o">=</span>javascriptcomplete#CompleteJS
</span><span class='line'>autocmd FileType html <span class="nb">set </span><span class="nv">omnifunc</span><span class="o">=</span>htmlcomplete#CompleteTags
</span><span class='line'>autocmd FileType css <span class="nb">set </span><span class="nv">omnifunc</span><span class="o">=</span>csscomplete#CompleteCSS
</span></code></pre></td></tr></table></div></figure>


<p>I also prefer to re-map the default key binding (<C-x><C-o>) to <C-space>, so I accomplish this by also adding the following line to my ~/.vimrc file:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'>inoremap &lt;C-space&gt; &lt;C-x&gt;&lt;C-o&gt;
</span></code></pre></td></tr></table></div></figure>


<p>I also found <a href="http://blogs.gnome.org/lharris/2008/07/20/code-completion-with-vim-7/">this trick</a> today while searching around&#8230;</p>

<blockquote><p>What this function does is that if there is no completion that could happen it will insert a tab.  Otherwise it checks to see if there is an omnifunction available and, if so, uses it. Otherwise it falls back to Dictionary completion if there is a dictionary defined.  Finally it resorts to simple known word completion.  In general, hitting the Tab key will just do the right thing for you in any given situation.</p></blockquote>

<p>Add the following to your ~/.vimrc and you should be good to go. It works like a charm for me.</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'><span class="k">function</span>! SuperCleverTab<span class="o">()</span>
</span><span class='line'>    <span class="k">if </span>strpart<span class="o">(</span>getline<span class="o">(</span><span class="s1">&#39;.&#39;</span><span class="o">)</span>, 0, col<span class="o">(</span><span class="s1">&#39;.&#39;</span><span class="o">)</span> - 1<span class="o">)</span> <span class="o">=</span>~ <span class="s1">&#39;^\s*$&#39;</span>
</span><span class='line'>        <span class="k">return</span> <span class="s2">&quot;\&quot;</span>
</span><span class='line'><span class="s2">    else</span>
</span><span class='line'><span class="s2">        if &amp;omnifunc != &#39;&#39;</span>
</span><span class='line'><span class="s2">            return &quot;</span><span class="se">\\</span><span class="s2">&quot;</span>
</span><span class='line'><span class="s2">        elseif &amp;dictionary != &#39;&#39;</span>
</span><span class='line'><span class="s2">            return &quot;</span><span class="se">\&quot;</span>
</span><span class='line'>        <span class="k">else</span>
</span><span class='line'><span class="k">            return</span> <span class="err">&quot;</span><span class="se">\&quot;</span>
</span><span class='line'>        endif
</span><span class='line'>    endif
</span><span class='line'>endfunction
</span><span class='line'>
</span><span class='line'>inoremap &lt;Tab&gt; &lt;C-R&gt;<span class="o">=</span>SuperCleverTab<span class="o">()</span>&lt;cr&gt;
</span></code></pre></td></tr></table></div></figure>


<p>If you find yourself writing code in other languages, the following lines in your vimrc should be adequate:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'>filetype plugin on
</span><span class='line'><span class="nb">set </span><span class="nv">ofu</span><span class="o">=</span>syntaxcomplete#Complete
</span></code></pre></td></tr></table></div></figure>


<p>You can now test that your installation works by changing directories to one of your django projects, firing up vim and running the following command:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'>:python from django import db
</span></code></pre></td></tr></table></div></figure>


<p>If you do not get a horrible error, you are good to go!</p>

<p>You can now access code completion by the following methods:</p>

<ul>
<li><p><code>&lt;C-p&gt;</code> - Shows a list of all local symbols. This is good if you do not have a tags file associated with the file you are editing.</p></li>
<li><p><code>&lt;C-space&gt;</code> - Shows a list of all available symbols. You need to set up a tags file, which is outside the scope of this blog post</p></li>
<li><p><code>&lt;C-x&gt;&lt;C-o&gt;</code> - The original keystroke sequence that we re-mapped C-space to.</p></li>
<li><p><code>&lt;Tab&gt;</code> - The all-powerful tab!`</p></li>
</ul>


<p>I hope you enjoy your new-found power with vim as much as I do!</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Django database migrations with South]]></title>
    <link href="http://belchak.com/2011/01/27/django-database-migrations-with-south/"/>
    <updated>2011-01-27T10:04:04-07:00</updated>
    <id>http://belchak.com/2011/01/27/django-database-migrations-with-south</id>
    <content type="html"><![CDATA[<p>I have been using <a href="http://djangoproject.com">django</a> for web development for almost a year now, and I just recently started using <a href="http://south.aeracode.org/">South</a> to do database migrations. To be fair, most of the work that I have been doing with databases has centered around <a href="http://www.mongodb.org">MongoDB</a> and schema-less document stores instead of a traditional RDBMS. Since Django does not come with any database migration tools, my standard approach was to make sure that my models are completely thought out before running the manage.py syncdb command. The lack of a good database migration tool was one of the things that originally had turned me off to django.</p>

<p>Enter South. South lets you manage your database in a way very similar to how <a href="http://rubyonrails.org">Ruby on Rails</a> works.</p>

<p>Converting a project to a South-managed project is very easy:</p>

<ol>
<li><p>Ensure that your database and models are completely synced up. (i.e. your models are not ahead of your database or vice-versa)</p></li>
<li><p>Install South by running <code>[sudo] pip install south</code></p></li>
<li><p>Add South to your <code>INSTALLED_APPS</code> list in the <code>settings.py</code> for your django project.</p></li>
<li><p>Run <code>./manage.py syncdb</code> in your project root directory to add the South database tables to your database.</p></li>
<li><p>If you have an existing application that you would like to conver to a South-managed application, run the following command: <code>./manage.py convert_to_south YOUR_APP_NAME</code> If not, go to the next step!</p></li>
<li><p>Now you are ready to go! You can change one of your models and then proceed to the next step.</p></li>
<li><p>Run the following command to get South to create an automatic migration for you: <code>./manage.py schemamigration YOUR_APP_NAME --auto</code></p></li>
<li><p>Now you can apply your newly created migration to your database:<code>./manage.py migrate YOUR_APP_NAME</code></p></li>
<li><p>Congratulations, you have performed your first database migration using South!</p></li>
</ol>


<p>South lets you apply up to or back to any migration point by running a command like: <code>./manage.py migrate YOUR_APP_NAME 0001</code> (that command would take you back to your initial migration point. You can get a list of all your migrations and a description about each one by running <code>./manage.py migrate YOUR_APP_NAME --list</code>. This lists all of the migrations you have available and denotes with a (*) which ones have been applied.</p>

<p>South is great for working in a team. All migrations are stored in YOUR_APP_NAME/migrations, so you can simply add these to your VCS and all of your team  members will get all of your migrations. If there is a conflict in some of the migrations that you and a team member have been working on, South will detect it and let you <a href="http://south.aeracode.org/docs/tutorial/part5.html#team-workflow">merge the conflicts</a>.</p>

<p>All in all, I am really loving South. It makes working with an RDBMS and Django much more pleasant!</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Removing old ssh fingerprints from your known_hosts the quick and easy way]]></title>
    <link href="http://belchak.com/2011/01/27/removing-old-ssh-fingerprints-from-your-known_hosts-the-quick-and-easy-way/"/>
    <updated>2011-01-27T05:38:05-07:00</updated>
    <id>http://belchak.com/2011/01/27/removing-old-ssh-fingerprints-from-your-known_hosts-the-quick-and-easy-way</id>
    <content type="html"><![CDATA[<p>Ever have this problem? You just rebuilt a machine, and when you go to SSH into it, you get the following message:</p>

<pre><code>@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
</code></pre>

<p>Many people just go edit their <code>~/.ssh/known_hosts</code> file and carry on. But there is a faster/better way!</p>

<p>OpenSSH comes with a command called <code>ssh-keygen</code> that allows you to generate and manage all your keys, including your ssh fingerprints.</p>

<p>Simple usage for this would be:</p>

<pre><code>ssh-keygen -R HOSTNAME
</code></pre>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Automatic MongoDB Backups to S3]]></title>
    <link href="http://belchak.com/2011/01/20/automatic-mongodb-backups-to-s3/"/>
    <updated>2011-01-20T01:00:46-07:00</updated>
    <id>http://belchak.com/2011/01/20/automatic-mongodb-backups-to-s3</id>
    <content type="html"><![CDATA[<p>One of the big problems with hosting your own database solution is that you have to do backups for it on a regular basis. Not only do you need to do backups for it, but you need to also keep backups offsite. Luckily, <a href="http://aws.amazon.com/s3/">Amazon S3</a> allows a cheap and easy solution for your offsite backups.</p>

<p>I found a shell <a href="https://github.com/micahwedemeyer/automongobackup">script solution</a> for handling MongoDB backups, but it only does local backups. It keeps a nice history of recent backups, and rotates off the oldest ones when the threshold for age is reached. I modified the code to call a Python script that then synchronizes the newly created backup file to S3. I haven&#8217;t wired up any purging functionality yet, and I don&#8217;t know if I am going to. S3 storage is so cheap that it really doesn&#8217;t matter much. A complete solution would, of course, keep your local files and your remote off-site backups in S3 in sync, but there is also a case to be made for keeping a rich history of backups in the &#8220;cloud&#8221; so as to be able to revert to any point in history if necessary.</p>

<p>The script that does the magic to synchronize and purge old backups is written in Python, and uses the <a href="https://github.com/boto/boto">boto</a> library to quickly do the work.</p>

<pre><code>ACCESS_KEY='YOUR_ACCESS_KEY'
SECRET='YOUR_SECRET_KEY'
BUCKET_NAME='YOUR_BACKUPS_BUCKET' #note that you need to create this bucket first

from boto.s3.connection import S3Connection
from boto.s3.key import Key

def save_file_in_s3(filename):
    conn = S3Connection(ACCESS_KEY, SECRET)
    bucket = conn.get_bucket(BUCKET_NAME)
    k = Key(bucket)
    k.key = filename
    k.set_contents_from_filename(filename)

def get_file_from_s3(filename):
    conn = S3Connection(ACCESS_KEY, SECRET)
    bucket = conn.get_bucket(BUCKET_NAME)
    k = Key(bucket)
    k.key = filename
    k.get_contents_to_filename(filename)

def list_backup_in_s3():
    conn = S3Connection(ACCESS_KEY, SECRET)
    bucket = conn.get_bucket(BUCKET_NAME)
    for i, key in enumerate(bucket.get_all_keys()):
        print "[%s] %s" % (i, key.name)

def delete_all_backups():
    #FIXME: validate filename exists
    conn = S3Connection(ACCESS_KEY, SECRET)
    bucket = conn.get_bucket(BUCKET_NAME)
    for i, key in enumerate(bucket.get_all_keys()):
        print "deleting %s" % (key.name)
        key.delete()

if __name__ == '__main__':
    import sys
    if len(sys.argv) &lt; 3:
        print 'Usage: %s  ' % (sys.argv[0])
    else:
        if sys.argv[1] == 'set':
            save_file_in_s3(sys.argv[2])
        elif sys.argv[1] == 'get':
            get_file_from_s3(sys.argv[2])
        elif sys.argv[1] == 'list':
            list_backup_in_s3()
        elif sys.argv[1] == 'delete':
            delete_all_backups()
        else:
            print 'Usage: %s  ' % (sys.argv[0])
</code></pre>

<p>There is obviously a lot more work to be done on this script, but it&#8217;s a start.</p>

<p>The appropriate setup for using this script and the AutoMongoBackup utility is to create a slave MongoDB node that receives synchronizations from the master. If you can handle having your Mongo instance locked for reads/writes while a backup is performed (i.e. you have a small database that backs up quickly) then you more than likely do not need to do the slave method.</p>

<p>Anyway, hope this helps! I&#8217;d love to hear other ideas about how else this can be done.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Problems with Facebook API and M2Crypto]]></title>
    <link href="http://belchak.com/2011/01/19/problems-with-facebook-api-and-m2crypto/"/>
    <updated>2011-01-19T16:25:36-07:00</updated>
    <id>http://belchak.com/2011/01/19/problems-with-facebook-api-and-m2crypto</id>
    <content type="html"><![CDATA[<p>After doing some crypto updates to a django application that I am working on, I discovered that the Facebook API was dog slow for retrieving any query using HTTPS. Turns out that the M2Crypto library apparently hijacks the SSL processing of urllib and mucks everything up. Thanks to <a href="http://hustoknow.blogspot.com/2011/01/m2crypto-and-facebooks-sdk-hangs.html">this handy blog post</a>, I was able to fix my Python implementation of the Facebook API and get things speeding along again.</p>

<p>The fix is basically to add the following lines before any <code>urllib.urlopen()</code> call (in my case, I only have two - one for GET and one for POST):</p>

<pre><code>        urllib._urlopener = urllib.FancyURLopener()
        urllib._urlopener.addheader('Connection', 'close')
</code></pre>
]]></content>
  </entry>
  
</feed>
