summaryrefslogtreecommitdiffstats
path: root/spec/unit/network/http/webrick/rest_spec.rb
blob: 267ddcc722371ed47399c726122a3e584d5b9b56 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
#!/usr/bin/env rspec
require 'spec_helper'
require 'puppet/network/http'
require 'webrick'
require 'puppet/network/http/webrick/rest'

describe Puppet::Network::HTTP::WEBrickREST do
  it "should include the Puppet::Network::HTTP::Handler module" do
    Puppet::Network::HTTP::WEBrickREST.ancestors.should be_include(Puppet::Network::HTTP::Handler)
  end

  describe "when initializing" do
    it "should call the Handler's initialization hook with its provided arguments as the server and handler" do
      Puppet::Network::HTTP::WEBrickREST.any_instance.expects(:initialize_for_puppet).with(:server => "my", :handler => "arguments")
      Puppet::Network::HTTP::WEBrickREST.new("my", "arguments")
    end
  end

  describe "when receiving a request" do
    before do
      @request     = stub('webrick http request', :query => {}, :peeraddr => %w{eh boo host ip}, :client_cert => nil)
      @response    = stub('webrick http response', :status= => true, :body= => true)
      @model_class = stub('indirected model class')
      @webrick     = stub('webrick http server', :mount => true, :[] => {})
      Puppet::Indirector::Indirection.stubs(:model).with(:foo).returns(@model_class)
      @handler = Puppet::Network::HTTP::WEBrickREST.new(@webrick, :foo)
    end

    it "should delegate its :service method to its :process method" do
      @handler.expects(:process).with(@request, @response).returns "stuff"
      @handler.service(@request, @response).should == "stuff"
    end

    describe "when using the Handler interface" do
      it "should use the 'accept' request parameter as the Accept header" do
        @request.expects(:[]).with("accept").returns "foobar"
        @handler.accept_header(@request).should == "foobar"
      end

      it "should use the 'content-type' request header as the Content-Type header" do
        @request.expects(:[]).with("content-type").returns "foobar"
        @handler.content_type_header(@request).should == "foobar"
      end

      it "should use the request method as the http method" do
        @request.expects(:request_method).returns "FOO"
        @handler.http_method(@request).should == "FOO"
      end

      it "should return the request path as the path" do
        @request.expects(:path).returns "/foo/bar"
        @handler.path(@request).should == "/foo/bar"
      end

      it "should return the request body as the body" do
        @request.expects(:body).returns "my body"
        @handler.body(@request).should == "my body"
      end

      it "should set the response's 'content-type' header when setting the content type" do
        @response.expects(:[]=).with("content-type", "text/html")
        @handler.set_content_type(@response, "text/html")
      end

      it "should set the status and body on the response when setting the response for a successful query" do
        @response.expects(:status=).with 200
        @response.expects(:body=).with "mybody"

        @handler.set_response(@response, "mybody", 200)
      end

      describe "when the result is a File" do
        before(:each) do
          stat = stub 'stat', :size => 100
          @file = stub 'file', :stat => stat, :path => "/tmp/path"
          @file.stubs(:is_a?).with(File).returns(true)
        end

        it "should serve it" do
          @response.stubs(:[]=)

          @response.expects(:status=).with 200
          @response.expects(:body=).with @file

          @handler.set_response(@response, @file, 200)
        end

        it "should set the Content-Length header" do
          @response.expects(:[]=).with('content-length', 100)

          @handler.set_response(@response, @file, 200)
        end
      end

      it "should set the status and message on the response when setting the response for a failed query" do
        @response.expects(:status=).with 400
        @response.expects(:reason_phrase=).with "mybody"

        @handler.set_response(@response, "mybody", 400)
      end
    end

    describe "and determining the request parameters" do
      it "should include the HTTP request parameters, with the keys as symbols" do
        @request.stubs(:query).returns("foo" => "baz", "bar" => "xyzzy")
        result = @handler.params(@request)
        result[:foo].should == "baz"
        result[:bar].should == "xyzzy"
      end

      it "should CGI-decode the HTTP parameters" do
        encoding = CGI.escape("foo bar")
        @request.expects(:query).returns('foo' => encoding)
        result = @handler.params(@request)
        result[:foo].should == "foo bar"
      end

      it "should convert the string 'true' to the boolean" do
        @request.expects(:query).returns('foo' => "true")
        result = @handler.params(@request)
        result[:foo].should be_true
      end

      it "should convert the string 'false' to the boolean" do
        @request.expects(:query).returns('foo' => "false")
        result = @handler.params(@request)
        result[:foo].should be_false
      end

      it "should YAML-load and CGI-decode values that are YAML-encoded" do
        escaping = CGI.escape(YAML.dump(%w{one two}))
        @request.expects(:query).returns('foo' => escaping)
        result = @handler.params(@request)
        result[:foo].should == %w{one two}
      end

      it "should not allow clients to set the node via the request parameters" do
        @request.stubs(:query).returns("node" => "foo")
        @handler.stubs(:resolve_node)

        @handler.params(@request)[:node].should be_nil
      end

      it "should not allow clients to set the IP via the request parameters" do
        @request.stubs(:query).returns("ip" => "foo")
        @handler.params(@request)[:ip].should_not == "foo"
      end

      it "should pass the client's ip address to model find" do
        @request.stubs(:peeraddr).returns(%w{noidea dunno hostname ipaddress})
        @handler.params(@request)[:ip].should == "ipaddress"
      end

      it "should set 'authenticated' to true if a certificate is present" do
        cert = stub 'cert', :subject => [%w{CN host.domain.com}]
        @request.stubs(:client_cert).returns cert
        @handler.params(@request)[:authenticated].should be_true
      end

      it "should set 'authenticated' to false if no certificate is present" do
        @request.stubs(:client_cert).returns nil
        @handler.params(@request)[:authenticated].should be_false
      end

      it "should pass the client's certificate name to model method if a certificate is present" do
        cert = stub 'cert', :subject => [%w{CN host.domain.com}]
        @request.stubs(:client_cert).returns cert
        @handler.params(@request)[:node].should == "host.domain.com"
      end

      it "should resolve the node name with an ip address look-up if no certificate is present" do
        @request.stubs(:client_cert).returns nil

        @handler.expects(:resolve_node).returns(:resolved_node)

        @handler.params(@request)[:node].should == :resolved_node
      end
    end
  end
end