Ruby Open-URI - specify content type? - ruby

I'm trying
io = open(uri, {ssl_verify_mode: OpenSSL::SSL::VERIFY_PEER})
the result is not what I want.
io.content_type
=> "text/html"
Can I specify I want "application/pdf"?

This seems to work:
io = open(uri, "Content-Type" => "application/pdf", ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE)

Related

Ruby - Webmock: Match URI using regular expression

I'm working with rspec and webmock and I'm looking into stubbing request. I do have a problem when I try to use regex to match the URI.
Everything was working fine when I used the stub below, without matching a specific URI (/.*/)
it "returns nil and stores an error when the response code is not OK" do
stub_request(:get, /.*/).
with(
:headers => insertion_api.send(:default_headers, false).merge('User-Agent'=>'Ruby'),
:body => {}
).
to_return(
:status => Insertion.internal_server_error.to_i,
:body => "{\"message\": \"failure\"}",
:headers => { 'Cookie' => [session_token] }
)
expect(insertion_api.get_iou(uid)).to be_nil
expect(insertion_api.error).to eq("An internal server error occurred")
end
Since I want to be more specific in my test to improve readability, if I try to match a this specific URI:
/insertion_order/012awQQd?fields=name,type&depth=4
using the stub below:
it "returns nil and stores an error when the response code is not OK" do
stub_request(:get, %r{insertion_order/\w+\?fields\=[\w,]+\&depth\=[0-9]}).
with(
:headers => insertion_api.send(:default_headers, false).merge('User-Agent'=>'Ruby'),
:body => {}
).
to_return(
:status => Insertion.internal_server_error.to_i,
:body => "{\"message\": \"failure\"}",
:headers => { 'Cookie' => [session_token] }
)
expect(insertion_api.get_iou(uid)).to be_nil
expect(insertion_api.error).to eq("An internal server error occurred")
end
running the test I've got:
WebMock::NetConnectNotAllowedError:
Real HTTP connections are disabled. Unregistered request: GET https://mocktocapture.com/mgmt/insertion_order/0C12345678 with body '{}' with headers {'Accept'=>'application/vnd.xxx.mgmt+json; version=2.0', 'Cookie'=>'y0Urv3ryLon6s3cur1tYT0k3ng0zeh3r3', 'User-Agent'=>'Ruby'}
You can stub this request with the following snippet:
stub_request(:get, "https://mocktocapture.com/mgmt/insertion_order_units/0C12345678").
with(:body => "{}",
:headers => {'Accept'=>'application/vnd.dataxu.mgmt+json; version=2.0', 'Cookie'=>'y0Urv3ryLon6s3cur1tYT0k3ng0zeh3r3', 'User-Agent'=>'Ruby'}).
to_return(:status => 200, :body => "", :headers => {})
registered request stubs:
stub_request(:get, "/insertion_order\/\w+\?fields\=[\w,]+\&depth\=[0-9]/").
with(:body => {},
:headers => {'Accept'=>'application/vnd.xxx.mgmt+json; version=2.0', 'Cookie'=>'y0Urv3ryLon6s3cur1tYT0k3ng0zeh3r3', 'User-Agent'=>'Ruby'})
The regex I've used is correct, but I don't understand why I've got this error message.
The request you got is :
https://mocktocapture.com/mgmt/insertion_order/0C12345678
You have given the regexp :
%r{insertion_order/\w+\?fields\=[\w,]+\&depth\=[0-9]}
In the regexp you have specified with the "\?" that it is mandatory that the request should contain "?" (or a query) after "insertion_order/\w+". In the request you got there aren't any query parameters. That's why it isn't matching the request.
One way you can fix that is to make the part that comes after "insertion_order/\w+" in the regexp optional. I would do it like this :
%r{insertion_order/\w+(\?fields\=[\w,]+\&depth\=[0-9])?}

Mocking methods in Puppet rspec tests

I've implemented a custom Puppet function that queries a Keystone server for information. The module that defines this function includes some helper methods that perform the actual work of querying keystone. Broadly, the structure looks like this:
def authenticate(auth_url, username, password)
...
end
def list_tenants(auth_url, token)
...
end
module Puppet::Parser::Functions
newfunction(:lookup_tenant, :type => :rvalue) do |args|
...
end
end
I would like to mock out the authenticate and list_tenants methods
during testing so that I can test the rest of the Puppet module in the
absence of an actual Keystone server.
I haven't previously worked with either Ruby or Rpsec before, and I'm
having a hard time finding examples of how to provide stubs for these
internal methods.
So far I have a stub rspec file that simply verified the existence of
the function:
require 'spec_helper'
describe 'lookup_tenant' do
it "should exist" do
Puppet::Parser::Functions.function("lookup_tenant").should == "function_lookup_tenant"
end
# This will fail because there is no keystone server.
it "should fail" do
should run.with_params(
'http://127.0.0.1:35357/v2.0',
'admin_user',
'admin_password',
'admin_tenant_name',
'target_tenant_name'
).and_raise_error(KeystoneError)
end
end
I would like to be able to provide custom returns from the
authenticate and list_tenants methods (or even raise exceptions
from inside these methods) so that I can test the behavior of the
lookup_tenant function in different failure scenarios.
WebMock could be used for simulating the http requests as stubs. Here is the link to the github repo: https://github.com/bblimke/webmock
For folks who haven't seen webmock before, I wanted to leave some information here about why it's particularly awesome.
So, I have in my module some code that makes an http request:
url = URI.parse("#{auth_url}/tokens")
req = Net::HTTP::Post.new url.path
req['content-type'] = 'application/json'
req.body = JSON.generate(post_args)
begin
res = Net::HTTP.start(url.host, url.port) {|http|
http.request(req)
}
if res.code != '200'
raise KeystoneError, "Failed to authenticate to Keystone server at #{auth_url} as user #{username}."
end
rescue Errno::ECONNREFUSED
raise KeystoneError, "Failed to connect to Keystone server at #{auth_url}."
end
By simply adding a require to the start of the spec file:
require `webmock`
Attempts to open a connection will result in:
WebMock::NetConnectNotAllowedError:
Real HTTP connections are disabled. Unregistered request: POST http://127.0.0.1:35357/v2.0/tokens with body '{"auth":{"passwordCredentials":{"username":"admin_user","password":"admin_password"},"tenantName":"admin_tenant"}}' with headers {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'Content-Type'=>'application/json', 'User-Agent'=>'Ruby'}
You can stub this request with the following snippet:
stub_request(:post, "http://127.0.0.1:35357/v2.0/tokens").
with(:body => "{\"auth\":{\"passwordCredentials\":{\"username\":\"admin_user\",\"password\":\"admin_password\"},\"tenantName\":\"admin_tenant\"}}",
:headers => {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'Content-Type'=>'application/json', 'User-Agent'=>'Ruby'}).
to_return(:status => 200, :body => "", :headers => {})
And that's just about all the information you need to stub out the
call. You can make the stubs as granular as necessary; I ended up
using something like:
good_auth_request = {
'auth' => {
'passwordCredentials' => {
'username' => 'admin_user',
'password' => 'admin_password',
},
'tenantName' => 'admin_tenant',
}
}
auth_response = {
'access' => {
'token' => {
'id' => 'TOKEN',
}
}
}
stub_request(:post, "http://127.0.0.1:35357/v2.0/tokens").
with(:body => good_auth_request.to_json).
to_return(:status => 200, :body => auth_response.to_json, :headers => {})
And now I can test my module when there is no Keystone server
available.

savon gem example_body not coming properly

I have a wsdl url to give request and get response this is my code(using savon gem for this)
client = Savon.new('http://services.chromedata.com/Description/7a?wsdl')
service = :Description7a
port = :Description7aPort
operation = :getDivisions
division = client.operation(service, port, operation)
I am able to print example_body like
division.example_body
=> {:DivisionsRequest=>{:accountInfo=>{:_number=>"string", :_secret=>"string", :_country=>"string", :_language=>"string", :_behalfOf=>"string"}, :_modelYear=>"int"}}
and i'm able to set values like
division.body = {.........}
other operation such like
operationlist = client.operations(service, port)
=> ["getVersionInfo", "getModelYears", "getDivisions", "getSubdivisions", "getModels", "getStyles", "describeVehicle", "getCategoryDefinitions", "getTechnicalSpecificationDefinitions"]
I used describe vehicle
desc_veh = client.operation(service, port, "describeVehicle")
whose example_body is like
desc_veh.example_body
=> {:VehicleDescriptionRequest=>{}}
so unable to set values for desc_veh.body and the use the .call function
I don know whether it is a savon gem problem or the wsdl url problem
Your code could look like this:
gem "savon", "~> 2.0"
require "savon"
client = Savon.client(
:wsdl => 'http://services.chromedata.com/Description/7a?wsdl',
:convert_request_keys_to => :camelcase,
:log => true,
:log_level => :debug,
:pretty_print_xml => true
)
res = client.call(:get_divisions,
message: { :param1 => 'value1', :param2 => 'value2' }
)
print res.to_hash
The parameters are simply a hash in key/value pairs.

Upload files using Faraday

I'm having issues attempting to upload a file to a web service using Faraday.
My code:
conn = Faraday.new('http://myapi') do |f|
f.request :multipart
end
payload = { :file => Faraday::UploadIO.new('...', 'image/jpeg') }
conn.post('/', payload)
Nothing seems to happen after attempting the post. When I inspect the response this is what I'm seeing:
#<Faraday::Response:0x007fd9e5903870 #env={:method=>:post, :body=>#<Faraday::CompositeReadIO:0x007fd9e5903a50 #parts=[#<Parts::FilePart:0x007fd9e5903e38 #head="-------------RubyMultipartPost\r\nContent-Disposition: form-data; name=\"file\"; filename=\"indymade-badge-horizontal.png\"\r\nContent-Length: 7821\r\nContent-Type: image/png\r\nContent-Transfer-Encoding: binary\r\n\r\n", #foot="\r\n", #length=8026, #io=#<CompositeReadIO:0x007fd9e5903b68 #ios=[#<StringIO:0x007fd9e5903bb8>, #<UploadIO:0x007fd9e514a3b8 #content_type="image/png", #original_filename="indymade-badge-horizontal.png", #local_path="/Users/anthonator/Downloads/indymade-badge-horizontal.png", #io=#<File:/Users/anthonator/Downloads/indymade-badge-horizontal.png>, #opts={}>, #<StringIO:0x007fd9e5903b90>], #index=0>>, #<Parts::EpiloguePart:0x007fd9e5903ac8 #part="-------------RubyMultipartPost--\r\n\r\n", #io=#<StringIO:0x007fd9e5903a78>>], #ios=[#<CompositeReadIO:0x007fd9e5903b68 #ios=[#<StringIO:0x007fd9e5903bb8>, #<UploadIO:0x007fd9e514a3b8 #content_type="image/png", #original_filename="indymade-badge-horizontal.png", #local_path="/Users/anthonator/Downloads/indymade-badge-horizontal.png", #io=#<File:/Users/anthonator/Downloads/indymade-badge-horizontal.png>, #opts={}>, #<StringIO:0x007fd9e5903b90>], #index=0>, #<StringIO:0x007fd9e5903a78>], #index=0>, :url=>#<URI::HTTPS:0x007fd9e5909d60 URL:https://myapi>, :request_headers=>{"User-Agent"=>"Faraday v0.8.7", "Content-Type"=>"multipart/form-data;boundary=-----------RubyMultipartPost", "Content-Length"=>"8062"}, :parallel_manager=>nil, :request=>{:proxy=>nil, :boundary=>"-----------RubyMultipartPost"}, :ssl=>{}, :response=>#<Faraday::Response:0x007fd9e5903870 ...>}, #on_complete_callbacks=[]>
irb(main):065:0> response.inspect
=> "#<Faraday::Response:0x007fd9e5903870 #env={:method=>:post, :body=>#<Faraday::CompositeReadIO:0x007fd9e5903a50 #parts=[#<Parts::FilePart:0x007fd9e5903e38 #head=\"-------------RubyMultipartPost\\r\\nContent-Disposition: form-data; name=\\\"file\\\"; filename=\\\"indymade-badge-horizontal.png\\\"\\r\\nContent-Length: 7821\\r\\nContent-Type: image/png\\r\\nContent-Transfer-Encoding: binary\\r\\n\\r\\n\", #foot=\"\\r\\n\", #length=8026, #io=#<CompositeReadIO:0x007fd9e5903b68 #ios=[#<StringIO:0x007fd9e5903bb8>, #<UploadIO:0x007fd9e514a3b8 #content_type=\"image/png\", #original_filename=\"indymade-badge-horizontal.png\", #local_path=\"/Users/anthonator/Downloads/indymade-badge-horizontal.png\", #io=#<File:/Users/anthonator/Downloads/indymade-badge-horizontal.png>, #opts={}>, #<StringIO:0x007fd9e5903b90>], #index=0>>, #<Parts::EpiloguePart:0x007fd9e5903ac8 #part=\"-------------RubyMultipartPost--\\r\\n\\r\\n\", #io=#<StringIO:0x007fd9e5903a78>>], #ios=[#<CompositeReadIO:0x007fd9e5903b68 #ios=[#<StringIO:0x007fd9e5903bb8>, #<UploadIO:0x007fd9e514a3b8 #content_type=\"image/png\", #original_filename=\"indymade-badge-horizontal.png\", #local_path=\"/Users/anthonator/Downloads/indymade-badge-horizontal.png\", #io=#<File:/Users/anthonator/Downloads/indymade-badge-horizontal.png>, #opts={}>, #<StringIO:0x007fd9e5903b90>], #index=0>, #<StringIO:0x007fd9e5903a78>], #index=0>, :url=>#<URI::HTTPS:0x007fd9e5909d60 URL:https://myapi>, :request_headers=>{\"User-Agent\"=>\"Faraday v0.8.7\", \"Content-Type\"=>\"multipart/form-data;boundary=-----------RubyMultipartPost\", \"Content-Length\"=>\"8062\"}, :parallel_manager=>nil, :request=>{:proxy=>nil, :boundary=>\"-----------RubyMultipartPost\"}, :ssl=>{}, :response=>#<Faraday::Response:0x007fd9e5903870 ...>}, #on_complete_callbacks=[]>"
The body is being set to a CompositeReadIO object and it seems to never be sending out a request.
It turns out that I needed to specify an adapter. Here's the code that ended up working.
conn = Faraday.new('http://myapi') do |f|
f.request :multipart
f.request :url_encoded
f.adapter :net_http # This is what ended up making it work
end
payload = { :file => Faraday::UploadIO.new('...', 'image/jpeg') }
conn.post('/', payload)
Something like this resolved my problem:
conn = Faraday.new(url: URL) do |faraday|
faraday.request :multipart #make sure this is set before url_encoded
faraday.request :url_encoded
faraday.adapter Faraday.default_adapter
end
file = Faraday::UploadIO.new(
params[:image].tempfile.path,
params[:image].content_type,
params[:image].original_filename
)
payload = { :file => file }
conn.post('/', payload)
Faraday after v0.16.0:
https://lostisland.github.io/faraday/middleware/multipart
"Multipart" middleware detects files and encodes with "multipart/form-data":
payload[:profile_pic] = Faraday::FilePart.new('/path/to/avatar.jpg', 'image/jpeg')
conn.put '/profile', payload

Parse WSDL file with SOAP4R

Is there any example of WSDL Parser using SOAP4R? I'm trying to list all operations of WSDL file but I can't figure it out :( Can you post me some tutorial?
Thx
Maybe that isn't answer you want, but I recommend you switch to Savon. For example, your task looks like this snippet (this example taken from github's savon page):
require "savon"
# create a client for your SOAP service
client = Savon::Client.new("http://service.example.com?wsdl")
client.wsdl.soap_actions
# => [:create_user, :get_user, :get_all_users]
# execute a SOAP request to call the "getUser" action
response = client.request(:get_user) do
soap.body = { :id => 1 }
end
response.body
# => { :get_user_response => { :first_name => "The", :last_name => "Hoff" } }

Resources