spec/praxis/router_spec.rb in praxis-0.11.2 vs spec/praxis/router_spec.rb in praxis-0.13.0

- old
+ new

@@ -12,15 +12,15 @@ let(:args){ {} } it 'defaults to no version' do expect( matcher.instance_variable_get(:@version) ).to eq("n/a") end end - + context '.call' do let(:env){ {"HTTP_X_API_VERSION" => request_version } } let(:request) {Praxis::Request.new(env)} - + #let(:request){ double("request", version: request_version, env: env ) } context 'with matching versions' do let(:request_version) { "1.0" } it 'calls the target' do expect( target ).to receive(:call).with(request) @@ -40,17 +40,18 @@ end end end end + describe Praxis::Router::RequestRouter do let(:request) {double("request", route_params: '', path: 'path')} let(:callback) {double("callback")} - + subject(:request_router) {Praxis::Router::RequestRouter.new} - + context ".invoke" do it "update request and call request for callback" do allow(request).to receive(:route_params=) allow(callback).to receive(:call).and_return(1) @@ -89,66 +90,143 @@ expect(args).to be_kind_of(Hash) expect(args[:call]).to be_kind_of(Praxis::Router::VersionMatcher) end router.add_route(target ,route) end - + it "raises warning when options are specified in route" do expect(router.add_route(proc {'target'},route)).to eq(['path']) end end context ".call" do - let(:env){ {"PATH_INFO"=>"/"} } + let(:env){ {"PATH_INFO"=>request_path_info, "REQUEST_METHOD"=>request_verb} } + let(:request_verb) { 'POST' } + let(:request_path_info) { '/' } let(:request_version){ nil } let(:request) {Praxis::Request.new(env)} let(:router_response){ 1 } - + let(:router_response_for_post){ "POST result" } + let(:router_response_for_wildcard){ "* result" } + let(:post_target_router){ double("POST target", call: router_response_for_post) } + let(:any_target_router){ double("ANY target", call: router_response_for_wildcard) } before do env['HTTP_X_API_VERSION'] = request_version if request_version allow_any_instance_of(Praxis::Router::RequestRouter). to receive(:call).with(request).and_return(router_response) + router.add_route(double("P"),double("route1", verb: 'POST', path: '/', options: {} , version: request_version)) + # Hijack the callable block in the routes (since there's no way to point back to the registered route object) + router.instance_variable_get( :@routes )['POST'] = post_target_router + end - - it "calls the route with params request" do - expect(router.call(request)).to eq(router_response) + + context 'for routes without wildcards (a single POST route)' do + + context 'and an incoming POST request' do + it "finds a match and invokes it the route" do + expect(router.call(request)).to eq(router_response_for_post) + end + end + context 'and an incoming PUT request' do + let(:request_verb) { 'PUT' } + it "does not find a route" do + response_code, _ , _ = router.call(request) + expect(response_code).to be(404) + end + end end + context 'for routes with wildcards (a POST and a * route)' do + before do + router.add_route(double("*"),double("route2", verb: 'ANY', path: '/*', options: {} , version: request_version)) + # Hijack the callable block in the routes (since there's no way to point back to the registered route object) + router.instance_variable_get( :@routes )['ANY'] = any_target_router + end + + context 'and an incoming PUT request' do + let(:request_verb) { 'PUT' } + it "it can successfully find a match using the wildcard target" do + expect(router.call(request)).to eq(router_response_for_wildcard) + end + end + context 'and an incoming POST request' do + it 'matches the most specific POST route, rather than the wildcard'do + expect(router.call(request)).to eq(router_response_for_post) + end + end + context 'and an incoming POST request (but that does not match other route conditions)' do + let(:router_response_for_post){ :not_found } + it 'still matches wildcard verb if that was route conditions-compatible' do + expect(post_target_router).to receive(:call).once # try the match cause it's a POST + expect(any_target_router).to receive(:call).once # fallback to wildcard upon a not_found + expect(router.call(request)).to eq(router_response_for_wildcard) + end + end + end + context "when not_found is returned" do + let(:request_verb) { 'DELETE' } let(:router_response){ :not_found } - before{ request.instance_variable_set(:@unmatched_versions, unmatched_versions) } - context "having passed no version in the request" do - - context 'and no controllers matching the path' do - let(:unmatched_versions){ Set.new([]) } - it 'returns a basic "NotFound" response: 404 status, text/plain content and "NotFound" body' do - expect( router.call(request) ).to eq([404, {"Content-Type" => "text/plain", }, ["NotFound"]]) - end + + it 'sets X-Cascade: pass by default' do + _, headers, _ = router.call(request) + expect(headers).to have_key('X-Cascade') + expect(headers['X-Cascade']).to eq('pass') + end + + context 'with X-Cascade disabled' do + let(:config) { Praxis::Application.instance.config.praxis } + before do + expect(config).to receive(:x_cascade).and_return(false) end - - context 'and some controllers matching the path' do - let(:unmatched_versions){ Set.new(["1.0"]) } - it 'returns a specific body response noting which request versions would matched if passed in' do - _, _, body = router.call(request) - expect( body.first ).to eq('NotFound. Your request did not specify an API version. Available versions = "1.0".') - end + + it 'does not set X-Cascade: pass' do + _, headers, _ = router.call(request) + expect(headers).to_not have_key("X-Cascade") end + end - - context "having passed a version in the request" do - - context 'but having no controllers matching the path part' do - let(:request_version){ "50.0" } - let(:unmatched_versions){ Set.new(["1.0","2.0"]) } - - it 'returns a specific body response noting that the version might be wrong (and which could be right)' do - code, headers, body = router.call(request) - expect(code).to eq(404) - expect(headers['Content-Type']).to eq('text/plain') - expect(body.first).to eq("NotFound. Your request speficied API version = \"#{request_version}\". Available versions = \"1.0\", \"2.0\".") + + context 'with versioning' do + before do + request.instance_variable_set(:@unmatched_versions, unmatched_versions) + end + + context "having passed no version in the request" do + context 'and no controllers matching the path' do + let(:unmatched_versions) { Set.new([]) } + + it 'returns a basic "NotFound" response: 404 status, text/plain content and "NotFound" body' do + expect( router.call(request) ).to eq([404, {"Content-Type" => "text/plain","X-Cascade"=>"pass"}, ["NotFound"]]) + end end + + context 'and some controllers matching the path' do + let(:unmatched_versions) { Set.new(["1.0"]) } + it 'returns a specific body response noting which request versions would matched if passed in' do + _, _, body = router.call(request) + expect( body.first ).to eq('NotFound. Your request did not specify an API version. Available versions = "1.0".') + end + end end + + context "having passed a version in the request" do + + context 'but having no controllers matching the path part' do + let(:request_version) { "50.0" } + let(:unmatched_versions) { Set.new(["1.0","2.0"]) } + + it 'returns a specific body response noting that the version might be wrong (and which could be right)' do + code, headers, body = router.call(request) + expect(code).to eq(404) + expect(headers['Content-Type']).to eq('text/plain') + expect(body.first).to eq("NotFound. Your request speficied API version = \"#{request_version}\". Available versions = \"1.0\", \"2.0\".") + end + end + end end + + end end end