This is the first main phase to having a common module for handling the REST api - this Handler module will be included by all of the web server REST modules and the Indirector Request class, so there's a common place that understands how the URI consists.
Signed-off-by: Luke Kanies <[email protected]> --- lib/puppet/network/http/handler.rb | 46 ++++++++++++++++ lib/puppet/node/environment.rb | 4 ++ spec/unit/network/http/handler.rb | 101 ++++++++++++++++++++++++++++++++++++ spec/unit/node/environment.rb | 4 ++ 4 files changed, 155 insertions(+), 0 deletions(-) diff --git a/lib/puppet/network/http/handler.rb b/lib/puppet/network/http/handler.rb index 7f6bd41..1e52816 100644 --- a/lib/puppet/network/http/handler.rb +++ b/lib/puppet/network/http/handler.rb @@ -2,6 +2,22 @@ module Puppet::Network::HTTP end module Puppet::Network::HTTP::Handler + + # How we map http methods and the indirection name in the URI + # to an indirection method. + METHOD_MAP = { + "GET" => { + :plural => :search, + :singular => :find + }, + "PUT" => { + :singular => :save + }, + "DELETE" => { + :singular => :destroy + } + } + attr_reader :model, :server, :handler # Retrieve the accept header from the http request. @@ -43,6 +59,36 @@ module Puppet::Network::HTTP::Handler return do_exception(response, e) end + def uri2indirection(http_method, uri, params) + environment, indirection, key = uri.split("/", 4)[1..-1] # the first field is always nil because of the leading slash + + raise ArgumentError, "The environment must be purely alphanumeric, not '%s'" % environment unless environment =~ /^\w+$/ + raise ArgumentError, "The indirection name must be purely alphanumeric, not '%s'" % indirection unless indirection =~ /^\w+$/ + + plurality = (indirection == handler.to_s + "s") ? :plural : :singular + + unless METHOD_MAP[http_method] + raise ArgumentError, "No support for http method %s" % http_method + end + + unless method = METHOD_MAP[http_method][plurality] + raise ArgumentError, "No support for plural %s operations" % http_method + end + + indirection.sub!(/s$/, '') if plurality == :plural + + params[:environment] = environment + + key = URI.unescape(key) + + Puppet::Indirector::Request.new(indirection, method, key, params) + end + + def indirection2uri(request) + indirection = request.method == :search ? request.indirection_name.to_s + "s" : request.indirection_name.to_s + "/#{request.environment.to_s}/#{indirection}/#{request.escaped_key}#{request.query_string}" + end + # Are we interacting with a singular instance? def singular?(request) %r{/#{handler.to_s}$}.match(path(request)) diff --git a/lib/puppet/node/environment.rb b/lib/puppet/node/environment.rb index 57dc23e..445439a 100644 --- a/lib/puppet/node/environment.rb +++ b/lib/puppet/node/environment.rb @@ -61,4 +61,8 @@ class Puppet::Node::Environment end result end + + def to_s + name.to_s + end end diff --git a/spec/unit/network/http/handler.rb b/spec/unit/network/http/handler.rb index 6f1a57b..fc73cc1 100755 --- a/spec/unit/network/http/handler.rb +++ b/spec/unit/network/http/handler.rb @@ -12,6 +12,107 @@ describe Puppet::Network::HTTP::Handler do @handler = HttpHandled.new end + it "should be able to convert a URI into a request" do + @handler.should respond_to(:uri2indirection) + end + + it "should be able to convert a request into a URI" do + @handler.should respond_to(:indirection2uri) + end + + describe "when converting a URI into a request" do + before do + @handler.stubs(:handler).returns "foo" + end + + it "should require the http method, the URI, and the query parameters" do + # Not a terribly useful test, but an important statement for the spec + lambda { @handler.uri2indirection("/foo") }.should raise_error(ArgumentError) + end + + it "should use the first field of the URI as the environment" do + @handler.uri2indirection("GET", "/env/foo/bar", {}).environment.should == Puppet::Node::Environment.new("env") + end + + it "should fail if the environment is not alphanumeric" do + lambda { @handler.uri2indirection("GET", "/env ness/foo/bar", {}) }.should raise_error(ArgumentError) + end + + it "should use the environment from the URI even if one is specified in the parameters" do + @handler.uri2indirection("GET", "/env/foo/bar", {:environment => "otherenv"}).environment.should == Puppet::Node::Environment.new("env") + end + + it "should use the second field of the URI as the indirection name" do + @handler.uri2indirection("GET", "/env/foo/bar", {}).indirection_name.should == :foo + end + + it "should fail if the indirection name is not alphanumeric" do + lambda { @handler.uri2indirection("GET", "/env/foo ness/bar", {}) }.should raise_error(ArgumentError) + end + + it "should use the remainder of the URI as the indirection key" do + @handler.uri2indirection("GET", "/env/foo/bar", {}).key.should == "bar" + end + + it "should support the indirection key being a /-separated file path" do + @handler.uri2indirection("GET", "/env/foo/bee/baz/bomb", {}).key.should == "bee/baz/bomb" + end + + it "should choose 'find' as the indirection method if the http method is a GET and the indirection name is singular" do + @handler.uri2indirection("GET", "/env/foo/bar", {}).method.should == :find + end + + it "should choose 'search' as the indirection method if the http method is a GET and the indirection name is plural" do + @handler.uri2indirection("GET", "/env/foos/bar", {}).method.should == :search + end + + it "should choose 'delete' as the indirection method if the http method is a DELETE and the indirection name is singular" do + @handler.uri2indirection("DELETE", "/env/foo/bar", {}).method.should == :destroy + end + + it "should choose 'save' as the indirection method if the http method is a PUT and the indirection name is singular" do + @handler.uri2indirection("PUT", "/env/foo/bar", {}).method.should == :save + end + + it "should fail if an indirection method cannot be picked" do + lambda { @handler.uri2indirection("UPDATE", "/env/foo/bar", {}) }.should raise_error(ArgumentError) + end + + it "should URI unescape the indirection key" do + escaped = URI.escape("foo bar") + @handler.uri2indirection("GET", "/env/foo/#{escaped}", {}).key.should == "foo bar" + end + end + + describe "when converting a request into a URI" do + before do + @request = Puppet::Indirector::Request.new(:foo, :find, "with spaces", :foo => :bar, :environment => "myenv") + end + + it "should use the environment as the first field of the URI" do + @handler.indirection2uri(@request).split("/")[1].should == "myenv" + end + + it "should use the indirection as the second field of the URI" do + @handler.indirection2uri(@request).split("/")[2].should == "foo" + end + + it "should pluralize the indirection name if the method is 'search'" do + @request.stubs(:method).returns :search + @handler.indirection2uri(@request).split("/")[2].should == "foos" + end + + it "should use the escaped key as the remainder of the URI" do + escaped = URI.escape("with spaces") + @handler.indirection2uri(@request).split("/")[3].sub(/\?.+/, '').should == escaped + end + + it "should add the query string to the URI" do + @request.expects(:query_string).returns "?query" + @handler.indirection2uri(@request).should =~ /\?query$/ + end + end + it "should have a method for initializing" do @handler.should respond_to(:initialize_for_puppet) end diff --git a/spec/unit/node/environment.rb b/spec/unit/node/environment.rb index 20889f0..dd6745f 100755 --- a/spec/unit/node/environment.rb +++ b/spec/unit/node/environment.rb @@ -19,6 +19,10 @@ describe Puppet::Node::Environment do Puppet::Node::Environment.new(:one).should equal(Puppet::Node::Environment.new("one")) end + it "should return its name when converted to a string" do + Puppet::Node::Environment.new(:one).to_s.should == "one" + end + it "should consider its module path to be the environment-specific modulepath setting" do FileTest.stubs(:directory?).returns true env = Puppet::Node::Environment.new("testing") -- 1.6.1 --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Puppet Developers" group. To post to this group, send email to [email protected] To unsubscribe from this group, send email to [email protected] For more options, visit this group at http://groups.google.com/group/puppet-dev?hl=en -~----------~----~----~----~------~----~------~--~---
