require "spec_helper" require "sham_rack" require "sham_rack/patron" require "open-uri" require "restclient" require "mechanize" require "rack" describe ShamRack do class NetHttpProhibited < StandardError; end before do any_instance_of(Net::HTTP) do |http| stub(http).start do raise NetHttpProhibited, "real network calls are not allowed" end end end after(:each) do ShamRack.unmount_all end describe "mounted Rack application" do before(:each) do ShamRack.mount(GreetingApp.new, "www.greetings.com") end it "can be accessed using Net::HTTP" do response = Net::HTTP.start("www.greetings.com") do |http| http.request(Net::HTTP::Get.new("/")) end response.body.should == "Hello, world" end it "can be accessed using Net::HTTP#get_response" do response = Net::HTTP.get_response(URI.parse("http://www.greetings.com/")) response.body.should == "Hello, world" end it "can be accessed using open-uri" do response = open("http://www.greetings.com") response.status.should == ["200", "OK"] response.read.should == "Hello, world" end it "can be accessed using RestClient" do response = RestClient.get("http://www.greetings.com") response.code.should == 200 response.to_s.should == "Hello, world" end it "can be accessed using Mechanize" do response = Mechanize.new.get("http://www.greetings.com") response.body.should == "Hello, world" end it "can be accessed using Patron" do patron = Patron::Session.new response = patron.get("http://www.greetings.com/foo/bar") response.body.should == "Hello, world" end end describe ".at" do context "with a block" do it "mounts associated block as an app" do ShamRack.at("simple.xyz") do |env| ["200 OK", { "Content-type" => "text/plain" }, ["Easy, huh?"]] end open("http://simple.xyz").read.should == "Easy, huh?" end end context "with a URL" do it "raises an ArgumentError" do lambda do ShamRack.at("http://www.greetings.com") end.should raise_error(ArgumentError, "invalid address") end end describe "#mount" do it "mounts an app" do ShamRack.at("hello.xyz").mount(GreetingApp.new) open("http://hello.xyz").read.should == "Hello, world" end end describe "#unmount" do it "deregisters a mounted app" do ShamRack.at("gone.xyz").mount(GreetingApp.new) ShamRack.at("gone.xyz").unmount lambda do open("http://gone.xyz").read end.should raise_error(NetHttpProhibited) end end describe "#rackup" do before do @return_value = ShamRack.at("rackup.xyz").rackup do use UpcaseBody run GreetingApp.new end end it "mounts an app created using Rack::Builder" do open("http://rackup.xyz").read.should == "HELLO, WORLD" end it "returns the app" do @return_value.should respond_to(:call) end end describe "#sinatra" do before do @return_value = ShamRack.at("sinatra.xyz").sinatra do get "/hello/:subject" do "Hello, #{params[:subject]}" end end end it "mounts associated block as a Sinatra app" do open("http://sinatra.xyz/hello/stranger").read.should == "Hello, stranger" end it "returns the app" do @return_value.should respond_to(:call) end end describe "#stub" do before do @return_value = ShamRack.at("stubbed.xyz").stub end it "mounts a StubWebService" do ShamRack.application_for("stubbed.xyz").should be_kind_of(ShamRack::StubWebService) end it "returns the StubWebService" do @return_value.should == ShamRack.application_for("stubbed.xyz") end end end describe ".mount" do it "is deprecated, but still works" do ShamRack.mount(GreetingApp.new, "hello.xyz") open("http://hello.xyz").read.should == "Hello, world" end end describe "response" do before(:each) do ShamRack.at("www.greetings.com") do [ "456 Foo Bar", { "Content-Type" => "text/plain", "X-Foo" => "bar" }, ["BODY"] ] end end let(:response) { Net::HTTP.get_response(URI.parse("http://www.greetings.com/")) } it "has status returned by app" do response.code.should == "456" end it "has status message returned by app" do response.message.should == "Foo Bar" end it "has body returned by app" do response.body.should == "BODY" end it "has Content-Type returned by app" do response.content_type.should == "text/plain" end it "has other headers returned by app" do response["x-foo"].should =="bar" end context "when the app returns a numeric status" do before(:each) do ShamRack.at("www.greetings.com") do [ 201, { "Content-Type" => "text/plain" }, ["BODY"] ] end @response = Net::HTTP.get_response(URI.parse("http://www.greetings.com/")) end it "has status returned by app" do response.code.should == "201" end it "derives a status message" do response.message.should == "Created" end end end describe "Rack environment" do before(:each) do @env_recorder = recorder = EnvRecorder.new(GreetingApp.new) ShamRack.at("env.xyz").rackup do use Rack::Lint run recorder end end def env @env_recorder.last_env end it "is valid" do open("http://env.xyz/blah?q=abc") env["REQUEST_METHOD"].should == "GET" env["SCRIPT_NAME"].should == "" env["PATH_INFO"].should == "/blah" env["QUERY_STRING"].should == "q=abc" env["SERVER_NAME"].should == "env.xyz" env["SERVER_PORT"].should == "80" env["rack.version"].should be_kind_of(Array) env["rack.url_scheme"].should == "http" env["rack.multithread"].should == true env["rack.multiprocess"].should == true env["rack.run_once"].should == false end it "provides request headers" do Net::HTTP.start("env.xyz") do |http| request = Net::HTTP::Get.new("/") request["Foo-bar"] = "baz" http.request(request) end env["HTTP_FOO_BAR"].should == "baz" end it "supports POST" do RestClient.post("http://env.xyz/resource", "q" => "rack") env["REQUEST_METHOD"].should == "POST" env["CONTENT_TYPE"].should == "application/x-www-form-urlencoded" env["rack.input"].read.should == "q=rack" end it "supports POST using Net::HTTP" do Net::HTTP.start("env.xyz") do |http| http.post("/resource", "q=rack") end env["REQUEST_METHOD"].should == "POST" env["rack.input"].read.should == "q=rack" end it "supports POST using Patron" do patron = Patron::Session.new response = patron.post("http://env.xyz/resource", "", "Content-Type" => "application/xml") response.status.should == 200 env["REQUEST_METHOD"].should == "POST" env["rack.input"].read.should == "" env["CONTENT_TYPE"].should == "application/xml" end it "supports PUT" do RestClient.put("http://env.xyz/thing1", "stuff", :content_type => "text/plain") env["REQUEST_METHOD"].should == "PUT" env["CONTENT_TYPE"].should == "text/plain" env["rack.input"].read.should == "stuff" end it "supports PUT using Patron" do patron = Patron::Session.new response = patron.put("http://env.xyz/resource", "stuff", "Content-Type" => "text/plain") env["REQUEST_METHOD"].should == "PUT" env["CONTENT_TYPE"].should == "text/plain" env["rack.input"].read.should == "stuff" end it "supports DELETE" do RestClient.delete("http://env.xyz/thing/1") env["REQUEST_METHOD"].should == "DELETE" env["PATH_INFO"].should == "/thing/1" end it "supports DELETE using Patron" do patron = Patron::Session.new response = patron.delete("http://env.xyz/resource") env["REQUEST_METHOD"].should == "DELETE" env["PATH_INFO"].should == "/resource" end end end