Pivotal Labs

Standup 04/30/2007

edit Posted by Joe Moore on Monday April 30, 2007 at 04:40PM

Interesting Things

  • MoniTwitter is live! Check out the coolest site-monitoring mash-up in the history of site-monitoring mash-ups!
  • When you use :dependent => :destroy to cascade deletes, make sure you test them well! This really saved our bacon during a major rafactoring.

Ask for Help

  • "I always forget how to submit an HTML form with a link in Rails..." Here you go!

<%= link_to_function('Link Name', "$('form_id').submit()") %>

Total Stand-up Meeting Time: 20:00 minutes

Standup 04/27/07: Testing File Uploads

edit Posted by da3mon on Friday April 27, 2007 at 05:48PM

The setup:

I'm told file uploading is a pain to test. We needed to. So we cruised through the tubes over to ruby-doc.org to check out the Net::HTTP rdoc -- only to find that Net:HTTP::Post does not support multipart uploading and files. What to do, what to DO?!?

The research:

Some googling later, we find this article showing how to do it. A little copy-paste, a small spike later, and we have an external script capable of uploading files into our web-apps. But, lets brain-storm a little...

  • How can we make it better?
  • What would be a nice interface?

Well, the first step is to change the script such that it can be more easily integrated into rake test:functionals: make it less script-y; more library. The interface is somewhat inspired by the basic_auth method. All you have to say is Net::HTTP::Post.new().multipart_params = {}? You give it a hash, and it takes care of the rest. Huzzah! So lets open up Net::HTTP::POST and give it some new methods. Time for some CODE!!!

The Code

require 'net/https'
require "rubygems"
require "mime/types"
require "base64"
require 'cgi'

class Net::HTTP::Post
  def multipart_params=(param_hash={})
    boundary_token = [Array.new(8) {rand(256)}].join
    self.content_type = "multipart/form-data; boundary=#{boundary_token}"
    boundary_marker = "--#{boundary_token}\r\n"
    self.body = param_hash.map { |param_name, param_value|
      boundary_marker + case param_value
      when String
        text_to_multipart(param_name, param_value)
      when File
        file_to_multipart(param_name, param_value)
      end
    }.join('') + "--#{boundary_token}--\r\n"
  end

  protected
  def file_to_multipart(key,file)
    filename = File.basename(file.path)
    mime_types = MIME::Types.of(filename)
    mime_type = mime_types.empty? ? "application/octet-stream" : mime_types.first.content_type
    part = Q|Content-Disposition: form-data; name="#{key}"; filename="#{filename}"\r\n|
    part += "Content-Transfer-Encoding: binary\r\n"
    part += "Content-Type: #{mime_type}\r\n\r\n#{file.read}"
  end

  def text_to_multipart(key,value)
    "Content-Disposition: form-data; name=\"#{key}\"\r\n\r\n#{value}\r\n"
  end
end

Oh the utility:

Now that's more like it. Hackish, since you have to stick headers into the request body, but effective. Notice the bit in there about MIME::Types. Did you see that? Yeah, we went there. Say it with me... Automatic mime type detection with a safe default. The absurd thing in there is that the MIME::Types gem (as of today) does not know about .rb files.

irb(main):007:0> MIME::Types.of('something.rb')                   
=> []

So now that you have that, it's just a simple use of Net::HTTP with a blizzock to upload a file in a functional test.

File.open(File.expand_path('script/test.png'), 'r') do |file|
  http = Net::HTTP.new('localhost', 3000)
  begin
    http.start do |http|
      request = Net::HTTP::Post.new('/your/url/here')
      request.basic_auth 'lonely_user', 'really_long_password'
      request.multipart_params = {'file' => file, 'title' => 'title'}
      response = http.request(request)
      response.value
      puts response.body
    end
  rescue Net::HTTPServerException => e
    p e
  end
end

The questions:

So what do you think? How can this be made even better?

Standup 2.5

edit Posted by Alex Chaffee on Monday April 23, 2007 at 09:45PM

  1. Introductions. Anybody new? Any guests in the room?
  2. Help! Anybody need assistance?
  3. Neat! Interesting things we want to share.
  4. Status. Only if there's time -- project or individual reports.

(Based on Standup 2.0.)

Full-stack web app testing with Selenium and Rails

edit Posted by Alex Chaffee on Monday April 23, 2007 at 07:32PM

Brian Takita and Alex Chaffee gave a presentation at the SDForum Silicon Valley Ruby Conference over the weekend, entitled Full-stack web app testing with Selenium and Rails. We're going to do it again at Agile 2007 (and we'll have an extra half-hour next time, so we'll have time to do some interactive pairing with some hapless audience member).

Here are the slides, courtesy of SlideShare:

Silicon Valley Ruby Conference Report

edit Posted by Alex Chaffee on Monday April 23, 2007 at 07:30PM

Brian Takita and Alex Chaffee gave a presentation at the SDForum Silicon Valley Ruby Conference over the weekend, entitled Full-stack web app testing with Selenium and Rails (slides hosted at SlideShare).

We also attended a few talks (unfortunately we couldn't attend the whole thing). A few highlights:

Mongrel HTTP handlers.

From Brian:

I'm at Ezra's Mongrel HTTP Handler's talk and it looks like a way to improve Tracker's JSON performance.

The simple "Hello World" benchmark was something like this:

  • Rails: ~121 req/sec
  • Mongrel: ~900 req/sec

There is an in-process mode that a mongrel HTTP handler can be run in. This handler will be run in process of your rails app. You have access to Active Record. It just avoids ActionController.

Ezra wrote a framework named Merb (Mongrel + ERB).

Also, mongrel is thread safe. Also, Ezra shared that he wants to avoid magic in Merb.

Ezra's slides are online now.

Here's what Josh wrote about Merb.

Heckle

Heckle is a framework for doing "mutation testing" (like Jester for Java). Kevin Clark demoed it and it looks like a valuable addition to any Ruby build (though probably not as a requirement for a green build -- more like part of a nightly metrics run).

Microformats

Chris Wanstrath of Err the Blog gave a talk that was ostensibly about Web Services but that actually ran a manic gamut from SOAP to Microformats to Firefox plugins to command-line blogs to mock object libraries. His speaking style is deceptively laid-back -- if you don't pay close attention, especially to code examples, you'll miss entire open-source civilizations being born and collapsing. Fortunately, I had just given a talk so my neurons were all juiced up, which meant I could just barely keep up. Bottom line for microformats: gem install mofo.

Update: More Slides

Check out SlideShare's svrc tag for more slide presentations from the conference, including Ezra's Mongrel Talk.

Standup 04/23/2007

edit Posted by Joe Moore on Monday April 23, 2007 at 04:51PM

Interesting Things

Latest news from the "cool new stuff" front:

Total Stand-up Meeting Time: 9:00 minutes

Keeping Your Design Three-Quarters-Baked

edit Posted by Alex Chaffee on Thursday April 19, 2007 at 02:12AM

I just gave a talk at the Web 2.0 Expo with Leslie Chicoine of Satisfaction. We shared our insights into the challenge of integrating foundational design methods (interaction design, usability design, interface design, interaction design) into a team doing Agile development (rapid releases, week-long iterations, high feedback and communication). It was a lot of fun! The room was packed, the energy was high, and they laughed at our jokes!

Here are the slides:

You can also see the slides here at SlideShare. Let me know what you think!

The Challenge of Agile Design

edit Posted by Alex Chaffee on Thursday April 19, 2007 at 02:03AM

I just gave a talk at the Web 2.0 Expo with Leslie Chicoine of Satisfaction. We shared our insights into the challenge of integrating foundational design methods (interaction design, usability design, interface design, interaction design) into a team doing Agile development (rapid releases, week-long iterations, high feedback and communication). It was a lot of fun! The room was packed, the energy was high, and they laughed at our jokes!

Here are the slides:

You can also see the slides here at SlideShare. Let me know what you think!

Standup 4/17/2007

edit Posted by Dav Yaginuma on Wednesday April 18, 2007 at 05:07PM

Interesting Things

  • Nesting a javascript generator within a javascript generator does not work:
<code>
  new.rhtml:
  link_to_function "myFunction" do |page|
     page.insert_html :bottom, :partial => 'new_stuff'
   end

   _new_stuff.rhtml:
   link_to_function "remove" do |page|
     page.replace_html 'some_id', ""
   end
</code>

The quotes in the nested JS are not escaped properly.

  • The plugin team introduced new email validation for the User plugin. They covered this with functional/unit tests within the plugin but projects using the plugin will need to update their own Selenium tests.

Total Stand-up Meeting Time: 10:00 minutes

Standup 4/16/2007

edit Posted by Dav Yaginuma on Tuesday April 17, 2007 at 04:59PM

Standup 04/16/2007

Help

  • Problems with initial start up of CrusieControl daemon script. J of cc.rb can take a look.
  • Running Selenium on IE7 remotely

Interesting Things

  • after_filter is called after the template is rendered, thus you cannot set instance variables in it and expect them to be available in the template. The after_filter method is good for post-render content manipulation or analysis such as gzipping, translating to pig latin or determining content-length. Perhaps it would be useful to add a before_render hook?
  • Remember integration tests are for full stack http testing (routes, REST, etc). Functional tests do not test full stack. Integration tests require some special handling.
  • After a reload on an association proxy object, the reference becomes a true Array (they always respond true to is_a?(Array). This means that none of the association proxy methods are available!
<code>
    class Foo < ActiveRecord::Base
       has_many :bar
    end

    foo = Foo.new
    foo.bars.reload.build
    NoMethodError: undefined method `build' for []:Array
</code>

Total Stand-up Meeting Time: 14:00 minutes

Other articles: