Stub request if it contains keyword - ruby

I want to stub requests from rspec file if it contains the keyword zimpler no matter what is the POST address and the content.
stub_request(:post, "http://www.example.com/").
with(body: "zimpler")
to_return(:status => 200, :body => xml_file, :headers => {})
is there a way to implement this?

Related

http client with custom params

I use this code to make network request:
request = HTTPClient.new()
request.ssl_config.verify_mode = OpenSSL::SSL::VERIFY_NONE
request.set_auth(url, terminal['api_login'], terminal['api_password'])
response = request.post(url, request_body, {"Content-Type" => "application/xml", "cache-control" => "no-cache"}).body
But when I tried to implement rspec with stub request two params are added which are every time different on every test env:
stub_request(:post, "http://www.example.com/").
with(:headers => {'Accept'=>'*/*', 'Cache-Control'=>'no-cache', 'Content-Type'=>'application/xml', 'Date'=>'Thu, 08 Mar 2018 14:20:55 GMT', 'User-Agent'=>'HTTPClient/1.0 (2.8.3, ruby 2.2.2 (2015-04-13))'}).
to_return(:status => 200, :body => "", :headers => {})
How I can configure http client not to send Date and for User-Agent to send something simple like 'Ruby'?
Is it possible to configure these params?
There is a great gem to deal with this kind of situations, it's called Timecop https://github.com/travisjeffery/timecop. Basically, you can freeze time, or move to a specific date. In your case, I think you just need to freeze the time so you can set an arbitrary date in the stub headers.
Timecop.freeze
stub_request(:post, "http://www.example.com/").
with(:headers => {'Accept'=>'*/*', 'Cache-Control'=>'no-cache', 'Content-Type'=>'application/xml', 'Date'=> Time.now, 'User-Agent'=>'HTTPClient/1.0 (2.8.3, ruby 2.2.2 (2015-04-13))'}).
to_return(:status => 200, :body => "", :headers => {})
# the rest of your test here
end
Also, you can simplify your stub by omitting the headers and using a regex for the url, something like:
stub_request(:post, /.example.*\/).and_return(:status => 200, :body => "", :headers => {})

Can't add email to Campaign Monitor API?

I am trying to create some simple Ruby code to add emails using the Campaign Monitor API. Below is my code.
require 'httparty'
require 'json'
def request
url = 'https://api.createsend.com/api/v3.1/subscribers/MYLISTID.json'
auth = {:username => 'MYAPIKEY', :password => 'x'}
response = HTTParty.post(url,
:basic_auth => auth, :body => {
'EmailAddress' => 'mike#hotmail.com',
'Name' => 'Test',
'Resubscribe' => true,
'RestartSubscriptionBasedAutoresponders' => true
})
puts response
puts response.code
end
request
I can connect with the API. However, when I try to add the email I am getting the following response.
{"Code"=>400, "Message"=>"Failed to deserialize your request.
Please check the documentation and try again.
Fields in error: subscriber"}
400
When I change the request to get instead of put
my response is:
{"Code"=>1, "Message"=>"Invalid Email Address"}
I can't understand what I am doing wrong as I have followed the documentation on the Campaign Monitor API
It looks like you have everything setup correctly, you just need to turn the body of the post into a json string.
response = HTTParty.post(url,
:basic_auth => auth, :body => {
'EmailAddress' => 'mike#hotmail.com',
'Name' => 'Test',
'Resubscribe' => true,
'RestartSubscriptionBasedAutoresponders' => true
}.to_json)
I'd like to point out that a Campaign Monitor API gem also exists that will do all of that work for you.
Campaign Monitor API Gem

POST JSON data with Curl Multi from ruby

I am using the curb gem to do a Curl Multi post using JSON data. However I am unable to actually get the parameters to get posted and have been unable to figure out how to properly configure the parameters.
urls = [
{
:url => "http://localhost:5000/",
:method => :post,
:headers => {'Accept' => 'application/json', 'Content-Type' => 'application/json'},
:post_fields => {'field1' => 'value1', 'k' => 'j'}
}
]
Curl::Multi.http(urls) do |easy, code, method|
puts "#{easy.body_str.inspect}, #{method.inspect}, #{code.inspect}"
end
=>
"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">\n<title>400 Bad Request</title>\n<h1>Bad Request</h1>\n<p>The browser (or proxy) sent a request that this server could not understand.</p>\n", :post, nil
Do that:
urls = [
{
:url => "http://localhost:5000/",
:method => :post,
:headers => {'Accept' => 'application/json', 'Content-Type' => 'application/json'},
:post_fields => {},
:post_body => {'field1' => 'value1', 'k' => 'j'}.to_json,
}
]
The problem: curb doesn't know that you are sending a JSON data. Curb don't read and interprets the contents of :headers. As you can see here, curb transforms your hash into a string separated by "&", which is the default for a normal (non-json) http data sending (eg.: "field1=value1&k=j"). When the server (Rails) read and interprets the header explicity saying that the data is in JSON format, it tries to decode and the result is the same exception that you get when you do that: JSON.parse("field1=value1&k=j").
To solve this, you need to send "post_fields" as an empty hash, and send your actual data by using "post_body". Also, you need to convert your hash to json manually with to_json.
I don't know if they (the curb project owners) know this problem, but I suggest you to warning them about it.

Can't mock website with Basic Authentication

Using Ruby, Mechanize, RSpec, and Webmock, I can not mock a website with Basic Authentication, my app keeps telling me that I got an unregistered stub.
The stubs:
stub_request(:get, "http://foo:bar#google.fr:80/").
with(:headers => {'Accept'=>'*/*', 'User-Agent'=>'Ruby'}).
to_return(:status => 200, :body => "", :headers => {})
Net::HTTP.start('www.google.fr') {|http|
req = Net::HTTP::Get.new('/')
req.basic_auth 'foo', 'bar'
http.request(req)
}
In the app:
url = 'http://www.google.fr'
agent = Mechanize.new
agent.add_auth(url, 'foo', 'bar')
agent.get(url)
The issue I get when running agent.get(url)
(rdb:1) agent.get(url)
*** WebMock::NetConnectNotAllowedError Exception: Real HTTP connections are disabled. Unregistered request: GET http://www.google.fr/ with headers {'Accept'=>'*/*', 'Accept-Charset'=>'ISO-8859-1,utf-8;q=0.7,*;q=0.7', 'Accept-Encoding'=>'gzip,deflate,identity', 'Accept-Language'=>'en-us,en;q=0.5', 'Connection'=>'keep-alive', 'Host'=>'www.google.fr', 'Keep-Alive'=>'300', 'User-Agent'=>'Mechanize/2.7.3 Ruby/1.9.3p194 (http://github.com/sparklemotion/mechanize/)'}
You can stub this request with the following snippet:
stub_request(:get, "http://www.google.fr/").
with(:headers => {'Accept'=>'*/*', 'Accept-Charset'=>'ISO-8859-1,utf-8;q=0.7,*;q=0.7', 'Accept-Encoding'=>'gzip,deflate,identity', 'Accept-Language'=>'en-us,en;q=0.5', 'Connection'=>'keep-alive', 'Host'=>'www.google.fr', 'Keep-Alive'=>'300', 'User-Agent'=>'Mechanize/2.7.3 Ruby/1.9.3p194 (http://github.com/sparklemotion/mechanize/)'}).
to_return(:status => 200, :body => "", :headers => {})
registered request stubs:
stub_request(:get, "http://foo:bar#www.google.fr/").
with(:headers => {'Accept'=>'*/*', 'User-Agent'=>'Ruby'})
A few points:
Assigning 'http://foo:bar#google.fr/' to url does
not work neither (and that would be very ugly if it works anyways).
Last but not least, creating a stub with http://www.google.fr/' as a url would not use basic authentication, since if I do so, even if I change the credentials, I will still access to my mocked page and no errors would be rendered.
Some screenshots:
There exists an incompatibility between WebMock and net-http-persistent.
See https://github.com/bblimke/webmock#connecting-on-nethttpstart
Add WebMock.allow_net_connect!(:net_http_connect_on_start => true) to your test set up.
According to the documentation this should work:
stub_request(:get, "foo:bar#www.google.fr").
with(:headers => {'Accept'=>'*/*', 'User-Agent'=>'Ruby'}).
to_return(:status => 200, :body => "", :headers => {})

What is the purpose of stubbing an HTTP request (e.g. using the WebMock gem)?

As a precursor FYI, I'm a budding developer. I'm trying to write a test for an http POST method for a Ruby gem. From what I can understand, when you stub an http response, for instance with the Ruby WebMock gem, you're basically telling it what to post and then artificially telling it what to respond with. For example, here is the code I'm trying to test:
## githubrepo.rb
module Githubrepo
include HTTParty
def self.create(attributes)
post = HTTParty.post(
'https://api.github.com/user/repos',
:headers => {
'User-Agent' => 'Githubrepo',
'Content-Type' => 'application/json',
'Accept' => 'application/json'
},
:basic_auth => {
:username => attributes[:username],
:password => attributes[:password]
},
:body => {
'name' => attributes[:repository],
'description' => attributes[:description]
}.to_json
)
Githubrepo.parse_response_from(post, attributes[:wants_ssh])
end
My RSpec test fails when I write:
Githubrepo.create(:repository => 'test', :username => 'test_user', :password => '1234')
because it makes a real HTTP request. It recommends I do the following instead:
stub_request(:post, "https://test_user:test_password#api.github.com/user/repos").
with(:body => "{\"name\":\"test_repo\",\"description\":null}",
:headers => {'Accept'=>'application/json', 'Content-Type'=>'application/json', 'User-Agent'=>'Githubrepo'}).
to_return(:status => 200, :body => "", :headers => {})
But to me, this seems like it's pointless since it's basically telling what to send and what to respond with. I can edit the URL to say "https://bananas#git-banana.banana" and the header to say Content-type => 'Rumplestilskin' and RSpec is ok with that. How am I supposed to integrate this into testing the functionality of the create method I specified above? Or if anything, can somebody point me to a solid beginner guide or blog to help me with this question? The Ruby gem READMEs seem to assume the user knows a thing or two already about this and I don't.
As Steve mentions in a comment, the point of this type of test is not to test the external API but instead that your code to handle and parse the response is correct.
As discussed in the comments to this question, check out the VCR gem for "recording" API responses to make sure your code processes them correctly: https://github.com/vcr/vcr

Resources