spec/optionsful_server_spec.rb in optionsful-0.2.3 vs spec/optionsful_server_spec.rb in optionsful-0.3.0

- old
+ new

@@ -1,335 +1,447 @@ -require File.dirname(__FILE__) + '/spec_helper' +require File.expand_path(File.dirname(__FILE__) + '/spec_helper') +include Rack::Test::Methods +require 'fileutils' +describe "Optionsful" do -describe Baurets::Optionsful::Server do - - include Rack::Test::Methods - context "as a Rack middleware" do - it "is a Ruby object that responds to call;" do - assert ::Baurets::Optionsful::Server.new(app).respond_to? :call + it "is a Ruby object that responds to call" do + ::Baurets::Optionsful::Server.new(app).respond_to?(:call).should be true end - it "takes exactly one argument, (the environment) and returns an Array;" do + it "takes exactly one argument, (the environment) and returns an Array" do response = ::Baurets::Optionsful::Server.new(app).call(mock_env({"REQUEST_METHOD" => "OPTIONS", "PATH_INFO" => "/posts"})) - assert response.kind_of?(Array) + response.should be_a_kind_of Array end - it "the returned Array must have exactly three values: the status, the headers and the body;" do + it "the returned Array must have exactly three values: the status, the headers and the body" do response = ::Baurets::Optionsful::Server.new(app).call(mock_env({"REQUEST_METHOD" => "OPTIONS", "PATH_INFO" => "/posts"})) - assert response.size.should == 3 - assert response[0].kind_of? Fixnum - assert response[1].kind_of? Hash - assert response[2].kind_of? String + validate_response(response) end before do - ActionController::Routing::Routes.draw do |map| - map.resources :posts, :has_many => :comments + rails_app.routes.draw do + resources :posts end end - it "must be nice, acting somewhere on a Rack middleware stack;" do + it "must be nice, acting somewhere on a Rack middleware stack" do response = fake_opts_app.call(mock_env({"REQUEST_METHOD" => "OPTIONS", "PATH_INFO" => "/posts"})) - assert response.size.should == 3 - assert response[0].kind_of? Fixnum - assert response[0].should == 204 - assert response[1].kind_of? Hash - assert response[1]["Allow"] + validate_response(response) + response[0].should be 204 + response[1]["Allow"].should_not be nil end it "must let the request go through the stack, if it has nothing to it!" do response = fake_opts_app.call(mock_env({"REQUEST_METHOD" => "GET", "PATH_INFO" => "/lobster"})) - assert response.size.should == 3 - assert response[0].kind_of? Fixnum - assert response[0].should == 200 - assert response[1].kind_of? Hash + validate_response(response) + response[0].should be 200 end end - context "as an interpreter for HTTP OPTIONS requests, MUST recognize the Rails" do + context "as an HTTP OPTIONS verb provider must master Rails" do - describe "default resource routing" do - #Sample resource route (maps HTTP verbs to controller actions automatically) + describe "default resources routing" do before(:all) do - ActionController::Routing::Routes.draw do |map| - map.resources :posts, :has_many => :comments + rails_app.routes.draw do + resources :posts end end it "the index action displays a list of all posts in response of a GET request" do response = http_options_request("/posts") - assert response.kind_of?(Array) - assert allows?(response[1], "GET") + validate_response(response) + response[0].should be 204 + response[1]["Allow"].should include "GET" end it "the new action return from a GET request an HTML form for creating a new post" do response = http_options_request("/posts/new") - assert response.kind_of?(Array) - assert allows?(response[1], "GET") + validate_response(response) + response[0].should be 204 + response[1]["Allow"].should include "GET" + response[1]["Allow"].should_not include "POST" end it "the create action uses POST to create a new post instance" do response = http_options_request("/posts") - assert response.kind_of?(Array) - assert allows?(response[1], "POST") + validate_response(response) + response[0].should be 204 + response[1]["Allow"].should include "POST" end it "the show action display a specific post in response of a GET request" do response = http_options_request("/posts/1") - assert response.kind_of?(Array) - assert allows?(response[1], "GET") + validate_response(response) + response[0].should be 204 + response[1]["Allow"].should include "GET" end it "the edit action return an HTML form for editing a post in response of a GET request" do response = http_options_request("/posts/1/edit") - assert response.kind_of?(Array) - assert allows?(response[1], "GET") + validate_response(response) + response[0].should be 204 + response[1]["Allow"].should include "GET" end it "the update action uses PUT to update a specific post" do response = http_options_request("/posts/1") - assert response.kind_of?(Array) - assert allows?(response[1], "PUT") + validate_response(response) + response[0].should be 204 + response[1]["Allow"].should include "PUT" end it "the destroy action uses DELETE to delete a specific post" do response = http_options_request("/posts/1") - assert response.kind_of?(Array) - assert allows?(response[1], "DELETE") + validate_response(response) + response[0].should be 204 + response[1]["Allow"].should include "DELETE" end - it "not finding a path, return 404 Not Found" do + it "not finding a path, gently return 404 Not Found" do response = http_options_request("/sblingers/sblongers") - assert response.kind_of?(Array) - assert response[0].should be 404 + validate_response(response) + response[0].should be 404 end - ## - # Note that extension relation types are REQUIRED to be absolute URIs - # in Link headers, and MUST be quoted if they contain a semicolon (";") - # or comma (",") (as these characters are used as delimiters in the - # header itself). - it "the Link header MUST be quoted if it contains a semicolon or comma" do - response = http_options_request("/posts") - assert response.kind_of?(Array) - link = response[1]["Link"] - assert link.should =~ /\A"{1}.+"\z/ + + after(:all) do + Rails.application.reload_routes! end end - describe "named routes" do + describe "resources routing with options" do - before(:each) do - ActionController::Routing::Routes.draw do |map| - map.login 'login', :controller => 'accounts', :action => 'login' + before(:all) do + rails_app.routes.draw do + resources :products do + member do + get :short + post :toggle + end + collection do + get :sold + end + end end end - it "should work" do - response = http_options_request("/login") - assert response.kind_of?(Array) - assert response[0].should be 204 - assert allows?(response[1], "GET") # WTF? return ANY?!? ;p + it "a GET member example should work" do + response = http_options_request("/products/123/short") + validate_response(response) + response[0].should be 204 + response[1]["Allow"].should include "GET" end + it "a POST member example should work" do + response = http_options_request("/products/123/toggle") + validate_response(response) + response[0].should be 204 + response[1]["Allow"].should include "POST" + end + + it "a named route with options should work" do + response = http_options_request("/products/sold") + validate_response(response) + response[0].should be 204 + response[1]["Allow"].should include "GET" + end + after(:all) do - ActionController::Routing::Routes.reload! + Rails.application.reload_routes! end end - describe "route globbing" do + describe "resources routing with sub-resources" do before(:all) do - ActionController::Routing::Routes.draw do |map| - map.connect '*path' , :controller => 'blog' , :action => 'unrecognized?' + rails_app.routes.draw do + resources :products do + resources :sales + resource :seller + end end end - it "should work" do - pending "What the hell is that?" - response = http_options_request("/post/path") - assert response.kind_of?(Array) - assert response[0].should_not be 404 + it "the parent resource collection does listing and creation" do + response = http_options_request("/products") + validate_response(response) + response[0].should be 204 + response[1]["Allow"].should include "GET" + response[1]["Allow"].should include "POST" end - after(:all) do - ActionController::Routing::Routes.reload! + it "the parent resource collection have an entry point for creating a new entry" do + pending "check regexp" + response = http_options_request("/products/new") + validate_response(response) + response[0].should be 204 + response[1]["Allow"].should include "GET" + response[1]["Allow"].should_not include "POST" + response[1]["Allow"].should_not include "PUT" + response[1]["Allow"].should_not include "DELETE" end - end + it "the parent resource collection have an entry point for editing an existing entry" do + response = http_options_request("/products/123/edit") + validate_response(response) + response[0].should be 204 + response[1]["Allow"].should include "GET" + response[1]["Allow"].should_not include "POST" + response[1]["Allow"].should_not include "PUT" + response[1]["Allow"].should_not include "DELETE" + end - describe "route conditions" do + it "the parent resource collection let its entries be read, updated and deleted" do + response = http_options_request("/products/123") + validate_response(response) + response[0].should be 204 + response[1]["Allow"].should include "GET" + response[1]["Allow"].should include "PUT" + response[1]["Allow"].should include "DELETE" + end - before(:all) do - ActionController::Routing::Routes.draw do |map| - map.connect 'post/:id', :controller => 'posts', :action => 'show', :conditions => { :method => :get } - map.connect 'post/:id', :controller => 'posts', :action => 'create_comment', :conditions => { :method => :post } - end + it "the parent resource collection let its sub-resource to be created, read, updated and deleted" do + response = http_options_request("/products/123/seller") + validate_response(response) + response[0].should be 204 + response[1]["Allow"].should include "POST" + response[1]["Allow"].should include "GET" + response[1]["Allow"].should include "PUT" + response[1]["Allow"].should include "DELETE" end - it "should work" do - response = http_options_request("/post/123") - assert response.kind_of?(Array) - assert allows?(response[1], "GET") - assert allows?(response[1], "POST") + it "the parent resource collection offers its sub-resource an entry point for creating a new entry" do + response = http_options_request("/products/123/seller/new") + validate_response(response) + response[0].should be 204 + response[1]["Allow"].should include "GET" + response[1]["Allow"].should_not include "POST" + response[1]["Allow"].should_not include "PUT" + response[1]["Allow"].should_not include "DELETE" end + it "the parent resource collection offers its sub-resource an entry point for editing the existing entry" do + response = http_options_request("/products/123/seller/edit") + validate_response(response) + response[0].should be 204 + response[1]["Allow"].should include "GET" + response[1]["Allow"].should_not include "POST" + response[1]["Allow"].should_not include "PUT" + response[1]["Allow"].should_not include "DELETE" + end + + it "the sub-resource collection behaves like a common resource collection" do + response = http_options_request("/products/123/sales") + validate_response(response) + response[0].should be 204 + response[1]["Allow"].should include "GET" + response[1]["Allow"].should include "POST" + response[1]["Allow"].should_not include "PUT" + response[1]["Allow"].should_not include "DELETE" + end + + it "the sub-resource collection have an entry point for creating a new entry" do + pending "check regexp" + response = http_options_request("/products/123/sales/new") + validate_response(response) + response[0].should be 204 + response[1]["Allow"].should include "GET" + response[1]["Allow"].should_not include "POST" + response[1]["Allow"].should_not include "PUT" + response[1]["Allow"].should_not include "DELETE" + end + + it "the sub-resource collection have an entry point for editing an existing entry" do + response = http_options_request("/products/123/sales/123/edit") + validate_response(response) + response[0].should be 204 + response[1]["Allow"].should include "GET" + response[1]["Allow"].should_not include "POST" + response[1]["Allow"].should_not include "PUT" + response[1]["Allow"].should_not include "DELETE" + end + + it "the sub-resource collection let its entries be read, updated and deleted" do + response = http_options_request("/products/123/sales/456") + validate_response(response) + response[0].should be 204 + response[1]["Allow"].should include "GET" + response[1]["Allow"].should include "PUT" + response[1]["Allow"].should include "DELETE" + response[1]["Allow"].should_not include "POST" + end + after(:all) do - ActionController::Routing::Routes.reload! + Rails.application.reload_routes! end end - describe "pretty URLs" do + describe "resources routing with more complex sub-resources" do before(:all) do - ActionController::Routing::Routes.draw do |map| - map.connect "articles/:year/:month/:day", :controller => 'articles', :action => 'find_by_date', :requirements => { :year => /\d{4}/, :month => /\d{1,2}/, :day => /\d{1,2}/ } + rails_app.routes.draw do + resources :products do + resources :sales do + get :recent, :on => :collection + end + end end end - it "should work" do - response = http_options_request("/articles/2010/07/23") - assert response.kind_of?(Array) - assert response[0].should be 204 + it "blah" do + response = http_options_request("/products/123/sales/recent.xml") + validate_response(response) + response[0].should be 204 + response[1]["Allow"].should include "GET" end after(:all) do - ActionController::Routing::Routes.reload! + Rails.application.reload_routes! end - end - describe "regular expressions and parameters" do + describe "resources routing within a namespace" do before(:all) do - ActionController::Routing::Routes.draw do |map| - map.geocode 'geocode/:postalcode', :controller => 'geocode', :action => 'show', :requirements => { :postalcode => /\d{5}(-\d{4})?/ } + rails_app.routes.draw do + namespace :admin do + resources :products + end end end - it "should work" do - response = http_options_request("/geocode/20100") - assert response.kind_of?(Array) - assert response[0].should be 204 - assert allows?(response[1], "GET") + it "a simple matching should work" do + response = http_options_request("/admin/products/123") + validate_response(response) + response[0].should be 204 + response[1]["Allow"].should include "GET" end after(:all) do - ActionController::Routing::Routes.reload! + Rails.application.reload_routes! end end - describe "resource route within a namespace" do + describe "custom regular routing" do before(:all) do - ActionController::Routing::Routes.draw do |map| - map.namespace :admin do |admin| - # Directs /admin/posts/* to Admin::PostsController (app/controllers/admin/posts_controller.rb) - admin.resources :posts - end + rails_app.routes.draw do + match 'products/:id' => 'catalog#view' end end - it "must understand an namespaced path" do - response = http_options_request("/admin/posts") - assert response.kind_of?(Array) - assert response[0].should be 204 - assert allows?(response[1], "GET") - assert allows?(response[1], "POST") + it "a simple matching should work" do + response = http_options_request("/products/123") + validate_response(response) + response[0].should be 204 + response[1]["Allow"].should include "GET" end after(:all) do - ActionController::Routing::Routes.reload! + Rails.application.reload_routes! end end - describe "deal the catch all" do + describe "the root" do before(:all) do - ActionController::Routing::Routes.draw do |map| - map.resources :posts - map.connect ':controller/:action/:id' + rails_app.routes.draw do + root :to => "welcome#index" end end - it "must cheat :P" do - response = http_options_request("/posts") - assert response.kind_of?(Array) - assert response[0].should be 204 - assert allows?(response[1], "GET") - assert allows?(response[1], "POST") + it " / should work" do + response = http_options_request("/") + validate_response(response) + response[0].should be 204 + response[1]["Allow"].should include "GET" end after(:all) do - ActionController::Routing::Routes.reload! + Rails.application.reload_routes! end end - - describe "another sample of named route" do + + describe "the legacy 'WILD' controller" do + before(:all) do - ActionController::Routing::Routes.draw do |map| - map.purchase 'products/:id/purchase', :controller => 'catalog', :action => 'purchase' + rails_app.routes.draw do + match ':controller(/:action(/:id(.:format)))' end end - it "should work" do - response = http_options_request("/products/123/purchase") - assert response.kind_of?(Array) - assert response[0].should be 204 - assert allows?(response[1], "ANY") + it "a simple matching should work" do + response = http_options_request("/products/show/123.json") + validate_response(response) + response[0].should be 204 + response[1]["Allow"].should include "GET" end after(:all) do - ActionController::Routing::Routes.reload! + Rails.application.reload_routes! end end - describe "Sample resource route with options" do - before(:all) do - ActionController::Routing::Routes.draw do |map| - map.resources :products, :member => { :short => :get, :toggle => :post }, :collection => { :sold => :get } + + end + + context "Link" do + + describe "should not be present" do + + before(:each) do + rails_app.routes.draw do + resources :posts end end - it "should work" do - response = http_options_request("/products/123/toggle") - assert response.kind_of?(Array) - assert response[0].should be 204 - assert allows?(response[1], "POST") + it "if no directions were given" do + FileUtils.mv File.join(Rails.root, 'config', 'optionsful.yml'), File.join(Rails.root, 'optionsful.yml') + response = http_options_request("/posts") + FileUtils.mv File.join(Rails.root, 'optionsful.yml'), File.join(Rails.root, 'config', 'optionsful.yml') + validate_response(response) + response[0].should be 204 + response[1]["Link"].should be nil end - it "should work" do - response = http_options_request("/products/123/short") - assert response.kind_of?(Array) - assert response[0].should be 204 - assert allows?(response[1], "GET") + after(:each) do + Rails.application.reload_routes! end - it "should work" do - response = http_options_request("/products/sold") - assert response.kind_of?(Array) - assert response[0].should be 204 - assert allows?(response[1], "GET") + end + + describe "behave arbitrarily if directions were given" do + + before(:all) do + rails_app.routes.draw do + resources :posts + end end + it "the Link header MUST be quoted if it contains a semicolon or comma" do + response = http_options_request("/posts") + validate_response(response) + response[0].should be 204 + link = response[1]["Link"] + link.should match /\A\".+\"\z/ + end + after(:all) do - ActionController::Routing::Routes.reload! + Rails.application.reload_routes! end end end end - -