Permalink
Browse files

Cucumber features and steps for most functionality as of the 0.2.8

version.  No features for the CLI yet.

Signed-off-by: John Nunemaker <nunemaker@gmail.com>
  • Loading branch information...
1 parent 5704725 commit 2febfe3c834b4dbcd2f8181b6611637daf757b89 @dpetersen dpetersen committed with Jan 29, 2009
View
@@ -1,11 +1,22 @@
bin/httparty
+cucumber.yml
examples/aaws.rb
examples/basic.rb
examples/delicious.rb
examples/google.rb
examples/rubyurl.rb
examples/twitter.rb
examples/whoismyrep.rb
+features/basic_authentication.feature
+features/command_line.feature
+features/deals_with_http_error_codes.feature
+features/handles_multiple_formats.feature
+features/steps/env.rb
+features/steps/httparty_response_steps.rb
+features/steps/httparty_steps.rb
+features/steps/mongrel_helper.rb
+features/steps/remote_service_steps.rb
+features/supports_redirection.feature
History
httparty.gemspec
lib/core_extensions.rb
View
@@ -6,6 +6,7 @@ require 'rake'
require 'echoe'
require 'spec/rake/spectask'
require "lib/#{ProjectName}/version"
+require 'cucumber/rake/task'
Echoe.new(ProjectName, HTTParty::Version) do |p|
p.description = "Makes http fun! Also, makes consuming restful web services dead easy."
@@ -40,4 +41,8 @@ Rake::Task[:default].prerequisites.clear
task :default => :spec
Spec::Rake::SpecTask.new do |t|
t.spec_files = FileList["spec/**/*_spec.rb"]
-end
+end
+
+Cucumber::Rake::Task.new(:features) do |t|
+ t.cucumber_opts = "--format pretty"
+end
View
@@ -0,0 +1 @@
+default: features
@@ -0,0 +1,20 @@
+Feature: Basic Authentication
+
+ As a developer
+ I want to be able to use a service that requires Basic Authentication
+ Because that is not an uncommon requirement
+
+ Scenario: Passing no credentials to a page requiring Basic Authentication
+ Given a restricted page at '/protected.html'
+ When I call HTTParty#get with '/protected.html'
+ Then it should return a response with a 401 response code
+
+ Scenario: Passing proper credentials to a page requiring Basic Authentication
+ Given a remote service that returns 'Authenticated Page'
+ And that service is accessed at the path '/protected.html'
+ And that service is protected by Basic Authentication
+ And that service requires the username 'jcash' with the password 'maninblack'
+ When I call HTTParty#get with '/protected.html' and a basic_auth hash:
+ | username | password |
+ | jcash | maninblack |
+ Then the return value should match 'Authenticated Page'
@@ -0,0 +1,7 @@
+Feature: Command Line
+
+ As a developer
+ I want to be able to harness the power of HTTParty from the command line
+ Because that would make quick testing and debugging easy
+ And 'easy' is my middle name
+ And I'm kidding it's actually 'Danger'!
@@ -0,0 +1,26 @@
+Feature: Deals with HTTP error codes
+
+ As a developer
+ I want to be informed of non-successful responses
+ Because sometimes thing explode
+ And I should probably know what happened
+
+ Scenario: A response of '404 - Not Found'
+ Given a remote service that returns a 404 status code
+ And that service is accessed at the path '/service.html'
+ When I call HTTParty#get with '/service.html'
+ Then it should return a response with a 404 response code
+
+ Scenario: A response of '500 - Internal Server Error'
+ Given a remote service that returns a 500 status code
+ And that service is accessed at the path '/service.html'
+ When I call HTTParty#get with '/service.html'
+ Then it should return a response with a 500 response code
+
+ Scenario: A non-successful response where I need the body
+ Given a remote service that returns a 400 status code
+ And the response from the service has a body of 'Bad response'
+ And that service is accessed at the path '/service.html'
+ When I call HTTParty#get with '/service.html'
+ Then it should return a response with a 400 response code
+ And the return value should match 'Bad response'
@@ -0,0 +1,34 @@
+Feature: Handles Multiple Formats
+
+ As a developer
+ I want to be able to consume remote services of many different formats
+ And I want those formats to be automatically detected and handled
+ Because web services take many forms
+ And I don't want to have to do any extra work
+
+ Scenario: An HTML service
+ Given a remote service that returns '<h1>Some HTML</h1>'
+ And that service is accessed at the path '/service.html'
+ And the response from the service has a Content-Type of 'text/html'
+ When I call HTTParty#get with '/service.html'
+ Then it should return a String
+ And the return value should match '<h1>Some HTML</h1>'
+
+ Scenario: A JSON service
+ Given a remote service that returns '{ "jennings": "waylon", "cash": "johnny" }'
+ And that service is accessed at the path '/service.json'
+ And the response from the service has a Content-Type of 'application/json'
+ When I call HTTParty#get with '/service.json'
+ Then it should return a Hash equaling:
+ | key | value |
+ | jennings | waylon |
+ | cash | johnny |
+
+ Scenario: An XML Service
+ Given a remote service that returns '<singer>waylon jennings</singer>'
+ And that service is accessed at the path '/service.xml'
+ And the response from the service has a Content-Type of 'text/xml'
+ When I call HTTParty#get with '/service.xml'
+ Then it should return a Hash equaling:
+ | key | value |
+ | singer | waylon jennings |
View
@@ -0,0 +1,15 @@
+require 'mongrel'
+require 'activesupport'
+require 'lib/httparty'
+require 'spec/expectations'
+
+Before do
+ port = ENV["HTTPARTY_PORT"] || 31981
+ @host_and_port = "0.0.0.0:#{port}"
+ @server = Mongrel::HttpServer.new("0.0.0.0", port)
+ @server.run
+end
+
+After do
+ @server.stop
+end
@@ -0,0 +1,26 @@
+Then /it should return an? (\w+)$/ do |class_string|
+ @response_from_httparty.should be_an_instance_of(class_string.constantize)
+end
+
+Then /the return value should match '(.*)'/ do |expected_text|
+ @response_from_httparty.should eql(expected_text)
+end
+
+Then /it should return a Hash equaling:/ do |hash_table|
+ @response_from_httparty.should be_an_instance_of(Hash)
+ @response_from_httparty.keys.length.should eql(hash_table.rows.length)
+ hash_table.hashes.each do |pair|
+ key, value = pair["key"], pair["value"]
+ @response_from_httparty.keys.should include(key)
+ @response_from_httparty[key].should eql(value)
+ end
+end
+
+Then /it should return a response with a (\d+) response code/ do |code|
+ @response_from_httparty.code.should eql(code)
+end
+
+Then /it should raise an HTTParty::RedirectionTooDeep exception/ do
+ @exception_from_httparty.should_not be_nil
+ @exception_from_httparty.class.should eql(HTTParty::RedirectionTooDeep)
+end
@@ -0,0 +1,15 @@
+When /I call HTTParty#get with '(.*)'$/ do |url|
+ begin
+ @response_from_httparty = HTTParty.get("http://#{@host_and_port}#{url}")
+ rescue HTTParty::RedirectionTooDeep => e
+ @exception_from_httparty = e
+ end
+end
+
+When /I call HTTParty#get with '(.*)' and a basic_auth hash:/ do |url, auth_table|
+ h = auth_table.hashes.first
+ @response_from_httparty = HTTParty.get(
+ "http://#{@host_and_port}#{url}",
+ :basic_auth => { :username => h["username"], :password => h["password"] }
+ )
+end
@@ -0,0 +1,55 @@
+def basic_mongrel_handler
+ Class.new(Mongrel::HttpHandler) do
+ attr_writer :content_type, :response_body, :response_code
+
+ def initialize
+ @content_type = "text/html"
+ @response_body = ""
+ @response_code = 200
+ @custom_headers = {}
+ end
+
+ def process(request, response)
+ reply_with(response, @response_code, @response_body)
+ end
+
+ def reply_with(response, code, response_body)
+ response.start(code) do |head, body|
+ head["Content-Type"] = @content_type
+ @custom_headers.each { |k,v| head[k] = v }
+ body.write(response_body)
+ end
+ end
+ end
+end
+
+def new_mongrel_handler
+ basic_mongrel_handler.new
+end
+
+def add_basic_authentication_to(handler)
+ m = Module.new do
+ attr_writer :username, :password
+
+ def self.extended(base)
+ base.instance_eval { @custom_headers["WWW-Authenticate"] = 'Basic Realm="Super Secret Page"' }
+ base.class_eval { alias_method_chain :process, :basic_authentication }
+ end
+
+ def process_with_basic_authentication(request, response)
+ if authorized?(request) then process_without_basic_authentication(request, response)
+ else reply_with(response, 401, "Incorrect. You have 20 seconds to comply.")
+ end
+ end
+
+ def authorized?(request)
+ request.params["HTTP_AUTHORIZATION"] == "Basic " + Base64.encode64("#{@username}:#{@password}").strip
+ end
+ end
+ handler.extend(m)
+end
+
+def new_mongrel_redirector(target_url, relative_path = false)
+ target_url = "http://#{@host_and_port}#{target_url}" unless relative_path
+ Mongrel::RedirectHandler.new(target_url)
+end
@@ -0,0 +1,47 @@
+Given /a remote service that returns '(.*)'/ do |response_body|
+ @handler = new_mongrel_handler
+ Given "the response from the service has a body of '#{response_body}'"
+end
+
+Given /a remote service that returns a (\d+) status code/ do |code|
+ @handler = new_mongrel_handler
+ @handler.response_code = code
+end
+
+Given /that service is accessed at the path '(.*)'/ do |path|
+ @server.register(path, @handler)
+end
+
+Given /the response from the service has a Content-Type of '(.*)'/ do |content_type|
+ @handler.content_type = content_type
+end
+
+Given /the response from the service has a body of '(.*)'/ do |response_body|
+ @handler.response_body = response_body
+end
+
+Given /the url '(.*)' redirects to '(.*)'/ do |redirection_url, target_url|
+ @server.register redirection_url, new_mongrel_redirector(target_url)
+end
+
+Given /that service is protected by Basic Authentication/ do
+ add_basic_authentication_to @handler
+end
+
+Given /that service requires the username '(.*)' with the password '(.*)'/ do |username, password|
+ @handler.username = username
+ @handler.password = password
+end
+
+Given /a restricted page at '(.*)'/ do |url|
+ Given "a remote service that returns 'A response I will never see'"
+ And "that service is accessed at the path '#{url}'"
+ And "that service is protected by Basic Authentication"
+ And "that service requires the username 'something' with the password 'secret'"
+end
+
+# This joins the server thread, and halts cucumber, so you can actually hit the
+# server with a browser. Runs until you kill it with Ctrl-c
+Given /I want to hit this in a browser/ do
+ @server.acceptor.join
+end
@@ -0,0 +1,22 @@
+Feature: Supports Redirection
+
+ As a developer
+ I want to work with services that may redirect me
+ And I want it to follow a reasonable number of redirects
+ Because sometimes web services do that
+
+ Scenario: A service that redirects once
+ Given a remote service that returns 'Service Response'
+ And that service is accessed at the path '/service.html'
+ And the url '/redirector.html' redirects to '/service.html'
+ When I call HTTParty#get with '/redirector.html'
+ Then the return value should match 'Service Response'
+
+ # TODO: Look in to why this actually fails...
+ Scenario: A service that redirects to a relative URL
+
+ Scenario: A service that redirects infinitely
+ Given the url '/first.html' redirects to '/second.html'
+ And the url '/second.html' redirects to '/first.html'
+ When I call HTTParty#get with '/first.html'
+ Then it should raise an HTTParty::RedirectionTooDeep exception

0 comments on commit 2febfe3

Please sign in to comment.