Validating RSS Feeds with RSpec

Posted by Rick DeNatale Fri, 08 Feb 2008 15:38:00 GMT

One of my current Rails projects involves generating an RSS feed. While I was working on this the other night, it seemed to be working, so I deployed it to the staging server. Everything looked fine. If I fetched it with Firefox, the browser offered to let me subscribe to the feed with Google Reader, and if I used Safari I'd see a nice view of the feed just like I expected.

So I sent a note via our campfire to check it out, and a colleague replied that his Safari was saying that it was in an invalid format.

So I went to the W3 RSS Feed Validation Service and worked through the validation issues, after which his browser was as happy as mine.

Of course, having been through that, I wanted to make sure that RSS validation was covered in the specs for the project.

I went looking for an existing RSpec matcher, and found a matcher to validate XHTML but nothing for RSS.

I then found the feedvalidator gem which provides a Ruby interface to the SOAP interface to the W3 feed validator. You would think that W3 would be providing a REST interface! The gem already provides assertions for use with Test::Unit, so I just built an RSpec matcher.

class BeValidFeed
  require 'feed_validator'
  require 'tmpdir'
  require 'md5'

  def matches?(response)
    return true if validity_checks_disabled?
    v = W3C::FeedValidator.new()
    fragment = response.body
    filename = File.join Dir::tmpdir, 'feed.' + MD5.md5(fragment).to_s
    begin
      response = File.open filename do |f| Marshal.load(f) end
      v.parse(response)
    rescue   
      unless v.validate_data(fragment)
        @failure = " could not access w3 validator to validate the feed."
        return false
      end
      File.open filename, 'w+' do |f| Marshal.dump v.response, f end
    end
    v.valid?   
  end

  def description
    "be valid xhtml"
  end

  def failure_message
   @failure || " expected xhtml to be valid, but validation produced these errors:\n #{@message}"
  end

  def negative_failure_message
    " expected to not be valid, but was (missing validation?)"
  end

  private
    def validity_checks_disabled?
      ENV["NONET"] == 'true'
    end
end

def be_valid_feed
  BeValidFeed.new
end

I saved this as spec/be_valid_feed.rb

And in a view or controller spec, I can include this file, and test a response with:

response.should be_valid_feed

If you use this in a controller spec, you will need to tell RSpec to integrate_views, or you won't have much of a feed to check. If you use nested example groups, integrate_views needs to be inside the inner group.


Trackbacks

Use the following link to trackback from your own site:
http://talklikeaduck.denhaven2.com/trackbacks?article_id=486

Comments

  1. Tim Bray about 2 hours later:

    Next time, generate Atom 1.0 instead. The validator messages are way more helpful and you get to dodge a bunch of corner cases with enclosures and summaries and categories and so on.

  2. Ben Mabey about 2 hours later:

    Thanks Rick! This will be handy next time I do a feed.

  3. Rick DeNatale 1 day later:

    Tim -

    Yes generally I prefer Atom, however for this gig the rss feed is for consumption by iTunes, and as far as I know that requires RSS.

  4. Edgar 1 day later:

    Great ! If I got time I’ll add the matcher to feedvalidator