ruby assert_equal undefined method 'downcase' for 0..13:Range - ruby

I have a module called token wrapper, in which there is a method getToken:
def Tokenwrapper.getToken
uri = URI.parse("[URL REDACTED]/api/authenticate")
request = Net::HTTP::Post.new(uri)
request.basic_auth("email#domain.com", "pass")
request.content_type = "application/json"
request["Accept"] = "application/json"
req_options = {
use_ssl: uri.scheme == "https",
}
response = Net::HTTP.start(uri.hostname, uri.port, req_options) do |http|
http.request(request)
end
response
end
When I attempt to test it with the following assertion:
assert_equal("#<Net::HTTPOK:",Tokenwrapper.getToken[0..13])
I get this error:
NoMethodError: undefined method 'downcase' for 0..13:Range
I don't manually invoke the downcase method, and I don't see any reason that ruby should be doing so automatically. Why is this happening and how do I make my test run?
I'll be honest I don't know a lot about HTTP API responses and how this area of networking operates, so I'd appreciate any resources as well as answers to this question.

The response object has a [] method that provides access to a header from the response. When you're trying to do getToken[0..13] this is the method that's actually being called.
This [] is expecting a call like response['Content-Type'] and uses downcase on the value passed in in order to handle header names case insensitively.
If you want to check the first few characters from the string representation of the response you can convert the response to a string and compare it, like this:
assert_equal("#<Net::HTTPOK:",Tokenwrapper.getToken.to_s[0..13])
Alternatively, can you use an assertion on the HTTP status code, e.g.
assert_equal(200, Tokenwrapper.getToken.code)

Related

How to stub a HTTParty request inside a method for testing?

I have created a function that makes a HTTParty get request. It raises a custom error message that i need to test. I tried to stub the request using Webmock in the test but it is raising a <Net::OpenTimeout>. How can i stub the get request if the url is dynamically constructed?
def function(a , b)
# some logic , dynamic url constructed
response = HTTParty.get(url, headers: {"Content-Type" =>
"application/json"})
if response.code != 200
raise CustomError.new <<~EOF
Error while fetching job details.
Response code: #{response.code}
Response body: #{response.body}
EOF
end
JSON.parse(response.body)
for the test
def test_function
WebMock.stub_request(:get, url).with(:headers => {'Content-
Type'=>'application/json'}).to_return(:status => 500)
# HTTParty.stub(get: fake_response)
err = assert_raises CustumError do
c.function(a , b)
end
WebMock allows you to use "wildcard matching" so you can stub requests matching a regular expression:
WebMock.stub_request(:get, /example/).to_return(status: 500)

Trying to make HTTP Post request with a body using Ruby HTTP start block

I'm trying to make a POST request with basic oauth and a body param.
response = Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
request = Net::HTTP::Post.new(uri)
request['Authorization'] = 'ACCESS_CODE'
request.body = {
to: to,
subject: subject,
text: text,
api_type: 'json',
uh: #modhash
}.to_json
http.request(request)
end
It returns a
<Net::HTTPOK 200 OK readbody=true>
so I know the oauth is working but the body param is not getting passed into the request because it is returning this error
[".error.NO_USER.field-to"]], ["please enter a username"]]
I checked all the data values in the body hash and none of them are null.
Use the set_form_data method to set your POST body:
Here is an example from the docs:
request = Net::HTTP::Post.new(uri)
request.set_form_data('from' => '2005-01-01', 'to' => '2005-03-31')

How to add "Content-type" header in HTTP POST

I keep getting a
400 "Bad Request" (Net::HTTPServerException)
error whenever I try to add a content-type header from various methods.
I've seen several different examples and I can't get any to work. My goal is to add a content type of JSON to my request. Without the header, my request doesn't error:
def post_data(notice)
uri = URI('my uri is here')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
req = Net::HTTP::Post.new("#{uri.path}?#{uri.query}")
text = notice
req.add_field('Content-Type', 'application/json')
req.body = "{\"sensu_payload\" = #{payload(text).to_json}}"
response = http.request(req)
verify_response(response)
end
I've also tried this method of adding a header:
request = Net::HTTP::Post.new(#path, initheader = {'Content-Type' =>'application/json'})
Use uri.path instead of #path:
request = Net::HTTP::Post.new(uri.path, initheader = {'Content-Type' =>'application/json'})
Instead of add_field, I think you should use the hash [] form:
req['Content-Type'] = 'application/json'
See the "Setting Headers" example in the documentation and []=.
Also, using:
"#{uri.path}?#{uri.query}"
is never a good idea. String concatenation can't manage the complexities of correctly encoding illegal values in a query, which can break a request. Consider doing something like this instead:
require 'uri'
require 'uri'
foo = URI('http://www.example.com') # => #<URI::HTTP http://www.example.com>
foo.query = URI::encode_www_form({'bar' => 'path/to/file', 'baz' => 'this & that'})
foo.to_s # => "http://www.example.com?bar=path%2Fto%2Ffile&baz=this+%26+that"
Beyond that, I'd recommend using any of the other HTTP-client gems available. They make it much easier to deal with unexpected situations, like redirects and retries than Net::HTTP. It's more like the building block for features that aren't available other ways.

Sending http post request in Ruby by Net::HTTP

I'm sending a request with custom headers to a web service.
require 'uri'
require 'net/http'
uri = URI("https://api.site.com/api.dll")
https = Net::HTTP.new(uri.host, uri.port)
https.use_ssl = true
headers =
{
'HEADER1' => "VALUE1",
'HEADER2' => "HEADER2"
}
response = https.post(uri.path, headers)
puts response
It's not working, I'm receiving an error of:
/usr/lib/ruby/1.9.1/net/http.rb:1932:in `send_request_with_body': undefined method `bytesize' for #<Hash:0x00000001b93a10> (NoMethodError)
How do I solve this?
P.S. Ruby 1.9.3
Try this:
For detailed documentation, take a look at:
http://www.rubyinside.com/nethttp-cheat-sheet-2940.html
require 'uri'
require 'net/http'
uri = URI('https://api.site.com/api.dll')
https = Net::HTTP.new(uri.host, uri.port)
https.use_ssl = true
request = Net::HTTP::Post.new(uri.path)
request['HEADER1'] = 'VALUE1'
request['HEADER2'] = 'VALUE2'
response = https.request(request)
puts response
The second argument of Net::HTTP#post needs to be a String containing the data to post (often form data), the headers would be in the optional third argument.
As qqx mentioned, the second argument of Net::HTTP#post needs to be a String
Luckily there's a neat function that converts a hash into the required string:
response = https.post(uri.path, URI.encode_www_form(headers))

Ruby Mechanize, Nokogiri and Net::HTTP

I am using Net::HTTP for HTTP requests and getting a response back:
uri = URI("http://www.example.com")
http = Net::HTTP.start(uri.host, uri.port, proxy_host, proxy_port)
request = Net::HTTP::Get.new uri.request_uri
response = http.request request # Net::HTTPResponse object
body = response.body
If I have to use the Nokogiri gem in order to parse this HTML response I will do:
nokogiri_obj = Nokogiri::HTML(body)
But if I want to use Mechanize gem I need to do this:
agent = Mechanize.new
mechanize_obj = agent.get("http://www.example.com")
Is it possible for me to use Net::Http for getting the HTML response and then use the Mechanize gem to convert it into a Mechanize object instead of using agent.get()?
EDIT:
The reason for getting around the agent.get() method is because I am trying to use EventMachine::Iterator to make concurrent EM-HTTP requests.
EventMachine.run do
EM::Iterator.new(urls, 3).each do |url,iter|
puts "giving #{url} to httprequest now"
http = EM::HttpRequest.new(url).get
http.callback { |resp|
uri = resp.send(:URI, url)
puts "inside callback of #{url}"
body = resp.response
page = agent.parse(uri, resp, body)
}
iter.next
end
end
But its not working. I am getting an error:
/usr/local/rvm/gems/ruby-1.9.3-p194/gems/mechanize-2.5.1/lib/mechanize.rb:1165:in`parse': undefined method `[]' for #<EventMachine::HttpClient:0x0000001c18eb30> (NoMethodError)
when I use the parse method for Net::HTTP it works fine and I get the Mechanize object:
uri = URI("http://www.example.com")
http = Net::HTTP.start(uri.host, uri.port, proxy_host, proxy_port)
request = Net::HTTP::Get.new uri.request_uri
response = http.request request # Net::HTTPResponse object
body = response.body
agent = Mechanize.new
page = agent.parse(uri, response, body)
Am I passing the wrong arguments for the parse method while using em-http?
I'm not sure why you think using Net::HTTP would be better. Mechanize will handle redirects and cookies, plus provides ready access to Nokogiri's parsed document.
require 'mechanize'
agent = Mechanize.new
page = agent.get('http://www.example.com')
# Use Nokogiri to find the content of the <h1> tag...
puts page.at('h1').content # => "Example Domains"
Note, setting the user_agent isn't necessary to reach example.com.
If you want to use a threaded engine to retrieve pages, take a look at Typhoeous and Hydra.
Looks like Mechanize has a parse method, so this could work:
mechanize_obj = Mechanize.parse(uri, response, body)

Resources