summaryrefslogtreecommitdiff
path: root/tests/helpers/http_helper.rb
blob: 0d0bb7d52c8987b98b71a1a17368d970aa35d9a8 (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
require 'net/http'

class LeapTest

  #
  # In order to easily provide detailed error messages, it is useful
  # to append a memo to a url string that details what this url is for
  # (e.g. stunnel, haproxy, etc).
  #
  # So, the url happens to be a UrlString, the memo field is used
  # if there is an error in assert_get.
  #
  class URLString < String
    attr_accessor :memo
  end

  #
  # aliases for http_send()
  #
  def get(url, params=nil, options=nil, &block)
    http_send("GET", url, params, options, &block)
  end
  def delete(url, params=nil, options=nil, &block)
    http_send("DELETE", url, params, options, &block)
  end
  def post(url, params=nil, options=nil, &block)
    http_send("POST", url, params, options, &block)
  end
  def put(url, params=nil, options=nil, &block)
    http_send("PUT", url, params, options, &block)
  end

  #
  # send a GET, DELETE, POST, or PUT
  # yields |body, response, error|
  #
  def http_send(method, url, params=nil, options=nil)
    options ||= {}
    response = nil

    # build uri
    uri = URI(url)
    if params && (method == 'GET' || method == 'DELETE')
      uri.query = URI.encode_www_form(params)
    end

    # build http
    http = Net::HTTP.new uri.host, uri.port
    if uri.scheme == 'https'
      http.verify_mode = OpenSSL::SSL::VERIFY_NONE
      http.use_ssl = true
    end

    # build request
    request = build_request(method, uri, params, options)

    # make http request
    http.start do |agent|
      response = agent.request(request)
      yield response.body, response, nil
    end
  rescue => exc
    yield nil, response, exc
  end

  #
  # Aliases for assert_http_send()
  #
  def assert_get(url, params=nil, options=nil, &block)
    assert_http_send("GET", url, params, options, &block)
  end
  def assert_delete(url, params=nil, options=nil, &block)
    assert_http_send("DELETE", url, params, options, &block)
  end
  def assert_post(url, params=nil, options=nil, &block)
    assert_http_send("POST", url, params, options, &block)
  end
  def assert_put(url, params=nil, options=nil, &block)
    assert_http_send("PUT", url, params, options, &block)
  end

  #
  # calls http_send, yielding results if successful or failing with
  # descriptive info otherwise.
  #
  # options:
  # - error_msg: custom error message to display.
  # - ok_codes: in addition to 2xx, codes in this array will not produce an error.
  #
  def assert_http_send(method, url, params=nil, options=nil, &block)
    options ||= {}
    error_msg = options[:error_msg] || (url.respond_to?(:memo) ? url.memo : nil)
    http_send(method, url, params, options) do |body, response, error|
      if response
        code = response.code.to_i
        ok = code >= 200 && code < 300
        if options[:ok_codes]
          ok ||= options[:ok_codes].include?(code)
        end
        if ok
          if block
            yield(body) if block.arity == 1
            yield(body, response) if block.arity == 2
            yield(body, response, error) if block.arity == 3
          end
        else
          fail ["Expected success code from #{method} #{url}, but got #{response.code} instead.", error_msg, body].compact.join("\n")
        end
      else
        fail ["Expected a response from #{method} #{url}, but got \"#{error}\" instead.", error_msg, body].compact.join("\n"), error
      end
    end
  end

  #
  # only a warning for now, should be a failure in the future
  #
  def assert_auth_fail(url, params)
    uri = URI(url)
    get(url, params) do |body, response, error|
      unless response.code.to_s == "401"
        warn "Expected a '401 Unauthorized' response, but got #{response.code} instead (GET #{uri.request_uri} with username '#{uri.user}')."
        return false
      end
    end
    true
  end

  private

  def build_request(method, uri, params, options)
    request = case method
      when "GET"    then Net::HTTP::Get.new(uri.request_uri)
      when "DELETE" then Net::HTTP::Delete.new(uri.request_uri)
      when "POST"   then Net::HTTP::Post.new(uri.request_uri)
      when "PUT"    then Net::HTTP::Put.new(uri.request_uri)
    end
    if uri.user
      request.basic_auth uri.user, uri.password
    end
    if params && (method == 'POST' || method == 'PUT')
      if options[:format] == :json || options[:format] == 'json'
        request["Content-Type"] = "application/json"
        request.body = params.to_json
      else
        request.set_form_data(params) if params
      end
    end
    if options[:headers]
      options[:headers].each do |key, value|
        request[key] = value
      end
    end
    request
  end

end