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