Connect to a SOAP API with savon and specify Domain - ruby

With SoapUI, I am successfully connecting to a SOAP API with details such as:
Initial WSDL: http://11.11.1.11:7303/FOO/BAR/BAZ
Username: foo
Password: bar
Domain: example
But I am not sure how to do this with Savon. I am trying this (not quite understanding if ntlm is the correct setting here):
savon_defaults = {
:wsdl => "http://11.11.1.11:7303/FOO/BAR/BAZ",
:ntlm => ["foo", "bar", "example"],
:log_level => :debug,
:pretty_print_xml => true,
:log => true
}
#client = Savon.client(savon_defaults)
#client.call(:foo, :message => {:bar => "baz"})
The above outputs:
D, [2020-05-18T21:21:14.853929 #7156] DEBUG -- : HTTPI /peer GET request to 11.11.1.11 (httpclient)
Savon::HTTPError: HTTP error (401)
Any ideas?

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.

Authenticate with http headers with savon 2.3.0

I had this code in Savon v1:
client = Savon.client("http://www.server.com:9191/soapserver?wsdl")
service = client.request :get_authentication do
client.http.headers["username"] = "myuser"
client.http.headers["password"] = "mypass"
end
After the update to savon v2.3.0, I don't manage to retranslate. It should be something like
client = Savon.client do
wsdl "http://www.shab.ch:9191/soapserver?wsdl
end
service = client.call(:get_authentication, {username: "myuser", password: "mypass"})`
but the line service = client.call(..." does not work. Any idea?
I think what you want to do is:
gem "savon"
require "savon", "~>2.0"
...
client = Savon.client(headers: { username: "user", password: "password"},
wsdl: "http://www.example.com/?wsdl",
log: true,
log_level: :debug,
pretty_print_xml: true
#, and more options here if necessary)
That will inject the key/values pairs into the http headers.
That last code block of yours is missing a " on line #2 and has a ``` too much in the end. It should look like:
client = Savon.client do
wsdl "http://www.shab.ch:9191/soapserver?wsdl"
end
service = client.call(:get_authentication, {username: "myuser", password: "mypass"})
to not trigger any syntax errors.
This works for me after a lot of trial and error:
client = Savon.client( wsdl: "http://www.server.com:9191/soapserver?wsdl", <\br>
headers: {'username' => 'myuser', 'password' => 'mypass'} )
service = client.call(:get_authentication)
So the header injection I do before calling the :get_authentication function.

How to geocode a Twitter status update using the Ruby OAuth Gem

Using the following Ruby code, I can send a status update over the Twitter API to my account. According to the Twitter API Docs I would expect it to be geocoded, but it isn't. What am I doing wrong?
require 'oauth'
consumer = OAuth::Consumer.new('<MY_CONSUMER_KEY>', '<MY_CONSUMER_SECRET>', :site => "http://api.twitter.com", :scheme => :header)
access_token = OAuth::AccessToken.from_hash(consumer, :oauth_token => '<MY_OAUTH_TOKEN>', :oauth_token_secret => '<MY_OAUTH_SECRET>')
access_token.request(:post, "http://api.twitter.com/1/statuses/update.xml", {"Content-Type" => "application/xml", "status" => "This Tweet is from Zuerich in Switzerland", "lat" => "47.3807", "long" => "8.537", "display_coordinates" => "true", "geo_enabled" => "true"})
It works ok. You should enable "Add a location to your tweets" in your twitter profile settings.

Resources