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

  <title>It's all connected</title>
  <link href="http://www.kraken.no/atom.xml" rel="self"/>
  <link href="http://www.kraken.no/"/>
  <updated>2012-03-23T11:12:50+01:00</updated>
  <id>http://www.kraken.no/</id>
  <author>
    <name>Tarjei Huse</name>
    
  </author>

  
  <entry>
    <title>Patterns for testing asynchronous javascripts.</title>
    <link href="http://www.kraken.no/blog/2012/03/23/notes-on-async-js-tests/"/>
    <updated>2012-03-23T10:47:00+01:00</updated>
    <id>http://www.kraken.no/blog/2012/03/23/notes-on-async-js-tests</id>
    <content type="html">&lt;p&gt;Many javascript test frameworks have a consept of async tests where your tests follow this pattern:&lt;/p&gt;

&lt;div&gt;&lt;figure role=code&gt;&lt;figcaption&gt;&lt;span&gt;someTestCode.js &lt;/span&gt;&lt;/figcaption&gt;
 &lt;div class=&quot;highlight&quot;&gt;&lt;table cellpadding=&quot;0&quot; cellspacing=&quot;0&quot;&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class='line'&gt;1&lt;/span&gt;
&lt;span class='line'&gt;2&lt;/span&gt;
&lt;span class='line'&gt;3&lt;/span&gt;
&lt;span class='line'&gt;4&lt;/span&gt;
&lt;span class='line'&gt;5&lt;/span&gt;
&lt;span class='line'&gt;6&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code' width='100%'&gt;&lt;pre&gt;&lt;code class='js'&gt;&lt;div class='line'&gt;    &lt;span class=&quot;s2&quot;&gt;&amp;quot;test http request&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;done&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;        &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;post&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;/some/url&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{},&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;success&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;            &lt;span class=&quot;nx&quot;&gt;asset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;equals&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;ok&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;            &lt;span class=&quot;nx&quot;&gt;done&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;        &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;


&lt;p&gt;I spent quite some time debugging a testcase looking like this one, can you spot the error?&lt;/p&gt;

&lt;p&gt;The problem with the code above is that done() only gets executed on success. If your request fails, then your test will timeout instead of telling you
what happened.&lt;/p&gt;

&lt;p&gt;The fixed testcase looks like this:&lt;/p&gt;

&lt;div&gt;&lt;figure role=code&gt;&lt;figcaption&gt;&lt;span&gt;someTestCode.js &lt;/span&gt;&lt;/figcaption&gt;
 &lt;div class=&quot;highlight&quot;&gt;&lt;table cellpadding=&quot;0&quot; cellspacing=&quot;0&quot;&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class='line'&gt;1&lt;/span&gt;
&lt;span class='line'&gt;2&lt;/span&gt;
&lt;span class='line'&gt;3&lt;/span&gt;
&lt;span class='line'&gt;4&lt;/span&gt;
&lt;span class='line'&gt;5&lt;/span&gt;
&lt;span class='line'&gt;6&lt;/span&gt;
&lt;span class='line'&gt;7&lt;/span&gt;
&lt;span class='line'&gt;8&lt;/span&gt;
&lt;span class='line'&gt;9&lt;/span&gt;
&lt;span class='line'&gt;10&lt;/span&gt;
&lt;span class='line'&gt;11&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code' width='100%'&gt;&lt;pre&gt;&lt;code class='js'&gt;&lt;div class='line'&gt;    &lt;span class=&quot;s2&quot;&gt;&amp;quot;test http request&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;done&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;        &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;post&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;/some/url&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{},&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;success&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;            &lt;span class=&quot;nx&quot;&gt;asset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;equals&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;ok&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;            &lt;span class=&quot;nx&quot;&gt;done&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;        &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;        &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;            &lt;span class=&quot;nx&quot;&gt;assert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Ajax failed&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;            &lt;span class=&quot;nx&quot;&gt;done&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;        &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;


&lt;p&gt;At least now you test will fail in a way where you will understand what happened.&lt;/p&gt;

&lt;h2&gt;Lessons for writing JS modules.&lt;/h2&gt;

&lt;p&gt;Most JS code you want to write is bigger than this example. It is also usually hidden within a module. This implies that you should take note of the &lt;code&gt;done&lt;/code&gt;
function early when developing the module and make sure it is present and also that it is injectable. Here's one way:&lt;/p&gt;

&lt;div&gt;&lt;figure role=code&gt;&lt;figcaption&gt;&lt;span&gt;kraken.js &lt;/span&gt;&lt;/figcaption&gt;
 &lt;div class=&quot;highlight&quot;&gt;&lt;table cellpadding=&quot;0&quot; cellspacing=&quot;0&quot;&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class='line'&gt;1&lt;/span&gt;
&lt;span class='line'&gt;2&lt;/span&gt;
&lt;span class='line'&gt;3&lt;/span&gt;
&lt;span class='line'&gt;4&lt;/span&gt;
&lt;span class='line'&gt;5&lt;/span&gt;
&lt;span class='line'&gt;6&lt;/span&gt;
&lt;span class='line'&gt;7&lt;/span&gt;
&lt;span class='line'&gt;8&lt;/span&gt;
&lt;span class='line'&gt;9&lt;/span&gt;
&lt;span class='line'&gt;10&lt;/span&gt;
&lt;span class='line'&gt;11&lt;/span&gt;
&lt;span class='line'&gt;12&lt;/span&gt;
&lt;span class='line'&gt;13&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code' width='100%'&gt;&lt;pre&gt;&lt;code class='js'&gt;&lt;div class='line'&gt;    &lt;span class=&quot;nb&quot;&gt;window&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;kraken&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;done&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;        &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;done&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;done&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;
&lt;/div&gt;&lt;div class='line'&gt;        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;            &lt;span class=&quot;nx&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;                &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;post&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;success&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;            &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;            &lt;span class=&quot;nx&quot;&gt;success&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;arg2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;                &lt;span class=&quot;nx&quot;&gt;done&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;            &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;        &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;


&lt;p&gt;Ok, but what if your interactions contain multiple async callbacks?&lt;/p&gt;

&lt;p&gt;Unittest purists will tell you that you are testing too much, which is true, but sometimes you have a complex setup with more than one callback firing that you want to test. For this I use a countdownLatch:&lt;/p&gt;

&lt;div&gt;&lt;figure role=code&gt;&lt;figcaption&gt;&lt;span&gt;someTestCode.js &lt;/span&gt;&lt;/figcaption&gt;
 &lt;div class=&quot;highlight&quot;&gt;&lt;table cellpadding=&quot;0&quot; cellspacing=&quot;0&quot;&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class='line'&gt;1&lt;/span&gt;
&lt;span class='line'&gt;2&lt;/span&gt;
&lt;span class='line'&gt;3&lt;/span&gt;
&lt;span class='line'&gt;4&lt;/span&gt;
&lt;span class='line'&gt;5&lt;/span&gt;
&lt;span class='line'&gt;6&lt;/span&gt;
&lt;span class='line'&gt;7&lt;/span&gt;
&lt;span class='line'&gt;8&lt;/span&gt;
&lt;span class='line'&gt;9&lt;/span&gt;
&lt;span class='line'&gt;10&lt;/span&gt;
&lt;span class='line'&gt;11&lt;/span&gt;
&lt;span class='line'&gt;12&lt;/span&gt;
&lt;span class='line'&gt;13&lt;/span&gt;
&lt;span class='line'&gt;14&lt;/span&gt;
&lt;span class='line'&gt;15&lt;/span&gt;
&lt;span class='line'&gt;16&lt;/span&gt;
&lt;span class='line'&gt;17&lt;/span&gt;
&lt;span class='line'&gt;18&lt;/span&gt;
&lt;span class='line'&gt;19&lt;/span&gt;
&lt;span class='line'&gt;20&lt;/span&gt;
&lt;span class='line'&gt;21&lt;/span&gt;
&lt;span class='line'&gt;22&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code' width='100%'&gt;&lt;pre&gt;&lt;code class='js'&gt;&lt;div class='line'&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;countdownLatch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;num&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;callback&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;        &lt;span class=&quot;nx&quot;&gt;num&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;num&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;        &lt;span class=&quot;nx&quot;&gt;callback&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;callback&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;        &lt;span class=&quot;nx&quot;&gt;done&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;msg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;            &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;num&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;            &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Done&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;num&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;nx&quot;&gt;msg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;num&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{;&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;                &lt;span class=&quot;nx&quot;&gt;callback&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;    &lt;span class=&quot;s2&quot;&gt;&amp;quot;test http request&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;done&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;        &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;latch&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;countdownLatch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;                &lt;span class=&quot;nx&quot;&gt;assert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;equals&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;#sum&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;val&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;                &lt;span class=&quot;nx&quot;&gt;done&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;                &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;        &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;obj&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;window&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;kraken&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;latch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;        &lt;span class=&quot;nx&quot;&gt;obj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;1&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;        &lt;span class=&quot;nx&quot;&gt;obj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;2&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;


&lt;p&gt;The latch above also lets me pass a messate to the done call so I can log progress, something that can be usefull for debugging.&lt;/p&gt;

&lt;h2&gt;Summary&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;When you write new JS modules, add support for a done callback for testing.&lt;/li&gt;
&lt;li&gt;Remember to wire up errorhandlers for all requests.&lt;/li&gt;
&lt;li&gt;You can use the done function for debugging as well.&lt;/li&gt;
&lt;/ol&gt;

</content>
  </entry>
  
  <entry>
    <title>Injecting HTML With BusterJS</title>
    <link href="http://www.kraken.no/blog/2012/03/23/injecting-html-with-busterjs/"/>
    <updated>2012-03-23T08:32:00+01:00</updated>
    <id>http://www.kraken.no/blog/2012/03/23/injecting-html-with-busterjs</id>
    <content type="html">&lt;p&gt;I've been working with the very promising new JS testframework named &lt;a href=&quot;http://busterjs.org&quot;&gt;buster.js&lt;/a&gt; which seems to be shaping up to become the next great
thing in JS testing.&lt;/p&gt;

&lt;p&gt;One of the reasons for this I thing is because they try to give you the whole stack, not just a toy for testing your latest implementation of the fibonaci
series.&lt;/p&gt;

&lt;p&gt;Loading HTML into the DOM of the test is still missing and someting that is quite usefull. JS code does not live in a vacum. They will fix it, &lt;a href=&quot;https://github.com/busterjs/buster/issues/89&quot;&gt;see
this issue&lt;/a&gt;,but until that happens - here's how you can do it.&lt;/p&gt;

&lt;p&gt;First setup your config file:&lt;/p&gt;

&lt;div&gt;&lt;figure role=code&gt;&lt;figcaption&gt;&lt;span&gt;buster.js &lt;/span&gt;&lt;/figcaption&gt;
 &lt;div class=&quot;highlight&quot;&gt;&lt;table cellpadding=&quot;0&quot; cellspacing=&quot;0&quot;&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class='line'&gt;1&lt;/span&gt;
&lt;span class='line'&gt;2&lt;/span&gt;
&lt;span class='line'&gt;3&lt;/span&gt;
&lt;span class='line'&gt;4&lt;/span&gt;
&lt;span class='line'&gt;5&lt;/span&gt;
&lt;span class='line'&gt;6&lt;/span&gt;
&lt;span class='line'&gt;7&lt;/span&gt;
&lt;span class='line'&gt;8&lt;/span&gt;
&lt;span class='line'&gt;9&lt;/span&gt;
&lt;span class='line'&gt;10&lt;/span&gt;
&lt;span class='line'&gt;11&lt;/span&gt;
&lt;span class='line'&gt;12&lt;/span&gt;
&lt;span class='line'&gt;13&lt;/span&gt;
&lt;span class='line'&gt;14&lt;/span&gt;
&lt;span class='line'&gt;15&lt;/span&gt;
&lt;span class='line'&gt;16&lt;/span&gt;
&lt;span class='line'&gt;17&lt;/span&gt;
&lt;span class='line'&gt;18&lt;/span&gt;
&lt;span class='line'&gt;19&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code' width='100%'&gt;&lt;pre&gt;&lt;code class='js'&gt;&lt;div class='line'&gt;    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;config&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;module&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;exports&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;fs&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;
&lt;/div&gt;&lt;div class='line'&gt;    &lt;span class=&quot;nx&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;someTest&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;        &lt;span class=&quot;nx&quot;&gt;rootPath&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;.&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;        &lt;span class=&quot;nx&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;browser&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// or &amp;quot;node&amp;quot;&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;        &lt;span class=&quot;nx&quot;&gt;libs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;         &lt;span class=&quot;s2&quot;&gt;&amp;quot;src/js/mootools-core.js&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;        &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;        &lt;span class=&quot;nx&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;            &lt;span class=&quot;s2&quot;&gt;&amp;quot;src/js/my.class.js&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;        &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;        &lt;span class=&quot;nx&quot;&gt;tests&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;            &lt;span class=&quot;s2&quot;&gt;&amp;quot;tests/js/test.my.class.js&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;        &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;        &lt;span class=&quot;nx&quot;&gt;resources&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;            &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;/menu&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;readFileSync&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;src/tests/fixtures/menu.html&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)},&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;        &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;    &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;


&lt;p&gt;In this example I use Mootools, but that is because I'm using mootools on the project I'm working on right now. Pick your poison.&lt;/p&gt;

&lt;p&gt;In the test file I load the html fragment and inject it into the dom.&lt;/p&gt;

&lt;div&gt;&lt;figure role=code&gt;&lt;figcaption&gt;&lt;span&gt;buster.js &lt;/span&gt;&lt;/figcaption&gt;
 &lt;div class=&quot;highlight&quot;&gt;&lt;table cellpadding=&quot;0&quot; cellspacing=&quot;0&quot;&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class='line'&gt;1&lt;/span&gt;
&lt;span class='line'&gt;2&lt;/span&gt;
&lt;span class='line'&gt;3&lt;/span&gt;
&lt;span class='line'&gt;4&lt;/span&gt;
&lt;span class='line'&gt;5&lt;/span&gt;
&lt;span class='line'&gt;6&lt;/span&gt;
&lt;span class='line'&gt;7&lt;/span&gt;
&lt;span class='line'&gt;8&lt;/span&gt;
&lt;span class='line'&gt;9&lt;/span&gt;
&lt;span class='line'&gt;10&lt;/span&gt;
&lt;span class='line'&gt;11&lt;/span&gt;
&lt;span class='line'&gt;12&lt;/span&gt;
&lt;span class='line'&gt;13&lt;/span&gt;
&lt;span class='line'&gt;14&lt;/span&gt;
&lt;span class='line'&gt;15&lt;/span&gt;
&lt;span class='line'&gt;16&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code' width='100%'&gt;&lt;pre&gt;&lt;code class='js'&gt;&lt;div class='line'&gt;    &lt;span class=&quot;nx&quot;&gt;buster&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;testCase&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Test menu handling&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;        &lt;span class=&quot;nx&quot;&gt;setUp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;            &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;HTML&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;                &lt;span class=&quot;nx&quot;&gt;async&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;                &lt;span class=&quot;nx&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;buster&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;contextPath&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;/menu&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;                &lt;span class=&quot;nx&quot;&gt;onSuccess&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;responseTree&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;responseElements&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;responseHTML&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;responseJavaScript&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;                    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;body&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Element&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;                    &lt;span class=&quot;nx&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;adopt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;responseElements&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;                &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;                &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;            &lt;span class=&quot;nx&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;        &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;        &lt;span class=&quot;s2&quot;&gt;&amp;quot;Test something with dom&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;
&lt;/div&gt;&lt;div class='line'&gt;        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;


&lt;p&gt;Note: With this method, the menu.html file should not be a complete html page, but just an html fragment that you can load into the dom.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Howto Export From Mysql to Hadoop Using Sqoop</title>
    <link href="http://www.kraken.no/blog/2012/02/07/howto-export-from-mysql-to-hadoop-using-sqoop/"/>
    <updated>2012-02-07T10:18:00+01:00</updated>
    <id>http://www.kraken.no/blog/2012/02/07/howto-export-from-mysql-to-hadoop-using-sqoop</id>
    <content type="html">&lt;p&gt;This is a quick howto for working with Apache Sqoop.&lt;/p&gt;

&lt;p&gt;I used Clouderas packages of Hadoop and Sqoop for this work. Both the maven packages and the debs.&lt;/p&gt;

&lt;h3&gt;A basic Sqoop import - MR workflow consist of:&lt;/h3&gt;

&lt;h4&gt;1. Dumping the table info HDFS as sequencefiles:&lt;/h4&gt;

&lt;pre&gt;&lt;code&gt;sqoop import --options-file ./sqoop-options.txt  --as-sequencefile --columns contentobject_id,item --table someTable  --class-name=com.example.MyClass --target-dir=/user/tarjei/db-sqoop/
&lt;/code&gt;&lt;/pre&gt;

&lt;h4&gt;2. Generate the class that is used in the sequecefile:&lt;/h4&gt;

&lt;pre&gt;&lt;code&gt;sqoop codegen  --options-file ./sqoop-options.txt --outdir src/main/java/ --class-name com.example.MyClass --table someTable
&lt;/code&gt;&lt;/pre&gt;

&lt;h1&gt;Create a Mapper that works with the data:&lt;/h1&gt;

&lt;p&gt;The mapper will have the format, LongWritable,Myclass:&lt;/p&gt;

&lt;div&gt;&lt;figure role=code&gt;&lt;figcaption&gt;&lt;span&gt;SomeMapper.java &lt;/span&gt;&lt;/figcaption&gt;
 &lt;div class=&quot;highlight&quot;&gt;&lt;table cellpadding=&quot;0&quot; cellspacing=&quot;0&quot;&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class='line'&gt;1&lt;/span&gt;
&lt;span class='line'&gt;2&lt;/span&gt;
&lt;span class='line'&gt;3&lt;/span&gt;
&lt;span class='line'&gt;4&lt;/span&gt;
&lt;span class='line'&gt;5&lt;/span&gt;
&lt;span class='line'&gt;6&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code' width='100%'&gt;&lt;pre&gt;&lt;code class='java'&gt;&lt;div class='line'&gt;    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SomeMapper&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Mapper&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;LongWritable&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MyClass&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Text&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Text&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;        &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;LongWritable&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MyClass&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Context&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;throws&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IOException&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;InterruptedException&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;            &lt;span class=&quot;n&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;someValue&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getValue&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;            &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;


&lt;p&gt;Thats it. The parts I missed in the documentation were the part that Sqoop generates a class for you to use when reading the dump files.&lt;/p&gt;

&lt;h2&gt;Links&lt;/h2&gt;

&lt;p&gt;The &lt;a href=&quot;http://archive.cloudera.com/cdh/3/sqoop/SqoopUserGuide.html&quot;&gt;Sqoop user guide&lt;/a&gt; is very usefull. Also the &lt;a href=&quot;http://incubator.apache.org/projects/sqoop.html&quot;&gt;Apache Sqoop
page&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Handy Symfony2 aliases</title>
    <link href="http://www.kraken.no/blog/2012/01/12/handy-symfony2-aliases/"/>
    <updated>2012-01-12T12:47:00+01:00</updated>
    <id>http://www.kraken.no/blog/2012/01/12/handy-symfony2-aliases</id>
    <content type="html">&lt;p&gt;While working with Symfony2 I've ended up defining a few aliases that might be of use for you. They make it a bit faster to do the things you do all the
time, i.e. test and clear caches.&lt;/p&gt;

&lt;p&gt;Here they are:&lt;/p&gt;

&lt;div&gt;&lt;figure role=code&gt;&lt;figcaption&gt;&lt;span&gt;.aliases &lt;/span&gt;&lt;/figcaption&gt;
&lt;pre&gt;&lt;code&gt;PROJECT_DIR=`pwd`
alias cc=&quot;$PROJECT_DIR/app/console cache:clear&quot;
alias ccp=&quot;$PROJECT_DIR/app/console cache:clear --env=prod&quot;
alias cct=&quot;$PROJECT_DIR/app/console cache:clear --env=test&quot;
alias cca=&quot;cc --env=prod ; cc --env=test&quot;
alias itest=&quot;phpunit -c /$PROJECT_DIRapp/phpunit.xml.ci&quot;
alias con=&quot;$PROJECT_DIR/app/console&quot;
alias routes=&quot;$PROJECT_DIR/app/console router:debug&quot;
alias log='tail -n 100 $PROJECT_DIR/app/logs/dev.log'
alias plog='tail -n 100 $PROJECT_DIR/app/logs/prod.log'
alias tlog='tail -n 100 $PROJECT_DIR/app/logs/test.log'
alias clear_prod_cache='frigg sudo -u www-data /webroot/vhosts/beta.scanmine.com/nywly/app/console cache:clear --env=demo'
#alias test=&quot;phpunit -c $PROJECT_DIR/app/phpunit.xml&quot;
function test {
    
if [ $# -gt 0 ]
then
    echo &quot;Filtering on: $1&quot;
    phpunit -c $PROJECT_DIR/app/phpunit.xml --debug --filter $1
else
phpunit -c $PROJECT_DIR/app/phpunit.xml --verbose 
fi
}
# setup project perms:
# sudo setfacl -R -m u:www-data:rwx -m u:tarjei:rwx app/cache app/logs&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;


&lt;p&gt;Just a quick rundown:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;con&lt;/em&gt; is an alias to the app/console object.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;cc&lt;/em&gt; clears the cache&lt;/li&gt;
&lt;li&gt;&lt;em&gt;cca&lt;/em&gt; clears all the caches&lt;/li&gt;
&lt;li&gt;&lt;em&gt;routes&lt;/em&gt; lis an alias to the console router:debug command.&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;&lt;em&gt;test&lt;/em&gt; is the command I use the most&lt;/h2&gt;

&lt;p&gt;It's implemented as a function and the usage is as follows:&lt;/p&gt;

&lt;p&gt;Run all tests&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;% test
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Run the tests that hit by a filter&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;% test MyController::testIndex
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Just remember that the aliases override the test function in bash so don't reuse the same shell!&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Using PEAR packages in Symfony2 with Pyrus</title>
    <link href="http://www.kraken.no/blog/2011/08/10/using-symfony2-with-pear/"/>
    <updated>2011-08-10T10:42:00+02:00</updated>
    <id>http://www.kraken.no/blog/2011/08/10/using-symfony2-with-pear</id>
    <content type="html">&lt;p&gt;It does not show up when you google for it, but there are ways to handle PEAR packages in Symfony2.&lt;/p&gt;

&lt;p&gt;I Found two bundles on symfony2bundles.org:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/tumf/PearBundle/&quot;&gt;Pearbundle&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/naderman/PyrusBundle&quot;&gt;PyrusBundle&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;None of them worked perfectly. I ended up updating the PyrusBundle to something that works fairly well.&lt;/p&gt;

&lt;p&gt;You can find the new version up at &lt;a href=&quot;https://github.com/tarjei/PyrusBundle&quot;&gt;github/tarjei/PyrusBundle&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I added a README to it as well so usage should be fairly simple.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Converted to Octopress</title>
    <link href="http://www.kraken.no/blog/2011/08/09/converted-to-octopress/"/>
    <updated>2011-08-09T08:47:00+02:00</updated>
    <id>http://www.kraken.no/blog/2011/08/09/converted-to-octopress</id>
    <content type="html">&lt;p&gt;I have converted this blog from using Drupal to using Octopress - I didn't need a CMS to handle it. Being a developer, it is easier to handle everything using git and vim.&lt;/p&gt;

&lt;p&gt;When I get the time, I'll try to post the conversion scripts. A problem now is that a lot of codelistings do not look good at all. I hope to fix them soon.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Using Pear Packages With Symfony2</title>
    <link href="http://www.kraken.no/blog/2011/08/08/using-pear-packages-with-symfony2/"/>
    <updated>2011-08-08T19:58:00+02:00</updated>
    <id>http://www.kraken.no/blog/2011/08/08/using-pear-packages-with-symfony2</id>
    <content type="html">&lt;p&gt;&lt;strong&gt;UPDATE: I improved the metod. &lt;a href=&quot;http://www.kraken.no/blog/2011/08/10/using-symfony2-with-pear/&quot;&gt;See using Symfony2 with PEAR using Pyrus&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I've just started using Symfony2 (http://www.symfony.com) and one of the first problems I stumbled across was how to integrate Pear packages into it.&lt;/p&gt;

&lt;p&gt;The way I ended up doing this was to create a php directory in my verdors directory and install the packages into this directory using pyrus.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;php pyrus.phar mypear ~/SymfonyProject/vendors
php pyrus.phar install pear/HTTP_Request2-2.0.0RC1
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Then I added the directories to &lt;code&gt;app/autoload.php&lt;/code&gt;:&lt;/p&gt;

&lt;div&gt;&lt;figure role=code&gt;&lt;figcaption&gt;&lt;span&gt;app/autoload.php &lt;/span&gt;&lt;/figcaption&gt;
 &lt;div class=&quot;highlight&quot;&gt;&lt;table cellpadding=&quot;0&quot; cellspacing=&quot;0&quot;&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class='line'&gt;1&lt;/span&gt;
&lt;span class='line'&gt;2&lt;/span&gt;
&lt;span class='line'&gt;3&lt;/span&gt;
&lt;span class='line'&gt;4&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code' width='100%'&gt;&lt;pre&gt;&lt;code class='php'&gt;&lt;div class='line'&gt;&lt;span class=&quot;x&quot;&gt;    $loader-&amp;gt;registerPrefixes(array(&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;&lt;span class=&quot;x&quot;&gt;       &amp;#39;Net_&amp;#39;             =&amp;gt; __DIR__.&amp;#39;/../vendor/php&amp;#39;,&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;&lt;span class=&quot;x&quot;&gt;       &amp;#39;HTTP_&amp;#39;             =&amp;gt; __DIR__.&amp;#39;/../vendor/php&amp;#39;,&lt;/span&gt;
&lt;/div&gt;&lt;div class='line'&gt;&lt;span class=&quot;x&quot;&gt;    ));&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;


&lt;p&gt;This isn't perfect as it clutters up the vendors directory with a lot of unneeded directories that follow a Pear installation - it would have been nicer if I could just download a cuple of phar files - so it is probably a good idea to have a separare pear directory under vendors to handle this.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>The annotation Template in method SomeClass\SomeBundle\Controller\RestController::addAction() was never imported.</title>
    <link href="http://www.kraken.no/blog/2011/08/05/The-annotation--Template-in-method-SomeClass-SomeBundle-Controller-RestController--addAction---was-never-imported-/"/>
    <updated>2011-08-05T10:48:00+02:00</updated>
    <id>http://www.kraken.no/blog/2011/08/05/The-annotation--Template-in-method-SomeClass-SomeBundle-Controller-RestController--addAction---was-never-imported-</id>
    <content type="html">&lt;p&gt;When you get this error it is because you need to import the annotation classes into the file you are using them in.&lt;/p&gt;

&lt;p&gt;For @Route and @Template this is:&lt;br/&gt;
&lt;/br/&gt;&lt;/p&gt;

&lt;pre&gt;&lt;pre class=&quot;brush:php&quot;&gt;use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;&lt;/pre&gt;&lt;/pre&gt;

</content>
  </entry>
  
  <entry>
    <title>Running large batches with Hibernate</title>
    <link href="http://www.kraken.no/blog/2010/06/25/Running-large-batches-with-Hibernate/"/>
    <updated>2010-06-25T08:36:00+02:00</updated>
    <id>http://www.kraken.no/blog/2010/06/25/Running-large-batches-with-Hibernate</id>
    <content type="html">&lt;p&gt;This week I've been fighting Hibernate again. That is, last week I should have implemented a quick job to export 30 million entities from a DB and to a new interchange format.&lt;/p&gt;

&lt;p&gt;Instead the job blew up due to memoryproblems. Below you'll find teh solution.&lt;/p&gt;

&lt;!--break--&gt;




&lt;!--break--&gt;


&lt;p&gt;First we thought this was due to a Hibernate bug, so we upgraded Hibernate - and spent a day fixing the consequences (thank god, we had tests). This didn't help.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The problem was that the Hibernate querycache didn't evict anything.&lt;/strong&gt;. The heap was filling up with org.hibernate.engine.query.QueryPlanCache objects.&lt;/p&gt;

&lt;p&gt;Now we did what we should have done in the first place. Google'd the terms&quot;hibernate batch jobs&quot;. We got these gems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://opensource.atlassian.com/projects/hibernate/browse/HHH-2431&quot;&gt;Hibernate queries should be parameterized or you'll have a problem.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://relation.to/Bloggers/BatchProcessingInHibernate&quot;&gt;Batch processing in Hibernate&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;The changes we did in the end were:&lt;/p&gt;

&lt;h3&gt;1. Remove the use of Spring autowired DAOs to ensure control over queries.&lt;/h3&gt;

&lt;p&gt;This is important both to ensure that the number of connections don't spiral out of control AND to clear the Hibernate entity caches.&lt;/p&gt;

&lt;p&gt;If you are using a Spring SessonFactory, you can get the session using the SessionFactoryUtils:&lt;/p&gt;

&lt;pre&gt;&lt;pre class=&quot;brush:java&quot;&gt;Session s = SessionFactoryUtils.getSession(sessionFactory, true);try {doExport(s);} finally {s.flush();s.clear();SessionFactoryUtils.closeSession(s);}&lt;/pre&gt;&lt;/pre&gt;


&lt;p&gt;The s.flush() and s.clear() are essential. If not, Hibernate will cache the objects it has created for you forever.&lt;/p&gt;

&lt;h3&gt;2. Make sure you use parameterized queries.&lt;/h3&gt;

&lt;p&gt;The point here is that this query:&lt;br/&gt;
&lt;/br/&gt;&lt;/p&gt;

&lt;pre&gt;&lt;pre class=&quot;brush:java&quot;&gt;Query query = s.createQuery(&quot;SELECT C.* from Blog where C.id=&quot;+ id);&lt;/pre&gt;&lt;/pre&gt;


&lt;p&gt;Will be cached separately for EACH time it is called. If you call it 100 000 times, the QueryPlanCache will contain 100 000 entries. The solution is this:&lt;/p&gt;

&lt;pre&gt;&lt;pre class=&quot;brush:java&quot;&gt;Query query = s.createQuery(&quot;SELECT C.* from Blog where C.id=:id&quot;);query.setInteger(&quot;id&quot;, id);&lt;/pre&gt;&lt;/pre&gt;


&lt;p&gt;DUH!&lt;/p&gt;

&lt;h3&gt;3. Love thy jmap&lt;/h3&gt;

&lt;p&gt;Use Eclipse to analyze jmap heapdumps. It's easy and rewarding. Never try to solve a problem you do not know you have.&lt;/p&gt;

&lt;h3&gt;4.Bonus camel tip&lt;/h3&gt;

&lt;p&gt;This does not do what you thought it would:&lt;/p&gt;

&lt;pre&gt;&lt;pre class=&quot;brush:java&quot;&gt;//.. in some camel route ....to(&quot;seda:myQueue&quot;).to(&quot;file://...&quot;)&lt;/pre&gt;&lt;/pre&gt;


&lt;p&gt;With this you are essentially sending the message two places. I should have known :)&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Groovy Camel MainSupport</title>
    <link href="http://www.kraken.no/blog/2010/06/17/Groovy-Camel-MainSupport/"/>
    <updated>2010-06-17T10:48:00+02:00</updated>
    <id>http://www.kraken.no/blog/2010/06/17/Groovy-Camel-MainSupport</id>
    <content type="html">&lt;p&gt;I've been using Apache Camel more and more lately and one thing that has irritated me is creating a big project with maven, multiple classes etc for just a simple task. I thought Scala would be my savior, instead Groovy is.&lt;/p&gt;

&lt;p&gt;This post shows how to get groovy scripts to block when stating up.&lt;/p&gt;

&lt;!--break--&gt;




&lt;!--break--&gt;


&lt;p&gt;The examples I've seen on the web says that all you need is:&lt;/p&gt;

&lt;pre&gt;&lt;pre class=&quot;brush:java&quot;&gt;def camelCtx = new  DefaultCamelContext()camelCtx.addRoutes(new SampleRoute())camelCtx.start()&lt;/pre&gt;&lt;/pre&gt;


&lt;p&gt;(from&lt;a href=&quot;http://www.andrejkoelewijn.com/wp/2009/03/11/groovy-example-activemq-broker-and-apache-camel/&quot;&gt;Groovy example: ActiveMQ broker and Apache Camel&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Somehow this didn't work for me, and according to the very helpful guys on #camel it shouldn't either.&lt;/p&gt;

&lt;p&gt;What happens is that the start() method returns to the calling thread while starting up Camel in the background. The main thread then exits - thus shutting down everything.&lt;/p&gt;

&lt;p&gt;I still do not understand how the examples are supposed to work - but I can hope to learn some day :)&lt;/p&gt;

&lt;p&gt;According to Claus Ibsen on #camel (and one of the main commiters to the project), the&lt;a href=&quot;http://stackoverflow.com/questions/1846791/camelcontext-start-doesnt-block&quot;&gt;correct&lt;/a&gt;way to get this to work is to implement a subclass of the abstract class MainSupport that creates the CamelContext and starts it.&lt;/p&gt;

&lt;p&gt;There is one implementation of MainSupport in camel-spring that supports loading Spring contexts etc when starting a Camel route, but I wanted something much simpler that would work with as little fuss as possible.&lt;/p&gt;

&lt;p&gt;Here's what I came up with:&lt;/p&gt;

&lt;pre&gt;&lt;pre class=&quot;brush:java&quot;&gt;/*** This is a simple implementation of MainsSupport to handle running simple scripts* as camel services.** Note that the implementation only does one context.* @author Tarjei Huse,&lt;a href=&quot;mailto:tarjei@scanmine.com&quot;&gt;tarjei@scanmine.com&lt;/a&gt;**/public class GroovyMain extends MainSupport {CamelContext context = new DefaultCamelContext();public GroovyMain() {this.addChildService contextthis.camelContexts.add context}protected  ProducerTemplate findOrCreateCamelTemplate() {return context.createProducerTemplate()}@Overrideprotected void doStart() throws Exception {super.doStart();//context.addRoutes this.getRouteBuilders()postProcessContext(); // does add routes}protected  Map&amp;lt;String, CamelContext&amp;gt; getCamelContextMap() {return ['main': context]}/*** Add a component to the context* @param name* @param component*/public void addComponent(String name, Component component ) {this.context.addComponent(name, component);}public CamelContext getCamelContext() {return context;}protected ModelFileGenerator createModelFileGenerator() throws JAXBException {return null;}/*** Enables the hangup support. Gracefully stops by calling stop() on a* Hangup signal.*/public void enableHangupSupport() {HangupInterceptor interceptor = new HangupInterceptor(this);Runtime.getRuntime().addShutdownHook(interceptor);}}/*** A class for intercepting the hang up signal* and do a graceful shutdown of the Camel.* Taken from the camel-spring implementation of MainSupport.*/class HangupInterceptor extends Thread {MainSupport mainInstance;public HangupInterceptor(MainSupport main) {mainInstance = main;}@Overridepublic void run() {try {mainInstance.stop();} catch (Exception ex) {Logger.getLogger(&quot;Shutdown handler&quot;).warn(ex);}}}&lt;/pre&gt;&lt;/pre&gt;


&lt;p&gt;The implementation only handles one simple camel context. It also adds support for adding components to the context.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Munin FAQ Entry: Why aren't my graphs updating</title>
    <link href="http://www.kraken.no/blog/2010/03/28/Munin-FAQ-Entry--Why-aren-t-my-graphs-updating/"/>
    <updated>2010-03-28T21:46:00+02:00</updated>
    <id>http://www.kraken.no/blog/2010/03/28/Munin-FAQ-Entry--Why-aren-t-my-graphs-updating</id>
    <content type="html">&lt;p&gt;I just upgraded to Munin 1.4.3 on Centos 5.4 (from 1.3.x I think) the other day and after some time noticed that my Graphs were not updating.&lt;/p&gt;

&lt;!--break--&gt;




&lt;!--break--&gt;


&lt;p&gt;After a long bout of debugging and cursing Munin's inability to provide any indications of what was wrong, I suddenly understood my error: I was deeplinking into pages that were not updated anymore because the Munin upgrade changed the way generated files are structured.&lt;/p&gt;

&lt;p&gt;The following is the quick fix:&lt;/p&gt;

&lt;pre&gt;&lt;pre class=&quot;brush:bash&quot;&gt;su -s /bin/bash muninfind . -name&quot;*.html&quot;-ls -exec rm -f {} \;/usr/bin/munin-cron&lt;/pre&gt;&lt;/pre&gt;


&lt;p&gt;I.e delete all html files generated by munin and ask it to generate them over again _as the munin user_.&lt;/p&gt;

&lt;p&gt;I sure hope this helps someone!&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Loading different fixtures based on environment</title>
    <link href="http://www.kraken.no/blog/2009/12/16/Loading-different-fixtures-based-on-environment/"/>
    <updated>2009-12-16T10:51:00+01:00</updated>
    <id>http://www.kraken.no/blog/2009/12/16/Loading-different-fixtures-based-on-environment</id>
    <content type="html">&lt;p&gt;A few days ago someone asked on #symfony if it is possible to make symfony load fixtures from different places depending on the environment.&lt;/p&gt;

&lt;p&gt;To do this, you have to define your own task. Here's one I just created. As a bonus, this task also loads sql files from a separate sql directory.&lt;/p&gt;

&lt;p&gt;Here's the task:&lt;/p&gt;

&lt;pre&gt;&lt;pre class=&quot;brush:php&quot;&gt;&amp;lt;?php/*** This task does almost the same as doctrine:data-load, but it also* loads the sql from the files in the data/sqlextra directory And takes into account the current environment.*** Use instead of doctrine:data-load*/class nnv_load_dataTask extends sfBaseTask{protected function configure(){$this-&amp;gt;addOptions(array(new sfCommandOption('application', null, sfCommandOption::PARAMETER_REQUIRED,'The application name'),new sfCommandOption('env', null, sfCommandOption::PARAMETER_REQUIRED,'The environment','dev'),new sfCommandOption('connection', null, sfCommandOption::PARAMETER_REQUIRED,'The connection name','doctrine'),// add your own options here));$this-&amp;gt;namespace        ='data';$this-&amp;gt;name             ='load-data';$this-&amp;gt;briefDescription ='Load fixtures and sql based on environment';$this-&amp;gt;detailedDescription =&amp;lt;&amp;lt;&amp;lt;EOFThis [nnv_load_data|INFO] task does almost the same as doctrine:data-load, but it alsoloads the sql from the files in the data/sqlextra/$env directory and loads fixtures from the data/fixtures/$env dir.Use instead of doctrine:data-loadCall it with:[php symfony load_extra_sql|INFO]EOF;}protected function execute($arguments = array(), $options = array()){// initialize the database connection$databaseManager = new sfDatabaseManager($this-&amp;gt;configuration);$connection = $databaseManager-&amp;gt;getDatabase($options['connection'] ? $options['connection'] : null)-&amp;gt;getConnection();Doctrine::loadData(sfConfig::get('sf_root_dir').'/data/fixtures/'. $env);$env = $options['env'];$files = glob(sfConfig::get('sf_root_dir').&quot;/data/sqlextra/$env/*.sql&quot;);foreach ($files as $file) {print&quot;Loading&quot;. $file .&quot;...&quot;;$sql = file_get_contents($file) ;try {$n = $connection-&amp;gt;exec($sql);print&quot;ok: $n\n&quot;;} catch (Exception $e) {print&quot;Error loading statement: \n$stmt\n:&quot;. $e-&amp;gt;getMessage();}}}}&lt;/pre&gt;&lt;/pre&gt;

</content>
  </entry>
  
  <entry>
    <title>Testing symfony with sqlite::memory:</title>
    <link href="http://www.kraken.no/blog/2009/12/03/Testing-symfony-with-sqlite--memory-/"/>
    <updated>2009-12-03T12:41:00+01:00</updated>
    <id>http://www.kraken.no/blog/2009/12/03/Testing-symfony-with-sqlite--memory-</id>
    <content type="html">&lt;p&gt;One thing I love about Java is that there are a number of databases that you can load into memory and run functional tests against. This is also an option in PHP thanks to Sqlite.&lt;/p&gt;

&lt;!--break--&gt;




&lt;!--break--&gt;


&lt;p&gt;To do this in Symfony, you must configure the test db like this:&lt;/p&gt;

&lt;pre&gt;test:doctrine:param:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; dsn:&quot;sqlite::memory:&quot;&lt;/pre&gt;


&lt;p&gt; &lt;/p&gt;

&lt;p&gt;And setup the test to reload the db each time you call it:&lt;/p&gt;

&lt;pre class=&quot;brush:php&quot;&gt;&amp;lt;?php require_once dirname(__FILE__).'/../bootstrap/functional.php';$configuration = ProjectConfiguration::getApplicationConfiguration('admin','test', true);new sfDatabaseManager($configuration);Doctrine::createTablesFromModels(dirname(__FILE__).'/../../lib/model');Doctrine::loadData(sfConfig::get('sf_test_dir').'/fixtures');$t = new lime_test(2);&lt;/pre&gt;


&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I had some trouble loading fixtures where the ids could not be autogenerated. In the end I ended up defining a separate function for loading files like these. Here's the complete bootstrap file I've ended up with:&lt;/br/&gt;&lt;/p&gt;

&lt;pre class=&quot;brush:php&quot;&gt;&amp;lt;?php/** This file is part of the symfony package.* (c) Fabien Potencier&amp;lt;fabien.potencier@symfony-project.com&amp;gt;** For the full copyright and license information, please view the LICENSE* file that was distributed with this source code.*/$_test_dir = realpath(dirname(__FILE__).'/..');// configurationrequire_once dirname(__FILE__).'/../../config/ProjectConfiguration.class.php';$configuration = ProjectConfiguration::hasActive() ? ProjectConfiguration::getActive() : new ProjectConfiguration(realpath($_test_dir.'/..'));// autoloader$autoload = sfSimpleAutoload::getInstance(sfConfig::get('sf_cache_dir').'/project_autoload.cache');$autoload-&amp;gt;loadConfiguration(sfFinder::type('file')-&amp;gt;name('autoload.yml')-&amp;gt;in(array(sfConfig::get('sf_symfony_lib_dir').'/config/config',sfConfig::get('sf_config_dir'),)));$autoload-&amp;gt;register();// limeinclude $configuration-&amp;gt;getSymfonyLibDir().'/vendor/lime/lime.php';//$configuration = ProjectConfiguration::getApplicationConfiguration('admin','test', true);new sfDatabaseManager(ProjectConfiguration::getApplicationConfiguration('admin','test', true));Doctrine::createTablesFromModels(sfConfig::get('sf_root_dir').'/lib/model');Doctrine::loadData(sfConfig::get('sf_test_dir').'/fixtures');/*** Load testdata from an sqldump. This is used when running tests where the* id's are significant (i.e. fylker, kommuner and postnummer)* this function expects a connection to exist* @param $file string path to the file to load*/function loadSqlDump($file) {$sql = file_get_contents($file);if ($sql =='') throw new Exception(&quot;No sql found in $file&quot;);$conn2 = Doctrine_Manager::connection();$sql = trim($sql);$dbo = $conn2-&amp;gt;getDbh();// sqlite doesn't like multiple statements$statements = explode(&quot;;&quot;, $sql);foreach ($statements as $stmt) {try {$n = $dbo-&amp;gt;exec($stmt);} catch (Exception $e) {print&quot;Error loading statement: \n$stmt\n:&quot;. $e-&amp;gt;getMessage();}}}&lt;/pre&gt;


&lt;p&gt;Note that I place these DB tests in the unittest directory.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Converting from DBCP to C3P0 with Spring</title>
    <link href="http://www.kraken.no/blog/2009/11/16/Converting-from-DBCP-to-C3P0-with-Spring/"/>
    <updated>2009-11-16T11:42:00+01:00</updated>
    <id>http://www.kraken.no/blog/2009/11/16/Converting-from-DBCP-to-C3P0-with-Spring</id>
    <content type="html">&lt;p&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;Just a few quick notes on things to do when converting from using the DBCP connectionpool implementation to using C3P0&lt;/span&gt;&lt;br/&gt;
&lt;span style=&quot;font-weight: bold;&quot;&gt;&lt;br /&gt;&lt;/span&gt;You start by changing the &lt;span style=&quot;font-weight: bold;&quot;&gt;dataSource&lt;/span&gt;in your Spring config from:&lt;br/&gt;
&lt;span style=&quot;font-family: Courier New;&quot;&gt;&lt;bean id=&quot;dataSource&quot;&lt;/span&gt;&lt;br style=&quot;font-family: Courier New;&quot; /&gt;&lt;br/&gt;
&lt;span style=&quot;font-family: Courier New;&quot;&gt;        class=&quot;org.springframework.jdbc.datasource.DriverManagerDataSource&quot;&gt;&lt;/span&gt;&lt;br style=&quot;font-family: Courier New;&quot; /&gt;&lt;br/&gt;
&lt;span style=&quot;font-family: Courier New;&quot;&gt;       &lt;property name=&quot;url&quot; value=&quot;jdbc:mysql://localhost&quot; /&gt;&lt;/span&gt;&lt;br style=&quot;font-family: Courier New;&quot; /&gt;&lt;br/&gt;
&lt;span style=&quot;font-family: Courier New;&quot;&gt;       &lt;property name=&quot;username&quot; value=&quot;yourname&quot; /&gt;&lt;/span&gt;&lt;br style=&quot;font-family: Courier New;&quot; /&gt;&lt;br/&gt;
&lt;span style=&quot;font-family: Courier New;&quot;&gt;       &lt;property name=&quot;password&quot; value=&quot;yourpass&quot; /&gt;&lt;/span&gt;&lt;br style=&quot;font-family: Courier New;&quot; /&gt;&lt;br/&gt;
&lt;span style=&quot;font-family: Courier New;&quot;&gt;   &lt;/bean&gt;&lt;/span&gt;&lt;br/&gt;
To:&lt;br/&gt;
&lt;span style=&quot;font-family: Courier New;&quot;&gt; &lt;bean id=&quot;dataSource&quot;&lt;/span&gt;&lt;br style=&quot;font-family: Courier New;&quot; /&gt;&lt;br/&gt;
&lt;span style=&quot;font-family: Courier New;&quot;&gt;          class=&quot;com.mchange.v2.c3p0.ComboPooledDataSource&quot;&lt;/span&gt;&lt;br style=&quot;font-family: Courier New;&quot; /&gt;&lt;br/&gt;
&lt;span style=&quot;font-family: Courier New;&quot;&gt;          destroy-method=&quot;close&quot;&gt;&lt;/span&gt;&lt;br style=&quot;font-family: Courier New;&quot; /&gt;&lt;br/&gt;
&lt;span style=&quot;font-family: Courier New;&quot;&gt;       &lt;property name=&quot;driverClass&quot;&gt;&lt;value&gt;com.mysql.jdbc.Driver&lt;/value&gt;&lt;/property&gt;&lt;/span&gt;&lt;br style=&quot;font-family: Courier New;&quot; /&gt;&lt;br/&gt;
&lt;span style=&quot;font-family: Courier New;&quot;&gt;       &lt;property name=&quot;jdbcUrl&quot; value=&quot;jdbc:mysql://localhost&quot; /&gt;&lt;/span&gt;&lt;br style=&quot;font-family: Courier New;&quot; /&gt;&lt;br/&gt;
&lt;span style=&quot;font-family: Courier New;&quot;&gt;       &lt;property name=&quot;user&quot; value=&quot;yourusername&quot; /&gt;&lt;/span&gt;&lt;br style=&quot;font-family: Courier New;&quot; /&gt;&lt;br/&gt;
&lt;span style=&quot;font-family: Courier New;&quot;&gt;       &lt;property name=&quot;password&quot; value=&quot;yourpassword&quot; /&gt;&lt;/span&gt;&lt;br style=&quot;font-family: Courier New;&quot; /&gt;&lt;br/&gt;
&lt;span style=&quot;font-family: Courier New;&quot;&gt;       &lt;property name=&quot;initialPoolSize&quot;&gt;&lt;value&gt;3&lt;/value&gt;&lt;/property&gt;&lt;/span&gt;&lt;br style=&quot;font-family: Courier New;&quot; /&gt;&lt;br/&gt;
&lt;span style=&quot;font-family: Courier New;&quot;&gt;       &lt;property name=&quot;idleConnectionTestPeriod&quot;&gt;&lt;value&gt;200&lt;/value&gt;&lt;/property&gt;&lt;/span&gt;&lt;br style=&quot;font-family: Courier New;&quot; /&gt;&lt;br/&gt;
&lt;span style=&quot;font-family: Courier New;&quot;&gt;       &lt;property name=&quot;maxStatements&quot;&gt;&lt;value&gt;0&lt;/value&gt;&lt;/property&gt; &lt;/span&gt;&lt;br style=&quot;font-family: Courier New;&quot; /&gt;&lt;br/&gt;
&lt;span style=&quot;font-family: Courier New;&quot;&gt;       &lt;property name=&quot;numHelperThreads&quot;&gt;&lt;value&gt;3&lt;/value&gt;&lt;/property&gt;&lt;/span&gt;&lt;br style=&quot;font-family: Courier New;&quot; /&gt;&lt;br/&gt;
&lt;span style=&quot;font-family: Courier New;&quot;&gt;   &lt;/bean&gt;&lt;/span&gt;&lt;br/&gt;
&lt;span style=&quot;font-weight: bold;&quot;&gt;&lt;br /&gt;1. Name differences:&lt;br /&gt;&lt;/span&gt;There are some variable name differences in the xml above. Note:&lt;span style=&quot;font-weight: bold;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;url becomes jdbcUrl&lt;/li&gt;
&lt;li&gt;driverClassName becomes driverClass&lt;/li&gt;
&lt;li&gt;username becomes user&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;2. Some variables must be moved into the sessionFactory configuration&lt;/span&gt;&lt;br/&gt;
According to&lt;a href=&quot;http://jlebleu.free.fr/youpla/index.php?2006/12/07/1-spring-c3p0-hibernate&quot;target=&quot;_blank&quot;&gt;this&lt;/a&gt;you must configure some of the variables into the hibernate config. The article is from 2006 so this might not be true anymore.&lt;/p&gt;

&lt;p&gt;I add the properties like this so that they can be in the same config file:&lt;br/&gt;
&lt;span style=&quot;font-family: Courier New;&quot;&gt;    &lt;bean id=&quot;sessionFactory&quot; class=&quot;org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean&quot;&gt;&lt;/span&gt;&lt;br style=&quot;font-family: Courier New;&quot; /&gt;&lt;br/&gt;
&lt;span style=&quot;font-family: Courier New;&quot;&gt;       &lt;property name=&quot;dataSource&quot; ref=&quot;dataSource&quot;/&gt;&lt;/span&gt;&lt;br style=&quot;font-family: Courier New;&quot; /&gt;&lt;br/&gt;
&lt;span style=&quot;font-family: Courier New;&quot;&gt;       &lt;property name=&quot;hibernateProperties&quot;&gt;&lt;/span&gt;&lt;br style=&quot;font-family: Courier New;&quot; /&gt;&lt;br/&gt;
&lt;span style=&quot;font-family: Courier New;&quot;&gt;           &lt;props&gt;&lt;/span&gt;&lt;br style=&quot;font-family: Courier New;&quot; /&gt;&lt;br/&gt;
&lt;span style=&quot;font-family: Courier New;&quot;&gt;               &lt;prop key=&quot;hibernate.show_sql&quot;&gt;true&lt;/prop&gt;&lt;/span&gt;&lt;br style=&quot;font-family: Courier New;&quot; /&gt;&lt;br/&gt;
&lt;span style=&quot;font-family: Courier New;&quot;&gt;               &lt;prop key=&quot;hibernate.hbm2ddl.auto&quot;&gt;create&lt;/prop&gt;&lt;/span&gt;&lt;br style=&quot;font-family: Courier New;&quot; /&gt;&lt;br/&gt;
&lt;span style=&quot;font-family: Courier New;&quot;&gt;          &lt;prop key=&quot;hibernate.c3p0.acquire_increment&quot;&gt;1&lt;/prop&gt;&lt;/span&gt;&lt;br style=&quot;font-family: Courier New;&quot; /&gt;&lt;br/&gt;
&lt;span style=&quot;font-family: Courier New;&quot;&gt;           &lt;prop key=&quot;hibernate.c3p0.minPoolSize&quot;&gt;3&lt;/prop&gt;&lt;/span&gt;&lt;br style=&quot;font-family: Courier New;&quot; /&gt;&lt;br/&gt;
&lt;span style=&quot;font-family: Courier New;&quot;&gt;         &lt;prop key=&quot;hibernate.c3p0.maxPoolSize&quot;&gt;50&lt;/prop&gt;&lt;/span&gt;&lt;br style=&quot;font-family: Courier New;&quot; /&gt;&lt;br/&gt;
&lt;span style=&quot;font-family: Courier New;&quot;&gt;               &lt;prop key=&quot;hibernate.dialect&quot;&gt;org.hibernate.dialect.MySQLDialect&lt;/prop&gt;&lt;/span&gt;&lt;br style=&quot;font-family: Courier New;&quot; /&gt;&lt;br/&gt;
&lt;span style=&quot;font-family: Courier New;&quot;&gt;           &lt;/props&gt;&lt;/span&gt;&lt;br style=&quot;font-family: Courier New;&quot; /&gt;&lt;br/&gt;
&lt;span style=&quot;font-family: Courier New;&quot;&gt;       &lt;/property&gt;&lt;/span&gt;&lt;br style=&quot;font-family: Courier New;&quot; /&gt;&lt;br/&gt;
&lt;span style=&quot;font-family: Courier New;&quot;&gt;&lt;/bean&gt;&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Some other notes regarding connection pooling with the above:&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;If you use DBUnit, remember to close the connection so it gets returned to the pool after you have set up the db.&lt;/li&gt;
&lt;/ol&gt;


&lt;p&gt; &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;If you use SessionFactoryUtils to get a session, remember to do SessionFactoryUtils.releaseSession() when done.&lt;br/&gt;
&lt;span style=&quot;font-weight: bold;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;


&lt;div class=&quot;zemanta-pixie&quot;&gt;
  &lt;img src=&quot;http://img.zemanta.com/pixy.gif?x-id=62726cf8-0091-880d-8334-c142d9591e1b&quot;alt=&quot;&quot;class=&quot;zemanta-pixie-img&quot; /&gt;
&lt;/div&gt;

</content>
  </entry>
  
  <entry>
    <title>Using MySQL for storing images</title>
    <link href="http://www.kraken.no/blog/2009/11/15/Using-MySQL-for-storing-images/"/>
    <updated>2009-11-15T15:29:00+01:00</updated>
    <id>http://www.kraken.no/blog/2009/11/15/Using-MySQL-for-storing-images</id>
    <content type="html">&lt;p&gt;You do not always have the luxury to decide how things are done. This weekend the image service at work decided it was its turn to wreck itself.&lt;/p&gt;

&lt;p&gt;The whole story starts of with me rewriting a part of the image service - the component that inserts an image into the service.&lt;/p&gt;

&lt;p&gt;The service has two parts: One that saves images to the datastore and one that retrieves images from the datastore and delivers them to some client, usually as a thumbnail. This should be fairly simple stuff that should never go wrong and usually just work. The problem was in the chosen datastore: MySQL.&lt;/p&gt;

&lt;p&gt;MySQL is good for many things, but far too often have I seen it used as a hammer where a screwdriver should have been used.&lt;/p&gt;

&lt;p&gt;The schema for image database looked like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;  CREATE TABLE IF NOT EXISTS \`image\` (  
      \`objectid\` int(11) NOT NULL default'0',  
      \`imagedata\` longblob,  
      \`imagewidth\` int(4) default NULL,  
      \`imageheight\` int(4) default NULL,  
      \`imagemime\` varchar(4) default NULL,  
      \`imageurl\` text,  
      PRIMARY KEY  (\`objectid\`) ) ENGINE=MyISAM; 
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I'll comment on a few of the fields above. The worst field here is probably the imagemime field. Notice that it is a varchar of max 4 characters. The idea is to only store the specific part of the mimetype, i.e. pjpeg from image/pjpeg. Notice that the author thought that imagetypes only come in names of less than 4 characters (jpeg, png and gif) and thus we would have no problems with the size of the field.&lt;/p&gt;

&lt;p&gt;The error caused by the service trying to thumnail pjpe images was what made me look at the image service.&lt;/p&gt;

&lt;p&gt;To fix this bug we issued&lt;/p&gt;

&lt;pre&gt;&lt;code&gt; &quot;ALTER TABLE \`image\` CHANGE \`imagemime\` \`imagemime\` VARCHAR( 10 )&quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;, thinking that this should work ok.&lt;/p&gt;

&lt;p&gt;Bad idea.&lt;/p&gt;

&lt;p&gt;The problem is that because this command should work atomically, MySQL will do all the work in a separate file and then mv the file over the original file when done. What do you think happens when there is too little space left on the disk? MySQL hangs, crashes and burns.&lt;/p&gt;

&lt;p&gt;Lesson learned: &lt;strong&gt;Always have more space left on the MySQL data partition than the size of the largest table(.MYD) file.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If not, you cannot perform recovery!&lt;/p&gt;

&lt;p&gt;Or in my case, change the table.&lt;/p&gt;

&lt;p&gt;The next thing I tried was deleting a large amount of the images in the store as they were old and had no value. This again blew up because of too little space.The solution to this mess was to move the whole database over to another partition, run myisamchk and then move it back.&lt;/p&gt;

&lt;p&gt;How should this service have been designed?&lt;/p&gt;

&lt;p&gt;I am not an expert on designing online storage facilities for images, but one thing that I would like to note is the storing of metadata together with the file - but not in the file itself.&lt;/p&gt;

&lt;p&gt;Most image formats for the web store image height and width in the start of the image and you can use metadata formats like IPTC to store even more information into the image. Storing metadata in the file makes it easier to retrieve the file since you do not need to fetch additional metadata that is already in the file.This would have made it possible to simplify the storage schema. You may want to keep a copy of the metadata in a store to be able to query it, but for most operations it will not be needed since you want the file at the same time anyway.&lt;/p&gt;

&lt;p&gt;Storing the files in the db is also a bad idea (IMHO). It may well be faster to serve binary objects from a database, but this comes at a price. The service is harder to backup, dependent on an extra component (the db) and thus much more complicated.There are two designs I've considered for a simple image service.&lt;/p&gt;

&lt;p&gt;Either build a tiny layer around&lt;a target=&quot;_blank&quot;href=&quot;http://www.danga.com/mogilefs/&quot;&gt;Mogile FS&lt;/a&gt;or use&lt;a target=&quot;_blank&quot;href=&quot;http://gluster.com&quot;&gt;GlusterFS&lt;/a&gt;to replicate the filesystem where the files are stored.&lt;/p&gt;

&lt;p&gt;Note: I would probably have done the same mistake myself if I got asked to create a system like this a year ago. I just hope someone reads this in time to not repeat the mistakes.&lt;/p&gt;

&lt;p&gt;Attendum about ActiveMQ: Sometimes you do not have the luxury to keep every service separated on different machines. When the disk filled up due to the MySQL problems above I also learned that if you run Active MQ with the Kaha persistent storage db then you should keep it on a separate partition - or else loose all messages when you run out of disk space.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Using Pythons logging module with unittest</title>
    <link href="http://www.kraken.no/blog/2009/10/08/Using-Pythons-logging-module-with-unittest/"/>
    <updated>2009-10-08T08:39:00+02:00</updated>
    <id>http://www.kraken.no/blog/2009/10/08/Using-Pythons-logging-module-with-unittest</id>
    <content type="html">&lt;p&gt;Problem: setUp() is called for every method but I only want to start logging once. Solution:Add a check on logger.handlers to see if any handlers have been registered with the logger:def startLogging():    logger = logging.getLogger()    if len(logger.handlers):        return logger    stdout = logging.StreamHandler()    stdout.setLevel(logging.DEBUG)    logger.addHandler(stdout)    return loggerclass MyTest(unittest.TestCase):     def setUp(self):         startLogging()    def test_something(self):        some_function_that_uses_logging()&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>TransactionManagerLookupFactory - No TransactionManagerLookup configured</title>
    <link href="http://www.kraken.no/blog/2009/09/01/TransactionManagerLookupFactory---No-TransactionManagerLookup-configured/"/>
    <updated>2009-09-01T15:55:00+02:00</updated>
    <id>http://www.kraken.no/blog/2009/09/01/TransactionManagerLookupFactory---No-TransactionManagerLookup-configured</id>
    <content type="html">&lt;p&gt;I spent the best part of yesterday afternoon fighting the message above. I post this so that the next person fighting it may save some time. One of the problems was that none of&lt;a href=&quot;http://forum.springsource.org/archive/index.php/t-70281.html&quot;&gt;the&lt;/a&gt;&lt;a href=&quot;http://stackoverflow.com/questions/739791/spring-no-transaction-manager-has-been-configured&quot;&gt;solutions&lt;/a&gt;&lt;a href=&quot;http://forum.springsource.org/archive/index.php/t-70281.html&quot;&gt;suggested&lt;/a&gt;helped. After some beer, sleep and a fresh start I found&lt;a href=&quot;http://forum.springsource.org/showthread.php?t=42841&quot;&gt;this message&lt;/a&gt;that talks about replacing&lt;/p&gt;

&lt;pre&gt;&amp;lt;tx:annotation-driven transaction-manager=&quot;transactionManager&quot; /&amp;gt;&lt;/pre&gt;


&lt;p&gt;With&lt;/p&gt;

&lt;pre&gt;&amp;lt;code&amp;gt;&amp;lt;bean class=&quot;org.springframework.transaction.aspectj.AnnotationTransactionAspect&quot;factory-method=&quot;aspectOf&quot;&amp;gt;&amp;lt;property name=&quot;transactionManager&quot; ref=&quot;transactionManager&quot;&amp;gt;&amp;lt;/property&amp;gt;&amp;lt;/bean&amp;gt;&amp;lt;/code&amp;gt;&lt;/pre&gt;


&lt;p&gt;And suddenly it all worked. Another example of GDD - Google Driven Development. If anyone knows why this works - please explain.&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;Update: &lt;/span&gt;There seems to be an issue when it comes to combining @Confgurable and @Transactional in a project that relates to the comment above. Also, I later experienced that doing sessionFactory.getCurrentsession() is not a good idea when using spring transactions. Instead, use&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Update 2:&lt;/strong&gt;None of the examples of Transactional tests using spring show it, but you'll need the TransactionalTestExecutionListener to get @AfterTransaction and @BeforeTransaction to work. Det it up like this:&lt;/p&gt;

&lt;pre&gt;@TestExecutionListeners( { TransactionalTestExecutionListener.class })&lt;img src=&quot;http://img.zemanta.com/pixy.gif?x-id=919f3f17-ce2c-8175-bc1b-b0b28ebc0c1b&quot;alt=&quot;&quot;class=&quot;zemanta-pixie-img&quot; /&gt;&lt;/pre&gt;




&lt;div class=&quot;zemanta-pixie&quot;&gt;
   
&lt;/div&gt;




&lt;div class=&quot;zemanta-pixie&quot;&gt;
   
&lt;/div&gt;



</content>
  </entry>
  
  <entry>
    <title>umount: device is busy</title>
    <link href="http://www.kraken.no/blog/2009/08/28/umount--device-is-busy/"/>
    <updated>2009-08-28T10:29:00+02:00</updated>
    <id>http://www.kraken.no/blog/2009/08/28/umount--device-is-busy</id>
    <content type="html">&lt;pre&gt;&lt;div class=&quot;codeblock&quot;&gt;
  &lt;code&gt;#umount /var&amp;lt;br /&amp;gt;&amp;lt;br /&gt;umount: device is busy&amp;lt;br /&amp;gt;&lt;/code&gt;
&lt;/div&gt;&lt;/pre&gt;


&lt;p&gt;Who hasn't experienced this one?&lt;/p&gt;

&lt;p&gt;Anyhow, I found&lt;a href=&quot;https://bugs.launchpad.net/ubuntu/+source/util-linux/+bug/195071&quot;target=&quot;_blank&quot;&gt;this&lt;/a&gt;shellscript that does the important checks:&lt;/p&gt;

&lt;h1&gt;!/bin/sh&lt;/h1&gt;

&lt;h1&gt;Attempts to umount a mountpoint or device. If it fails, give info on why it might be busy.&lt;/h1&gt;

&lt;p&gt;/bin/umount $&lt;em&gt; || (&lt;br/&gt;
    if [ -z&quot;$&lt;/em&gt;&quot; ]&lt;br/&gt;
    then&lt;br/&gt;
       exit&lt;br/&gt;
    fi&lt;br/&gt;
    echo `pwd`/&quot;$1&quot; | sed's/&lt;sup&gt;.*\/\//\//g'|&lt;/sup&gt; ( read abspath&lt;br/&gt;
   &lt;br/&gt;
    mtab_entry=`grep&quot;$abspath&quot;&amp;lt; /etc/mtab`&lt;br/&gt;
    echo $mtab_entry | if grep&quot;/&quot;&gt; /dev/null&lt;br/&gt;
    then&lt;br/&gt;
       device=`echo $mtab_entry | sed&quot;s/ .&lt;em&gt;$//g&quot;`&lt;br/&gt;
       mountpoint=`echo $mtab_entry | sed&quot;s/[^ ]&lt;/em&gt; //&quot; | sed&quot;s/ .*$//g&quot;`&lt;br/&gt;
       #echo $device $mountpoint&lt;/p&gt;

&lt;p&gt;       ( echo The mountpoint $mountpoint is in use by:&lt;br/&gt;
        lsof | grep&quot; $mountpoint&quot; | head     #list files open&lt;br/&gt;
           cat /etc/mtab | grep&quot; $mountpoint/&quot;  #list sub mount points&lt;br/&gt;
       ) 1&gt;&amp;amp;2&lt;br/&gt;
    fi&lt;br/&gt;
))&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;div class=&quot;zemanta-pixie&quot;&gt;
  &lt;img src=&quot;http://img.zemanta.com/pixy.gif?x-id=a339129d-589c-88fd-ad11-cc18348b8c21&quot;alt=&quot;&quot;class=&quot;zemanta-pixie-img&quot; /&gt;
&lt;/div&gt;

</content>
  </entry>
  
  <entry>
    <title>Securing the web: PHP CMSs should autodestruct</title>
    <link href="http://www.kraken.no/blog/2009/07/20/Securing-the-web--PHP-CMSs-should-autodestruct/"/>
    <updated>2009-07-20T09:31:00+02:00</updated>
    <id>http://www.kraken.no/blog/2009/07/20/Securing-the-web--PHP-CMSs-should-autodestruct</id>
    <content type="html">&lt;p&gt;I've been using Drupal a bit lately for some simple sites and just happened to come over&lt;a target=&quot;_blank&quot;href=&quot;http://fourkitchens.com/blog/2009/04/03/vulnerability-reports-are-not-indications-weakness&quot;&gt;this&lt;/a&gt;debate on the relative security between Drupal and Plone. I think we need to go beond looking at the number of Security advisories and start discussing how we protect vulnerable versions of software. The problem with the larger PHP CMS'es (Drupal, Joomla etc) isn't that they do not care about security - but that that their users do not.One thing I've noticed is that there are a lot of simple sites out there that get hacked because they do not upgrade their CMS'es to the latest version. Often the hacker keeps the site up so that it is impossible to notice that that the account is being used for all kinds of spamming - for example by adding a bunch of&quot;invisible&quot;links at the bottom of the site. I've tried to contact some ISP's that hosts sites like this (Servetheworld amongst others), but their reply is that they cannot disable a customers account or clean up the customers site just because it is hacked. IMHO we need a way to protect users against themselves here. A simple protocol that checks the version of the running CMS against a registry somewhere and then either shuts down the CMS and/or notifies the user.At least 50% of the people running small sites do not know enough about the security to keep their site up to date. We need to provide protection for them.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>MYSQL datatruncation errors</title>
    <link href="http://www.kraken.no/blog/2009/06/22/MYSQL-datatruncation-errors/"/>
    <updated>2009-06-22T08:38:00+02:00</updated>
    <id>http://www.kraken.no/blog/2009/06/22/MYSQL-datatruncation-errors</id>
    <content type="html">&lt;p&gt;Few things can provide as much frustration as refactoring a legacy system bit by bit. Today I have been wrestling with a field defined in MySQL as&quot;timestamp default'0000-00-00 00:00:00'. In my (reveng'ed) POJO the field is defined like this:&lt;/p&gt;

&lt;pre&gt;@Temporal(TemporalType.TIMESTAMP)&amp;nbsp;&amp;nbsp;&amp;nbsp; @Column(name =&quot;httpstatus_time&quot;, nullable = false, length = 19,
    columnDefinition=&quot;timestamp default'0000-00-00 00:00:00'&quot;)    
    public Date getHttpstatusTime() {       
      return this.httpstatusTime;
    }&lt;/pre&gt;


&lt;p&gt;Now, it turns out that JDBC cannot deal with date values that are before UNIX epoch, something 0000-00-00 clearly is. So, what does JDBC do in these situations? It will throw an exception. To get around this, you can add'zeroDateTimeBehavior=convertToNull'to your jdbc url. After setting zeroDateTimeBehaviour, the value will be set to a Java&lt;span style=&quot;font-weight: bold;&quot;&gt;null&lt;/span&gt;. This provides you with another issue: When you get an object from the db, and you modify it, you may have to also modify some other values and set them to something other than null.&lt;/p&gt;

&lt;p&gt;Note: I tried setting the dates to&quot;new Date(1)&quot; but that didn't work - it is too close to 0 so JDBC still throws a fit. I ended up with&quot;new Date(10000)&quot;.&lt;/p&gt;

&lt;p&gt;If you do not check your null's, you'll get this: (I've omitted parts of the stacktrace for brevity)&lt;/p&gt;

&lt;pre&gt;
org.springframework.dao.DataIntegrityViolationException: not-null property references a null or transient value: com.scanmine.scheduler.server.model.Source.httpstatusTime;
 nested exception is org.hibernate.PropertyValueException: not-null property references a null or transient value: com.example.Myclass.httpstatusTime    at org.springframework.orm.hibernate3.SessionFactoryUtils.convertHibernateAccessException...Caused by: org.hibernate.PropertyValueException: not-null property references a null or transient value:com.example.Myclass.httpstatusTime...Caused by: org.hibernate.PropertyValueException: not-null property references anull or transient value: com.example.Myclass.httpstatusTime&lt;/pre&gt;


&lt;p&gt;Not fun.&lt;span style=&quot;font-weight: bold;&quot;&gt;Bonus tip&lt;/span&gt;If you use DBUnit to test your legacy db and want to add values lik'0000-00-00 00:00:00'you will hit the same bug as described above. To get around it, add jdbcCompliantTruncation=false to the connection url.&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;h3&gt;Links&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;http://bugs.mysql.com/bug.php?id=3331&quot;&gt;http://bugs.mysql.com/bug.php?id=3331&lt;/a&gt;&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;
</content>
  </entry>
  
</feed>

