glennr_opensrs 0.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,59 @@
1
+ begin
2
+ require 'nokogiri'
3
+ rescue LoadError => e
4
+ $stderr.puts "Cannot find Nokogiri gem. Please install Nokogiri before using it as the xml processor\n\n"
5
+ raise e
6
+ end
7
+
8
+ module OpenSRS
9
+ class XmlProcessor::Nokogiri < OpenSRS::XmlProcessor
10
+
11
+ def self.build(data)
12
+ builder = ::Nokogiri::XML::Builder.new
13
+
14
+ envelope = ::Nokogiri::XML::Node.new("OPS_envelope", builder.doc)
15
+ header = ::Nokogiri::XML::Node.new("header", builder.doc)
16
+ version = ::Nokogiri::XML::Node.new("version", builder.doc)
17
+ body = ::Nokogiri::XML::Node.new("body", builder.doc)
18
+ data_block = ::Nokogiri::XML::Node.new("data_block", builder.doc)
19
+ other_data = encode_data(data, builder.doc)
20
+ builder.doc << envelope << header << version << '0.9'
21
+ envelope << body << data_block << other_data
22
+ return builder.to_xml
23
+ end
24
+
25
+ protected
26
+
27
+ def self.data_block_element(response)
28
+ doc = ::Nokogiri::XML(response)
29
+ return doc.xpath('//OPS_envelope/body/data_block/*')
30
+ end
31
+
32
+ def self.decode_dt_array_data(element)
33
+ dt_array = []
34
+
35
+ element.children.each do |item|
36
+ next if item.content.strip.empty?
37
+ dt_array[item.attributes["key"].value.to_i] = decode_data(item.children)
38
+ end
39
+
40
+ return dt_array
41
+ end
42
+
43
+ def self.decode_dt_assoc_data(element)
44
+ dt_assoc = {}
45
+
46
+ element.children.each do |item|
47
+ next if item.content.strip.empty?
48
+ dt_assoc[item.attributes["key"].value] = decode_data(item.children)
49
+ end
50
+
51
+ return dt_assoc
52
+ end
53
+
54
+ def self.new_element(element_name, container)
55
+ return ::Nokogiri::XML::Node.new(element_name.to_s, container)
56
+ end
57
+
58
+ end
59
+ end
data/opensrs.gemspec ADDED
@@ -0,0 +1,76 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "opensrs"
8
+ s.version = "0.3.3"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Josh Delsman", "Glenn Roberts"]
12
+ s.date = "2013-03-11"
13
+ s.description = "Provides support to utilize the OpenSRS API with Ruby/Rails."
14
+ s.email = "jdelsman@voxxit.com"
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README.rdoc"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ "Gemfile",
22
+ "Gemfile.lock",
23
+ "LICENSE",
24
+ "README.rdoc",
25
+ "Rakefile",
26
+ "lib/opensrs.rb",
27
+ "lib/opensrs/response.rb",
28
+ "lib/opensrs/server.rb",
29
+ "lib/opensrs/version.rb",
30
+ "lib/opensrs/xml_processor.rb",
31
+ "lib/opensrs/xml_processor/libxml.rb",
32
+ "lib/opensrs/xml_processor/nokogiri.rb",
33
+ "opensrs.gemspec",
34
+ "spec/opensrs/server_spec.rb",
35
+ "spec/opensrs/version_spec.rb",
36
+ "spec/opensrs/xml_processor/libxml_spec.rb",
37
+ "spec/opensrs/xml_processor/nokogiri_spec.rb",
38
+ "spec/spec_helper.rb"
39
+ ]
40
+ s.homepage = "http://github.com/voxxit/opensrs"
41
+ s.licenses = ["MIT"]
42
+ s.require_paths = ["lib"]
43
+ s.rubygems_version = "1.8.23"
44
+ s.summary = "Provides support to utilize the OpenSRS API with Ruby/Rails."
45
+
46
+ if s.respond_to? :specification_version then
47
+ s.specification_version = 3
48
+
49
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
50
+ s.add_runtime_dependency(%q<libxml-ruby>, ["~> 2.1.2"])
51
+ s.add_development_dependency(%q<nokogiri>, ["~> 1.4.6"])
52
+ s.add_development_dependency(%q<jeweler>, [">= 0"])
53
+ s.add_development_dependency(%q<git>, [">= 0"])
54
+ s.add_development_dependency(%q<rake>, [">= 0"])
55
+ s.add_development_dependency(%q<shoulda>, [">= 0"])
56
+ s.add_development_dependency(%q<rspec>, ["~> 2.0"])
57
+ else
58
+ s.add_dependency(%q<libxml-ruby>, ["~> 2.1.2"])
59
+ s.add_dependency(%q<nokogiri>, ["~> 1.4.6"])
60
+ s.add_dependency(%q<jeweler>, [">= 0"])
61
+ s.add_dependency(%q<git>, [">= 0"])
62
+ s.add_dependency(%q<rake>, [">= 0"])
63
+ s.add_dependency(%q<shoulda>, [">= 0"])
64
+ s.add_dependency(%q<rspec>, ["~> 2.0"])
65
+ end
66
+ else
67
+ s.add_dependency(%q<libxml-ruby>, ["~> 2.1.2"])
68
+ s.add_dependency(%q<nokogiri>, ["~> 1.4.6"])
69
+ s.add_dependency(%q<jeweler>, [">= 0"])
70
+ s.add_dependency(%q<git>, [">= 0"])
71
+ s.add_dependency(%q<rake>, [">= 0"])
72
+ s.add_dependency(%q<shoulda>, [">= 0"])
73
+ s.add_dependency(%q<rspec>, ["~> 2.0"])
74
+ end
75
+ end
76
+
@@ -0,0 +1,109 @@
1
+ require 'spec_helper'
2
+
3
+ describe OpenSRS::Server do
4
+ let(:server) { OpenSRS::Server.new }
5
+
6
+ describe '#new' do
7
+ it 'allows timeouts to be set' do
8
+ server = OpenSRS::Server.new({ :timeout => 90 })
9
+ server.timeout.should == 90
10
+ server.open_timeout.should be_nil
11
+ end
12
+
13
+ it 'allows open timeouts to be set' do
14
+ server = OpenSRS::Server.new({ :timeout => 90, :open_timeout => 10 })
15
+ server.timeout.should eq(90)
16
+ server.open_timeout.should eq(10)
17
+ end
18
+
19
+ it 'leaves it up to Net::HTTP if no timeouts given' do
20
+ server.timeout.should be_nil
21
+ server.open_timeout.should be_nil
22
+ end
23
+ end
24
+
25
+ describe ".call" do
26
+ let(:response) { double(:body => 'some response') }
27
+ let(:header) { {"some" => "header" } }
28
+ let(:xml) { '<some xml></some xml>' }
29
+ let(:response_xml) { xml }
30
+ let(:xml_processor) { double OpenSRS::XmlProcessor }
31
+ let(:http) { double(Net::HTTP, :use_ssl= => true, :verify_mode= => true) }
32
+
33
+ before :each do
34
+ server.stub(:headers).and_return header
35
+ xml_processor.stub(:build).and_return xml
36
+ xml_processor.stub(:parse).and_return response_xml
37
+ server.stub(:xml_processor).and_return xml_processor
38
+ http.stub(:post).and_return response
39
+ Net::HTTP.stub(:new).and_return http
40
+ end
41
+
42
+ it "builds XML request" do
43
+ xml_processor.should_receive(:build).with(:protocol => "XCP", :some => 'option')
44
+ server.call(:some => 'option')
45
+ end
46
+
47
+ it "posts to given path" do
48
+ server.server = URI.parse 'http://with-path.com/endpoint'
49
+ http.should_receive(:post).with('/endpoint', xml, header).and_return double.as_null_object
50
+ server.call
51
+ end
52
+
53
+ it "parses the response" do
54
+ xml_processor.should_receive(:parse).with(response.body)
55
+ server.call(:some => 'option')
56
+ end
57
+
58
+ it "posts to root path" do
59
+ server.server = URI.parse 'http://root-path.com/'
60
+ http.should_receive(:post).with('/', xml, header).and_return double.as_null_object
61
+ server.call
62
+ end
63
+
64
+ it "defaults path to '/'" do
65
+ server.server = URI.parse 'http://no-path.com'
66
+ http.should_receive(:post).with('/', xml, header).and_return double.as_null_object
67
+ server.call
68
+ end
69
+
70
+ it 'allows overriding of default (Net:HTTP) timeouts' do
71
+ server.timeout = 90
72
+
73
+ http.should_receive(:open_timeout=).with(90)
74
+ http.should_receive(:read_timeout=).with(90)
75
+
76
+ server.call( { :some => 'data' } )
77
+ end
78
+
79
+ it 'allows overriding of default (Net:HTTP) timeouts' do
80
+ server.timeout = 180
81
+ server.open_timeout = 30
82
+
83
+ http.should_receive(:read_timeout=).with(180)
84
+ http.should_receive(:open_timeout=).with(180)
85
+ http.should_receive(:open_timeout=).with(30)
86
+
87
+ server.call( { :some => 'data' } )
88
+ end
89
+
90
+ it 're-raises Net:HTTP timeouts' do
91
+ http.should_receive(:post).and_raise err = Timeout::Error.new('test')
92
+ expect { server.call }.to raise_exception OpenSRS::TimeoutError
93
+ end
94
+ end
95
+
96
+ describe "#test xml processor" do
97
+ context "on class initialization" do
98
+ it { server.xml_processor.should eql(OpenSRS::XmlProcessor::Libxml) }
99
+ end
100
+
101
+ context "on changing xml processor" do
102
+ before(:each) do
103
+ OpenSRS::Server.xml_processor = :nokogiri
104
+ end
105
+
106
+ it { server.xml_processor.should eql(OpenSRS::XmlProcessor::Nokogiri) }
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,9 @@
1
+ require 'spec_helper'
2
+
3
+ describe OpenSRS::Version do
4
+ describe "VERSION" do
5
+ it "should return version string" do
6
+ OpenSRS::Version::VERSION.should eql("0.3.3")
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,254 @@
1
+ require 'spec_helper'
2
+ require 'date'
3
+
4
+ describe OpenSRS::XmlProcessor::Libxml do
5
+ describe ".build" do
6
+ it "should create XML for a nested hash" do
7
+ attributes = {:foo => {:bar => 'baz'}}
8
+ xml = OpenSRS::XmlProcessor::Libxml.build(attributes)
9
+ xml.should eq %{<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<OPS_envelope>\n <header>\n <version>0.9</version>\n </header>\n <body>\n <data_block>\n <dt_assoc>\n <item key=\"foo\">\n <dt_assoc>\n <item key=\"bar\">baz</item>\n </dt_assoc>\n </item>\n </dt_assoc>\n </data_block>\n </body>\n</OPS_envelope>\n}
10
+ end
11
+ end
12
+
13
+ describe '.encode_data' do
14
+ context "on a 3 element array" do
15
+ before(:each) do
16
+ @e = OpenSRS::XmlProcessor::Libxml.encode_data([1,2,3])
17
+ end
18
+
19
+ it "is a REXML::Element" do
20
+ @e.should be_an_instance_of(LibXML::XML::Node)
21
+ end
22
+
23
+ it "is a dt_array" do
24
+ @e.name.should == 'dt_array'
25
+ end
26
+
27
+ it "has 3 children all called <item>" do
28
+ @e.should have(3).children
29
+ @e.children[0].name.should == "item"
30
+ @e.children[1].name.should == "item"
31
+ @e.children[2].name.should == "item"
32
+ end
33
+
34
+ it "has children with keys 0, 1 and 2" do
35
+ @e.children[0].attributes["key"].should == "0"
36
+ @e.children[1].attributes["key"].should == "1"
37
+ @e.children[2].attributes["key"].should == "2"
38
+ end
39
+ end
40
+
41
+ context "on a hash" do
42
+ before(:each) do
43
+ @e = OpenSRS::XmlProcessor::Libxml.encode_data({:name => "kitteh"})
44
+ end
45
+
46
+ it "is a REXML::Element" do
47
+ @e.should be_an_instance_of(LibXML::XML::Node)
48
+ end
49
+
50
+ it "is a dt_assoc" do
51
+ @e.name.should == 'dt_assoc'
52
+ end
53
+
54
+ it "has an <item> child with the right key" do
55
+ @e.should have(1).children
56
+ @e.children[0].name.should == 'item'
57
+ @e.children[0].attributes["key"].should == 'name'
58
+ end
59
+ end
60
+
61
+ context "on a nested hash" do
62
+ before(:each) do
63
+ @e = OpenSRS::XmlProcessor::Libxml.encode_data({:suggestion => {:maximum => "10"}})
64
+ end
65
+
66
+ it "is a REXML::Element" do
67
+ @e.should be_an_instance_of(LibXML::XML::Node)
68
+ end
69
+
70
+ it "is a dt_assoc" do
71
+ @e.name.should == 'dt_assoc'
72
+ end
73
+
74
+ it "has an <item> child with the correct children" do
75
+ @e.should have(1).children
76
+ suggestion = @e.children[0]
77
+ suggestion.name.should == 'item'
78
+ suggestion.attributes["key"].should == 'suggestion'
79
+
80
+ suggestion.should have(1).children
81
+ dt_assoc = suggestion.children[0]
82
+ dt_assoc.name.should == 'dt_assoc'
83
+
84
+ dt_assoc.should have(1).children
85
+ maximum = dt_assoc.children[0]
86
+ maximum.name.should == 'item'
87
+ maximum.attributes["key"].should == 'maximum'
88
+ end
89
+ end
90
+
91
+ context "produces a scalar" do
92
+ it "from a string" do
93
+ OpenSRS::XmlProcessor::Libxml.encode_data("cheezburger").to_s.should == "cheezburger"
94
+ end
95
+
96
+ it "from a string with XML characters" do
97
+ OpenSRS::XmlProcessor::Libxml.encode_data("<smile>").to_s.should == "<smile>"
98
+ end
99
+
100
+ it "from an integer" do
101
+ OpenSRS::XmlProcessor::Libxml.encode_data(12345).to_s.should == "12345"
102
+ end
103
+
104
+ it "from a date" do
105
+ date = Date.parse("2010/02/12")
106
+ OpenSRS::XmlProcessor::Libxml.encode_data(date).to_s.should == "2010-02-12"
107
+ end
108
+
109
+ it "from a symbol" do
110
+ OpenSRS::XmlProcessor::Libxml.encode_data(:name).to_s.should == "name"
111
+ end
112
+
113
+ it "from true or false" do
114
+ OpenSRS::XmlProcessor::Libxml.encode_data(true).to_s.should == "true"
115
+ OpenSRS::XmlProcessor::Libxml.encode_data(false).to_s.should == "false"
116
+ end
117
+ end
118
+ end
119
+
120
+ describe '.parse' do
121
+ it "should handle scalar values" do
122
+ xml = %{<?xml version='1.0' encoding='UTF-8' standalone='no' ?>
123
+ <!DOCTYPE OPS_envelope SYSTEM 'ops.dtd'>
124
+ <OPS_envelope>
125
+ <header>
126
+ <version>1.0</version>
127
+ </header>
128
+ <body>
129
+ <data_block>
130
+ <dt_scalar>Tom Jones</dt_scalar>
131
+ </data_block>
132
+ </body>
133
+ </OPS_envelope>}
134
+
135
+ resp = OpenSRS::XmlProcessor::Libxml.parse(xml)
136
+ resp.should == "Tom Jones"
137
+ end
138
+
139
+ it "should handle associate arrays with arrays of values" do
140
+ xml = %{<?xml version='1.0' encoding='UTF-8' standalone='no' ?>
141
+ <!DOCTYPE OPS_envelope SYSTEM 'ops.dtd'>
142
+ <OPS_envelope>
143
+ <header>
144
+ <version>1.0</version>
145
+ </header>
146
+ <body>
147
+ <data_block>
148
+ <dt_assoc>
149
+ <item key='domain_list'>
150
+ <dt_array>
151
+ <item key='0'>ns1.example.com</item>
152
+ <item key='1'>ns2.example.com</item>
153
+ <item key='2'>ns3.example.com</item>
154
+ </dt_array>
155
+ </item>
156
+ </dt_assoc>
157
+ </data_block>
158
+ </body>
159
+ </OPS_envelope>}
160
+
161
+ resp = OpenSRS::XmlProcessor::Libxml.parse(xml)
162
+ resp["domain_list"].class.should == Array
163
+ resp["domain_list"][0].should == "ns1.example.com"
164
+ resp["domain_list"][1].should == "ns2.example.com"
165
+ resp["domain_list"][2].should == "ns3.example.com"
166
+ end
167
+
168
+ it "should handle associative arrays containing other associative arrays" do
169
+ xml = %{<?xml version='1.0' encoding='UTF-8' standalone='no' ?>
170
+ <!DOCTYPE OPS_envelope SYSTEM 'ops.dtd'>
171
+ <OPS_envelope>
172
+ <header>
173
+ <version>1.0</version>
174
+ </header>
175
+ <body>
176
+ <data_block>
177
+ <dt_assoc>
178
+ <item key="contact_set">
179
+ <dt_assoc>
180
+ <item key='owner'>
181
+ <dt_assoc>
182
+ <item key='first_name'>Tom</item>
183
+ <item key='last_name'>Jones</item>
184
+ </dt_assoc>
185
+ </item>
186
+ <item key='tech'>
187
+ <dt_assoc>
188
+ <item key='first_name'>Anne</item>
189
+ <item key='last_name'>Smith</item>
190
+ </dt_assoc>
191
+ </item>
192
+ </dt_assoc>
193
+ </item>
194
+ </dt_assoc>
195
+ </data_block>
196
+ </body>
197
+ </OPS_envelope>}
198
+
199
+ resp = OpenSRS::XmlProcessor::Libxml.parse(xml)
200
+
201
+ resp["contact_set"]["owner"]["first_name"].should == "Tom"
202
+ resp["contact_set"]["owner"]["last_name"].should == "Jones"
203
+ resp["contact_set"]["tech"]["first_name"].should == "Anne"
204
+ resp["contact_set"]["tech"]["last_name"].should == "Smith"
205
+ end
206
+
207
+ context "with a balance enquiry example response" do
208
+ before(:each) do
209
+ xml = %{<?xml version='1.0' encoding='UTF-8' standalone='no' ?>
210
+ <!DOCTYPE OPS_envelope SYSTEM 'ops.dtd'>
211
+ <OPS_envelope>
212
+ <header>
213
+ <version>0.9</version>
214
+ </header>
215
+ <body>
216
+ <data_block>
217
+ <dt_assoc>
218
+ <item key="protocol">XCP</item>
219
+ <item key="action">REPLY</item>
220
+ <item key="object">BALANCE</item>
221
+ <item key="is_success">1</item>
222
+ <item key="response_code">200</item>
223
+ <item key="response_text">Command successful</item>
224
+ <item key="attributes">
225
+ <dt_assoc>
226
+ <item key="balance">8549.18</item>
227
+ <item key="hold_balance">1676.05</item>
228
+ </dt_assoc>
229
+ </item>
230
+ </dt_assoc>
231
+ </data_block>
232
+ </body>
233
+ </OPS_envelope>}
234
+
235
+ @resp = OpenSRS::XmlProcessor::Libxml.parse(xml)
236
+ end
237
+
238
+ it "produces a hash" do
239
+ @resp.should be_an_instance_of(Hash)
240
+ end
241
+
242
+ it "has top level keys" do
243
+ @resp["protocol"].should == "XCP"
244
+ @resp["action"].should == "REPLY"
245
+ @resp["object"].should == "BALANCE"
246
+ end
247
+
248
+ it "has second level keys" do
249
+ @resp["attributes"]["balance"].should == "8549.18"
250
+ @resp["attributes"]["hold_balance"].should == "1676.05"
251
+ end
252
+ end
253
+ end
254
+ end