Rails MockCGI testing
Posted by Aaron Bedra over 2 years ago
require File.dirname(__FILE__) + '/../test_helper'
require 'cpa_controller'
require 'user'
require 'action_controller/integration'

# Re-raise errors caught by the controller.
class CpaController; def rescue_action(e) raise e end; end

class CpaControllerTest < Test::Unit::TestCase
  fixtures :users
  
  class MockCGI < CGI #:nodoc:
    attr_accessor :stdinput, :stdoutput, :env_table

    def initialize(env, data = '')      
      self.env_table = env
      self.stdinput = StringIO.new(data)
      self.stdoutput = StringIO.new
      super()
    end
  end
  
  def setup
    assert_equal "test", ENV['RAILS_ENV']
    assert_equal "change-me", SALT
    @controller = CpaController.new
    @foobar_postdata = "foobar"
    @john_postdata = "johnbarracuda"
  end
  
  def test_fails_with_401_if_not_authorized_user
    process "post", :create_user, "nobody", "nohow", @foobar_postdata
    assert_response_and_body 401, "401 Unauthorized: You are not authorized to interact with Tracks."
  end
  
  def test_fails_with_401_if_not_admin_user
    process "post", :create_user, users(:other_user).login, 'sesame', @foobar_postdata
    assert_response_and_body 401, "401 Unauthorized: You are not authorized to interact with Tracks."
  end
  
  def test_content_type_must_be_xml
    process "post", :create_user, users(:admin_user).login, 'abracadabra', @foobar_postdata, "application/x-www-form-urlencoded"
    assert_response_and_body 404, "Content Type must be application/xml."
  end
  
  def test_fails_with_invalid_xml_format
    invalid_postdata = ""
    process "post", :create_user, users(:admin_user).login, 'abracadabra', invalid_postdata
    assert_response_and_body 404, "Expected post format is xml like so: usernameabc123."
  end
  
  def test_fails_with_invalid_xml_format2
    invalid_postdata = "foo"
    process "post", :create_user, users(:admin_user).login, 'abracadabra', invalid_postdata
    assert_response_and_body 404, "Expected post format is xml like so: usernameabc123."
  end
  
  def test_xml_simple_param_parsing
    process "post", :create_user, users(:admin_user).login, 'abracadabra', @foobar_postdata
    assert @controller.params.has_key?(:request)
    assert @controller.params[:request].has_key?(:login)
    assert @controller.params[:request].has_key?(:password)
    assert_equal 'foo', @controller.params[:request][:login]
    assert_equal 'bar', @controller.params[:request][:password]
  end

  def test_fails_with_too_short_password
    process "post", :create_user, users(:admin_user).login, 'abracadabra', @foobar_postdata
    assert_response_and_body 404, "Password is too short (minimum is 5 characters)"
  end
  
  def test_fails_with_nonunique_login
    existing_login = users(:other_user).login
    data = "#{existing_login}barracuda"
    process "post", :create_user, users(:admin_user).login, 'abracadabra', data
    assert_response_and_body 404, "Login has already been taken"
  end
  
  def test_creates_new_user
    process "post", :create_user, users(:admin_user).login, 'abracadabra', @john_postdata
    assert_response_and_body 200, "User created."
    assert_equal 3, User.count
    john1 = User.find_by_login('john')
    assert_not_nil john1, "expected user john to be created"
    john2 = User.authenticate('john','barracuda')
    assert_not_nil john2, "expected user john to be created"
  end

  def test_fails_with_get_verb
    process "get", :create_user, users(:admin_user).login, 'abracadabra', @john_postdata
    assert_response_and_body 403, "403 Forbidden: Only POST requests on this resource are allowed."
  end
  
  #TODO: test_creates_preferences
  
  private  
  
  def process(verb, action, login, password, data = '', content_type = 'application/xml', accept =  'application/xml')
    
    cgi = MockCGI.new({
      'REQUEST_METHOD' => verb,
      'HTTP_ACCEPT'   => accept,
      'HTTP_AUTHORIZATION' => "Basic " + Base64.encode64(login + ":" + password),
      'CONTENT_TYPE'   => content_type,
      'QUERY_STRING'   => "action=#{action}&controller=cpa}",
      "REQUEST_URI"    => "/",
      "HTTP_HOST"      => 'testdomain.com',
      "CONTENT_LENGTH" => data.size,
      "SERVER_PORT"    => "80",
      "HTTPS"          => "off"}, data)
          
    @controller.send(:process, ActionController::CgiRequest.new(cgi, {}), ActionController::CgiResponse.new(cgi))
    @response = @controller.response
    # Decorate the response with the standard behavior of the TestResponse
    # so that things like assert_response can be used
    @response.extend(ActionController::TestResponseBehavior)
  end
  
  def assert_response_and_body (type, body, message = nil)
    assert_response type, message
    assert_equal body, @response.body, message
  end
  
end
Language Ruby / Tagged with rails, testing, cgi