epp 1.2.2 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,6 +1,8 @@
1
- = EPP (by {Ultraspeed}[http://ultraspeed.co.uk])
1
+ = EPP v1.3.0 (by {Ultraspeed}[http://ultraspeed.co.uk])
2
2
 
3
- The EPP gem provides basic functionality for connecting and making requests on EPP (Extensible Provisioning Protocol) servers. Currently, major providers Centralnic and Nominet have been tested.
3
+ The EPP gem provides basic functionality for connecting and making requests on EPP (Extensible Provisioning Protocol) servers. It has been fully tested against the RFC 5730 & 5734 specification.
4
+
5
+ Currently, major providers Centralnic and Nominet have been integrated using this gem. CoCCA is currently in testing.
4
6
 
5
7
  * {Nominet Standard EPP Documentation}[http://www.nominet.org.uk/registrars/systems/standardepp/]
6
8
  * {Centralnic Labs EPP Documentation}[http://labs.centralnic.com/epp/]
data/Rakefile CHANGED
@@ -14,6 +14,7 @@ begin
14
14
 
15
15
  # Dependencies
16
16
  gem.add_development_dependency "shoulda"
17
+ gem.add_development_dependency "mocha"
17
18
  gem.add_dependency "activesupport"
18
19
  gem.add_dependency "hpricot"
19
20
  end
@@ -24,7 +25,7 @@ end
24
25
  require 'rake/testtask'
25
26
  Rake::TestTask.new(:test) do |test|
26
27
  test.libs << 'lib' << 'test'
27
- test.pattern = 'test/**/*_test.rb'
28
+ test.pattern = 'test/**/test_*.rb'
28
29
  test.verbose = true
29
30
  end
30
31
 
@@ -33,7 +34,7 @@ begin
33
34
 
34
35
  Rcov::RcovTask.new do |test|
35
36
  test.libs << 'test'
36
- test.pattern = 'test/**/*_test.rb'
37
+ test.pattern = 'test/**/test_*.rb'
37
38
  test.verbose = true
38
39
  end
39
40
  rescue LoadError
@@ -45,7 +46,6 @@ end
45
46
  task :test => :check_dependencies
46
47
  task :default => :test
47
48
 
48
- require 'sdoc'
49
49
  require 'rake/rdoctask'
50
50
  Rake::RDocTask.new do |rdoc|
51
51
  version = File.exist?('VERSION') ? File.read('VERSION') : ""
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.2.2
1
+ 1.3.0
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{epp}
8
- s.version = "1.2.2"
8
+ s.version = "1.3.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Josh Delsman"]
12
- s.date = %q{2010-07-01}
12
+ s.date = %q{2010-07-07}
13
13
  s.description = %q{Basic functionality for connecting and making requests on EPP (Extensible Provisioning Protocol) servers}
14
14
  s.email = %q{jdelsman@ultraspeed.com}
15
15
  s.extra_rdoc_files = [
@@ -26,8 +26,18 @@ Gem::Specification.new do |s|
26
26
  "lib/epp/exceptions.rb",
27
27
  "lib/epp/server.rb",
28
28
  "lib/require_parameters.rb",
29
- "test/epp_test.rb",
30
- "test/test_helper.rb"
29
+ "test/test_epp.rb",
30
+ "test/test_helper.rb",
31
+ "test/xml/error.xml",
32
+ "test/xml/login_request.xml",
33
+ "test/xml/login_response.xml",
34
+ "test/xml/login_with_extensions_request.xml",
35
+ "test/xml/logout_request.xml",
36
+ "test/xml/logout_response.xml",
37
+ "test/xml/new_request.xml",
38
+ "test/xml/socket_preparation.xml",
39
+ "test/xml/test_request.xml",
40
+ "test/xml/test_response.xml"
31
41
  ]
32
42
  s.homepage = %q{http://github.com/ultraspeed/epp}
33
43
  s.rdoc_options = ["--charset=UTF-8"]
@@ -35,7 +45,7 @@ Gem::Specification.new do |s|
35
45
  s.rubygems_version = %q{1.3.7}
36
46
  s.summary = %q{EPP (Extensible Provisioning Protocol) for Ruby}
37
47
  s.test_files = [
38
- "test/epp_test.rb",
48
+ "test/test_epp.rb",
39
49
  "test/test_helper.rb"
40
50
  ]
41
51
 
@@ -45,15 +55,18 @@ Gem::Specification.new do |s|
45
55
 
46
56
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
47
57
  s.add_development_dependency(%q<shoulda>, [">= 0"])
58
+ s.add_development_dependency(%q<mocha>, [">= 0"])
48
59
  s.add_runtime_dependency(%q<activesupport>, [">= 0"])
49
60
  s.add_runtime_dependency(%q<hpricot>, [">= 0"])
50
61
  else
51
62
  s.add_dependency(%q<shoulda>, [">= 0"])
63
+ s.add_dependency(%q<mocha>, [">= 0"])
52
64
  s.add_dependency(%q<activesupport>, [">= 0"])
53
65
  s.add_dependency(%q<hpricot>, [">= 0"])
54
66
  end
55
67
  else
56
68
  s.add_dependency(%q<shoulda>, [">= 0"])
69
+ s.add_dependency(%q<mocha>, [">= 0"])
57
70
  s.add_dependency(%q<activesupport>, [">= 0"])
58
71
  s.add_dependency(%q<hpricot>, [">= 0"])
59
72
  end
@@ -1,11 +1,15 @@
1
1
  class EppErrorResponse < StandardError #:nodoc:
2
+ include RequiresParameters
3
+
2
4
  attr_accessor :response_xml, :response_code, :message
3
5
 
4
6
  # Generic EPP exception. Accepts a response code and a message
5
7
  def initialize(attributes = {})
6
- @response_xml = attributes[:xml]
7
- @response_code = attributes[:code]
8
- @message = attributes[:message]
8
+ requires!(attributes, :xml, :code, :message)
9
+
10
+ @response_xml = attributes[:xml]
11
+ @response_code = attributes[:code]
12
+ @message = attributes[:message]
9
13
  end
10
14
 
11
15
  def to_s
@@ -3,7 +3,7 @@ module Epp #:nodoc:
3
3
  include REXML
4
4
  include RequiresParameters
5
5
 
6
- attr_accessor :tag, :password, :server, :port, :old_server, :services, :lang, :extensions, :version
6
+ attr_accessor :tag, :password, :server, :port, :services, :lang, :extensions, :version
7
7
 
8
8
  # ==== Required Attrbiutes
9
9
  #
@@ -15,7 +15,6 @@ module Epp #:nodoc:
15
15
  #
16
16
  # * <tt>:port</tt> - The EPP standard port is 700. However, you can choose a different port to use.
17
17
  # * <tt>:clTRID</tt> - The client transaction identifier is an element that EPP specifies MAY be used to uniquely identify the command to the server. You are responsible for maintaining your own transaction identifier space to ensure uniqueness. Defaults to "ABC-12345"
18
- # * <tt>:old_server</tt> - Set to true to read and write frames in a way that is compatible with older EPP servers. Default is false.
19
18
  # * <tt>:lang</tt> - Set custom language attribute. Default is 'en'.
20
19
  # * <tt>:services</tt> - Use custom EPP services in the <login> frame. The defaults use the EPP standard domain, contact and host 1.0 services.
21
20
  # * <tt>:extensions</tt> - URLs to custom extensions to standard EPP. Use these to extend the standard EPP (e.g., Nominet uses extensions). Defaults to none.
@@ -27,45 +26,16 @@ module Epp #:nodoc:
27
26
  @password = attributes[:password]
28
27
  @server = attributes[:server]
29
28
  @port = attributes[:port] || 700
30
- @old_server = attributes[:old_server] || false
31
29
  @lang = attributes[:lang] || "en"
32
30
  @services = attributes[:services] || ["urn:ietf:params:xml:ns:domain-1.0", "urn:ietf:params:xml:ns:contact-1.0", "urn:ietf:params:xml:ns:host-1.0"]
33
31
  @extensions = attributes[:extensions] || []
34
- @version = attributes[:verison] || "1.0"
35
- @debug_log = attributes[:debug_log] || false
32
+ @version = attributes[:version] || "1.0"
36
33
 
37
34
  @logged_in = false
38
35
  end
39
36
 
40
- # Sends an XML request to the EPP server, and receives an XML response.
41
- # <tt><login></tt> and <tt><logout></tt> requests are also wrapped
42
- # around the request, so we can close the socket immediately after
43
- # the request is made.
44
- def request(xml)
45
- open_connection
46
-
47
- @logged_in = true if login
48
-
49
- begin
50
- puts "** EPP - Sending frame..." if @debug_log
51
- @response = send_request(xml)
52
- ensure
53
- if @logged_in && !old_server
54
- @logged_in = false if logout
55
- end
56
-
57
- close_connection
58
- end
59
-
60
- return @response
61
- end
62
-
63
- private
64
-
65
37
  # Sends a standard login request to the EPP server.
66
- def login
67
- puts "** EPP - Attempting login..." if @debug_log
68
-
38
+ def login
69
39
  xml = new_epp_request
70
40
 
71
41
  command = xml.root.add_element("command")
@@ -83,7 +53,6 @@ module Epp #:nodoc:
83
53
  services.add_element("objURI").text = "urn:ietf:params:xml:ns:contact-1.0"
84
54
  services.add_element("objURI").text = "urn:ietf:params:xml:ns:host-1.0"
85
55
 
86
- # Include schema extensions for registrars which require it
87
56
  extensions_container = services.add_element("svcExtension") unless extensions.empty?
88
57
 
89
58
  for uri in extensions
@@ -92,14 +61,12 @@ module Epp #:nodoc:
92
61
 
93
62
  command.add_element("clTRID").text = "ABC-12345"
94
63
 
95
- # Receive the login response
96
64
  response = Hpricot.XML(send_request(xml.to_s))
97
65
 
98
66
  result_message = (response/"epp"/"response"/"result"/"msg").text.strip
99
67
  result_code = (response/"epp"/"response"/"result").attr("code").to_i
100
68
 
101
69
  if result_code == 1000
102
- puts "** EPP - Successfully logged in." if @debug_log
103
70
  return true
104
71
  else
105
72
  raise EppErrorResponse.new(:xml => response, :code => result_code, :message => result_message)
@@ -107,22 +74,18 @@ module Epp #:nodoc:
107
74
  end
108
75
 
109
76
  # Sends a standard logout request to the EPP server.
110
- def logout
111
- puts "** EPP - Attempting logout..." if @debug_log
112
-
77
+ def logout
113
78
  xml = new_epp_request
114
79
 
115
80
  command = xml.root.add_element("command")
116
81
  login = command.add_element("logout")
117
82
 
118
- # Receive the logout response
119
83
  response = Hpricot.XML(send_request(xml.to_s))
120
84
 
121
85
  result_message = (response/"epp"/"response"/"result"/"msg").text.strip
122
86
  result_code = (response/"epp"/"response"/"result").attr("code").to_i
123
87
 
124
88
  if result_code == 1500
125
- puts "** EPP - Successfully logged out." if @debug_log
126
89
  return true
127
90
  else
128
91
  raise EppErrorResponse.new(:xml => response, :code => result_code, :message => result_message)
@@ -142,6 +105,36 @@ module Epp #:nodoc:
142
105
  return xml
143
106
  end
144
107
 
108
+ def connection
109
+ @connection ||= TCPSocket.new(server, port)
110
+ end
111
+
112
+ def socket
113
+ @socket ||= OpenSSL::SSL::SSLSocket.new(connection) if connection
114
+ end
115
+
116
+ # Sends an XML request to the EPP server, and receives an XML response.
117
+ # <tt><login></tt> and <tt><logout></tt> requests are also wrapped
118
+ # around the request, so we can close the socket immediately after
119
+ # the request is made.
120
+ def request(xml)
121
+ open_connection
122
+
123
+ @logged_in = true if login
124
+
125
+ begin
126
+ @response = send_request(xml)
127
+ ensure
128
+ if @logged_in
129
+ @logged_in = false if logout
130
+ end
131
+
132
+ close_connection
133
+ end
134
+
135
+ return @response
136
+ end
137
+
145
138
  # Wrapper which sends an XML frame to the server, and receives
146
139
  # the response frame in return.
147
140
  def send_request(xml)
@@ -154,40 +147,18 @@ module Epp #:nodoc:
154
147
  # the EPP <tt><greeting></tt> frame which is sent by the
155
148
  # server upon connection.
156
149
  def open_connection
157
- @connection = TCPSocket.new(server, port)
158
- @socket = OpenSSL::SSL::SSLSocket.new(@connection)
159
-
160
- # Synchronously close the connection & socket
161
- @socket.sync_close
162
-
163
- # Connect
164
- @socket.connect
165
-
166
- # Get the initial frame
167
- frame = get_frame
168
-
169
- if frame
170
- puts "EPP - Connection opened." if @debug_log
171
- return frame
172
- end
150
+ socket.sync_close
151
+ socket.connect
152
+
153
+ get_frame
173
154
  end
174
155
 
175
156
  # Closes the connection to the EPP server.
176
157
  def close_connection
177
- if defined?(@socket) and @socket.is_a?(OpenSSL::SSL::SSLSocket)
178
- @socket.close
179
- @socket = nil
180
- end
181
-
182
- if defined?(@connection) and @connection.is_a?(TCPSocket)
183
- @connection.close
184
- @connection = nil
185
- end
158
+ socket.close
159
+ connection.close
186
160
 
187
- if @connection.nil? and @socket.nil?
188
- puts "EPP - Connection closed." if @debug_log
189
- return true
190
- end
161
+ connection.closed? and socket.closed?
191
162
  end
192
163
 
193
164
  # Receive an EPP frame from the server. Since the connection is blocking,
@@ -195,48 +166,34 @@ module Epp #:nodoc:
195
166
  # the connection is broken, a SocketError will be raised. Otherwise,
196
167
  # it will return a string containing the XML from the server.
197
168
  def get_frame
198
- if old_server
199
- data = ""
200
- first_char = @socket.read(1)
201
-
202
- if first_char.nil? and @socket.eof?
203
- raise SocketError.new("Connection closed by remote server")
204
- elsif first_char.nil?
205
- raise SocketError.new("Error reading frame from remote server")
206
- else
207
- data << first_char
208
-
209
- while char = @socket.read(1)
210
- data << char
211
-
212
- return data if data =~ %r|<\/epp>\n$|mi # at end
213
- end
214
- end
215
- else
216
- header = @socket.read(4)
217
-
218
- if header.nil? and @socket.eof?
219
- raise SocketError.new("Connection closed by remote server")
220
- elsif header.nil?
221
- raise SocketError.new("Error reading frame from remote server")
222
- else
223
- unpacked_header = header.unpack("N")
224
- length = unpacked_header[0]
225
-
226
- if length < 5
227
- raise SocketError.new("Got bad frame header length of #{length} bytes from the server")
228
- else
229
- response = @socket.read(length - 4)
230
- end
231
- end
232
- end
169
+ header = socket.read(4)
170
+
171
+ raise SocketError.new("Connection closed by remote server") if header.nil? and socket.eof?
172
+ raise SocketError.new("Error reading frame from remote server") if header.nil?
173
+
174
+ length = header_size(header)
175
+
176
+ raise SocketError.new("Got bad frame header length of #{length} bytes from the server") if length < 5
177
+
178
+ response = socket.read(length - 4)
233
179
  end
234
180
 
235
181
  # Send an XML frame to the server. Should return the total byte
236
182
  # size of the frame sent to the server. If the socket returns EOF,
237
183
  # the connection has closed and a SocketError is raised.
238
184
  def send_frame(xml)
239
- @socket.write(old_server ? (xml + "\r\n") : ([xml.size + 4].pack("N") + xml))
185
+ socket.write(packed(xml) + xml)
186
+ end
187
+
188
+ # Pack the XML as a header for the EPP server.
189
+ def packed(xml)
190
+ [xml.size + 4].pack("N")
191
+ end
192
+
193
+ # Returns size of header of response from the EPP server.
194
+ def header_size(header)
195
+ unpacked_header = header.unpack("N")
196
+ unpacked_header[0]
240
197
  end
241
198
  end
242
199
  end
@@ -0,0 +1,361 @@
1
+ require 'test_helper'
2
+
3
+ class EppTest < Test::Unit::TestCase
4
+ context "EPP" do
5
+ context "server" do
6
+ setup do
7
+ @epp = Epp::Server.new(
8
+ :server => "test-epp.nominet.org.uk",
9
+ :tag => "TEST",
10
+ :password => "test"
11
+ )
12
+
13
+ @tcp_sock = mock('TCPSocket')
14
+ @ssl_sock = mock('OpenSSL::SSL::SSLSocket')
15
+ end
16
+
17
+ should "verify class name is Epp::Server" do
18
+ assert @epp.is_a?(Epp::Server)
19
+ end
20
+
21
+ should "require server, tag and password attributes" do
22
+ assert_raises ArgumentError do
23
+ epp = Epp::Server.new(:tag => "a", :password => "a")
24
+ end
25
+
26
+ assert_raises ArgumentError do
27
+ epp = Epp::Server.new(:server => "a", :password => "a")
28
+ end
29
+
30
+ assert_raises ArgumentError do
31
+ epp = Epp::Server.new(:server => "a", :tag => "a")
32
+ end
33
+
34
+ assert_nothing_raised do
35
+ epp = Epp::Server.new(:server => "a", :tag => "a", :password => "a")
36
+ end
37
+ end
38
+
39
+ should "set instance variables for attributes" do
40
+ epp = Epp::Server.new(
41
+ :tag => "TAG",
42
+ :password => "f00bar",
43
+ :server => "nominet-epp.server.org.uk",
44
+ :port => 8700,
45
+ :lang => "es",
46
+ :services => ["urn:ietf:params:xml:ns:domain-nom-ext-1.1.xsd"],
47
+ :extensions => ["domain-nom-ext-1.1.xsd"],
48
+ :version => "90.0"
49
+ )
50
+
51
+ assert_equal "TAG", epp.tag
52
+ assert_equal "f00bar", epp.password
53
+ assert_equal "nominet-epp.server.org.uk", epp.server
54
+ assert_equal 8700, epp.port
55
+ assert_equal "es", epp.lang
56
+ assert_equal ["urn:ietf:params:xml:ns:domain-nom-ext-1.1.xsd"], epp.services
57
+ assert_equal ["domain-nom-ext-1.1.xsd"], epp.extensions
58
+ assert_equal "90.0", epp.version
59
+ end
60
+
61
+ should "build a new XML request" do
62
+ xml = xml_file("new_request.xml")
63
+
64
+ assert @epp.new_epp_request.is_a?(REXML::Document)
65
+ assert_equal xml, @epp.new_epp_request.to_s
66
+ end
67
+
68
+ should "have a TCP socket" do
69
+ TCPSocket.expects(:new).returns(@tcp_sock)
70
+
71
+ assert @epp.connection
72
+ end
73
+
74
+ should "have a SSL socket" do
75
+ TCPSocket.expects(:new).returns(@tcp_sock)
76
+ OpenSSL::SSL::SSLSocket.expects(:new).returns(@ssl_sock)
77
+
78
+ assert @epp.socket
79
+ end
80
+
81
+ should "open connection and receive a greeting" do
82
+ prepare_socket!
83
+
84
+ assert @epp.open_connection
85
+ end
86
+
87
+ should "return true if connection closed" do
88
+ prepare_socket!
89
+
90
+ @epp.open_connection
91
+
92
+ @tcp_sock.expects(:close).returns(nil)
93
+ @ssl_sock.expects(:close).returns(nil)
94
+ @tcp_sock.expects(:closed?).returns(true)
95
+ @ssl_sock.expects(:closed?).returns(true)
96
+
97
+ assert @epp.close_connection
98
+ end
99
+
100
+ should "return false if TCP socket not closed" do
101
+ prepare_socket!
102
+
103
+ @epp.open_connection
104
+
105
+ @tcp_sock.expects(:close).returns(nil)
106
+ @ssl_sock.expects(:close).returns(nil)
107
+ @tcp_sock.expects(:closed?).returns(false)
108
+
109
+ assert !@epp.close_connection
110
+ end
111
+
112
+ should "return false if SSL socket not closed" do
113
+ prepare_socket!
114
+
115
+ @epp.open_connection
116
+
117
+ @tcp_sock.expects(:close).returns(nil)
118
+ @ssl_sock.expects(:close).returns(nil)
119
+ @tcp_sock.expects(:closed?).returns(true)
120
+ @ssl_sock.expects(:closed?).returns(false)
121
+
122
+ assert !@epp.close_connection
123
+ end
124
+
125
+ should "get frame from new EPP servers with a header of four bytes" do
126
+ prepare_socket!
127
+
128
+ @epp.open_connection
129
+
130
+ response = xml_file("test_response.xml")
131
+
132
+ @ssl_sock.expects(:read).with(4).returns("\000\000\003\"")
133
+ @ssl_sock.expects(:read).with(798).returns(response)
134
+
135
+ assert response, @epp.get_frame
136
+ end
137
+
138
+ should "raise exception if socket closed unexpectedly while getting frame" do
139
+ prepare_socket!
140
+ simulate_close!
141
+
142
+ @epp.open_connection
143
+ @epp.close_connection
144
+
145
+ @ssl_sock.expects(:read).with(4).returns(nil)
146
+ @ssl_sock.expects(:eof?).returns(true)
147
+
148
+ assert_raises SocketError do
149
+ @epp.get_frame
150
+ end
151
+ end
152
+
153
+ should "raise exception if header cannot be read when getting frame" do
154
+ prepare_socket!
155
+
156
+ @epp.open_connection
157
+
158
+ @ssl_sock.expects(:read).with(4).returns(nil)
159
+ @ssl_sock.expects(:eof?).returns(false)
160
+
161
+ assert_raises SocketError do
162
+ @epp.get_frame
163
+ end
164
+ end
165
+
166
+ should "send frame to an EPP server" do
167
+ prepare_socket!
168
+
169
+ @epp.open_connection
170
+
171
+ send = xml_file("test_request.xml")
172
+
173
+ @ssl_sock.expects(:write).with(@epp.packed(send) + send).returns(121)
174
+
175
+ assert_equal 121, @epp.send_frame(send)
176
+ end
177
+
178
+ should "create a packed header for EPP request" do
179
+ xml_to_send = "<xml><test/></xml>"
180
+ assert_equal "\000\000\000\026", @epp.packed(xml_to_send)
181
+ end
182
+
183
+ should "return size of header from EPP response" do
184
+ assert_equal [22], "\000\000\000\026".unpack("N")
185
+ assert_equal 22, @epp.header_size("\000\000\000\026")
186
+ end
187
+
188
+ should "send frame, and get response from server" do
189
+ prepare_socket!
190
+
191
+ @epp.open_connection
192
+
193
+ send = xml_file("test_request.xml")
194
+ receive = xml_file("test_response.xml")
195
+
196
+ @ssl_sock.expects(:write).with(@epp.packed(send) + send).returns(121)
197
+ @ssl_sock.expects(:read).with(4).returns("\000\000\003\"")
198
+ @ssl_sock.expects(:read).with(798).returns(receive)
199
+
200
+ assert receive, @epp.send_request(send)
201
+ end
202
+
203
+ should "login to the server" do
204
+ prepare_socket!
205
+
206
+ @epp.open_connection
207
+
208
+ send = xml_file("login_request.xml")
209
+ receive = xml_file("login_response.xml")
210
+
211
+ @ssl_sock.expects(:write).with(@epp.packed(send) + send)
212
+ @ssl_sock.expects(:read).with(4).returns("\000\000\0019")
213
+ @ssl_sock.expects(:read).with(309).returns(receive)
214
+
215
+ assert @epp.login
216
+ end
217
+
218
+ should "login to the server with extensions" do
219
+ prepare_socket!
220
+
221
+ epp = Epp::Server.new(
222
+ :server => "test-epp.nominet.org.uk",
223
+ :tag => "TEST",
224
+ :password => "test",
225
+ :extensions => ["urn:ietf:params:xml:ns:rgp-1.0"]
226
+ )
227
+
228
+ epp.open_connection
229
+
230
+ send = xml_file("login_with_extensions_request.xml")
231
+ receive = xml_file("login_response.xml")
232
+
233
+ @ssl_sock.expects(:write).with(epp.packed(send) + send)
234
+ @ssl_sock.expects(:read).with(4).returns("\000\000\0019")
235
+ @ssl_sock.expects(:read).with(309).returns(receive)
236
+
237
+ assert epp.login
238
+ end
239
+
240
+ should "raise exception if login returns anything other than 1500 response" do
241
+ prepare_socket!
242
+
243
+ @epp.open_connection
244
+
245
+ send = xml_file("login_request.xml")
246
+ receive = xml_file("error.xml")
247
+
248
+ @ssl_sock.expects(:write).with(@epp.packed(send) + send)
249
+ @ssl_sock.expects(:read).with(4).returns("\000\000\001\231")
250
+ @ssl_sock.expects(:read).with(405).returns(receive)
251
+
252
+ assert_raises EppErrorResponse do
253
+ @epp.login
254
+ end
255
+ end
256
+
257
+ should "log out of the server" do
258
+ prepare_socket!
259
+
260
+ @epp.open_connection
261
+
262
+ send = xml_file("logout_request.xml")
263
+ receive = xml_file("logout_response.xml")
264
+
265
+ @ssl_sock.expects(:write).with(@epp.packed(send) + send)
266
+ @ssl_sock.expects(:read).with(4).returns("\000\000\001I")
267
+ @ssl_sock.expects(:read).with(325).returns(receive)
268
+
269
+ assert @epp.logout
270
+ end
271
+
272
+ should "raise exception if logout returns anything other than 1500 response" do
273
+ prepare_socket!
274
+
275
+ @epp.open_connection
276
+
277
+ send = xml_file("logout_request.xml")
278
+ receive = xml_file("error.xml")
279
+
280
+ @ssl_sock.expects(:write).with(@epp.packed(send) + send)
281
+ @ssl_sock.expects(:read).with(4).returns("\000\000\001\231")
282
+ @ssl_sock.expects(:read).with(405).returns(receive)
283
+
284
+ assert_raises EppErrorResponse do
285
+ @epp.logout
286
+ end
287
+ end
288
+
289
+ should "wrap a request around a logging in and logging out request" do
290
+ prepare_socket!
291
+ simulate_close!
292
+
293
+ test_request = xml_file("test_request.xml")
294
+ test_response = xml_file("test_response.xml")
295
+
296
+ @epp.expects(:login).returns(true)
297
+ @epp.expects(:logout).returns(true)
298
+ @epp.expects(:send_request).with(test_request).returns(test_response)
299
+
300
+ @response = @epp.request(test_request)
301
+
302
+ assert_equal test_response, @response
303
+ end
304
+ end
305
+
306
+ context "exceptions" do
307
+ should "require XML, code and message attributes" do
308
+ assert_raises ArgumentError do
309
+ e = EppErrorResponse.new(:code => "a", :message => "a")
310
+ end
311
+
312
+ assert_raises ArgumentError do
313
+ e = EppErrorResponse.new(:xml => "a", :message => "a")
314
+ end
315
+
316
+ assert_raises ArgumentError do
317
+ e = EppErrorResponse.new(:xml => "a", :code => "a")
318
+ end
319
+
320
+ assert_nothing_raised do
321
+ e = EppErrorResponse.new(:xml => "a", :code => "a", :message => "a")
322
+ end
323
+ end
324
+
325
+ should "print error message to string" do
326
+ e = EppErrorResponse.new(
327
+ :xml => "<xml></xml>",
328
+ :code => 400,
329
+ :message => "Test error message"
330
+ )
331
+
332
+ assert_equal "Test error message (code 400)", e.to_s
333
+ end
334
+ end
335
+ end
336
+
337
+ private
338
+
339
+ def prepare_socket!
340
+ @response = xml_file("test_request.xml")
341
+
342
+ TCPSocket.expects(:new).returns(@tcp_sock)
343
+ OpenSSL::SSL::SSLSocket.expects(:new).returns(@ssl_sock)
344
+
345
+ @ssl_sock.expects(:sync_close).returns(false)
346
+ @ssl_sock.expects(:connect).returns(@ssl_sock)
347
+ @ssl_sock.expects(:read).with(4).returns("\000\000\003\r")
348
+ @ssl_sock.expects(:read).with(777).returns(@response)
349
+ end
350
+
351
+ def simulate_close!
352
+ @ssl_sock.expects(:close).returns(nil)
353
+ @tcp_sock.expects(:close).returns(nil)
354
+ @ssl_sock.expects(:closed?).returns(true)
355
+ @tcp_sock.expects(:closed?).returns(true)
356
+ end
357
+
358
+ def xml_file(name)
359
+ File.read(File.dirname(__FILE__) + "/xml/#{name}")
360
+ end
361
+ end
@@ -1,9 +1,11 @@
1
1
  require 'rubygems'
2
2
  require 'test/unit'
3
3
  require 'shoulda'
4
+ require 'mocha'
4
5
 
5
6
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
6
7
  $LOAD_PATH.unshift(File.dirname(__FILE__))
8
+
7
9
  require 'epp'
8
10
 
9
11
  class Test::Unit::TestCase
@@ -0,0 +1,14 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <epp xmlns="urn:ietf:params:xml:ns:epp-1.0"
3
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4
+ xsi:schemaLocation="urn:ietf:params:xml:ns:epp-1.0 epp-1.0.xsd">
5
+ <response>
6
+ <result code="2200">
7
+ <msg>Authentication error</msg>
8
+ </result>
9
+ <trID>
10
+ <clTRID>ABC-12345</clTRID>
11
+ <svTRID>54321-XYZ</svTRID>
12
+ </trID>
13
+ </response>
14
+ </epp>
@@ -0,0 +1 @@
1
+ <?xml version='1.0' encoding='UTF-8' standalone='no'?><epp xsi:schemaLocation='urn:ietf:params:xml:ns:epp-1.0 epp-1.0.xsd' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns='urn:ietf:params:xml:ns:epp-1.0'><command><login><clID>TEST</clID><pw>test</pw><options><version>1.0</version><lang>en</lang></options><svcs><objURI>urn:ietf:params:xml:ns:domain-1.0</objURI><objURI>urn:ietf:params:xml:ns:contact-1.0</objURI><objURI>urn:ietf:params:xml:ns:host-1.0</objURI></svcs></login><clTRID>ABC-12345</clTRID></command></epp>
@@ -0,0 +1,12 @@
1
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
2
+ <epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
3
+ <response>
4
+ <result code="1000">
5
+ <msg>Command completed successfully</msg>
6
+ </result>
7
+ <trID>
8
+ <clTRID>ABC-12345</clTRID>
9
+ <svTRID>54321-XYZ</svTRID>
10
+ </trID>
11
+ </response>
12
+ </epp>
@@ -0,0 +1 @@
1
+ <?xml version='1.0' encoding='UTF-8' standalone='no'?><epp xsi:schemaLocation='urn:ietf:params:xml:ns:epp-1.0 epp-1.0.xsd' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns='urn:ietf:params:xml:ns:epp-1.0'><command><login><clID>TEST</clID><pw>test</pw><options><version>1.0</version><lang>en</lang></options><svcs><objURI>urn:ietf:params:xml:ns:domain-1.0</objURI><objURI>urn:ietf:params:xml:ns:contact-1.0</objURI><objURI>urn:ietf:params:xml:ns:host-1.0</objURI><svcExtension><extURI>urn:ietf:params:xml:ns:rgp-1.0</extURI></svcExtension></svcs></login><clTRID>ABC-12345</clTRID></command></epp>
@@ -0,0 +1 @@
1
+ <?xml version='1.0' encoding='UTF-8' standalone='no'?><epp xsi:schemaLocation='urn:ietf:params:xml:ns:epp-1.0 epp-1.0.xsd' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns='urn:ietf:params:xml:ns:epp-1.0'><command><logout/></command></epp>
@@ -0,0 +1,12 @@
1
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
2
+ <epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
3
+ <response>
4
+ <result code="1500">
5
+ <msg>Command completed successfully; ending session</msg>
6
+ </result>
7
+ <trID>
8
+ <clTRID>ABC-12345</clTRID>
9
+ <svTRID>54321-XYZ</svTRID>
10
+ </trID>
11
+ </response>
12
+ </epp>
@@ -0,0 +1 @@
1
+ <?xml version='1.0' encoding='UTF-8' standalone='no'?><epp xsi:schemaLocation='urn:ietf:params:xml:ns:epp-1.0 epp-1.0.xsd' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns='urn:ietf:params:xml:ns:epp-1.0'/>
@@ -0,0 +1,27 @@
1
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
2
+ <epp xmlns="urn:ietf:params:xml:ns:epp-1.0"
3
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4
+ xsi:schemaLocation="urn:ietf:params:xml:ns:epp-1.0 epp-1.0.xsd">
5
+ <greeting>
6
+ <svID>CoCCA EPP Server - epp.cocca.iors.cx</svID>
7
+ <svDate>2010-07-07T12:46:33.0536Z</svDate>
8
+ <svcMenu>
9
+ <version>1.0</version>
10
+ <lang>en</lang>
11
+ <objURI>urn:ietf:params:xml:ns:contact-1.0</objURI>
12
+ <objURI>urn:ietf:params:xml:ns:domain-1.0</objURI>
13
+ <objURI>urn:ietf:params:xml:ns:host-1.0</objURI>
14
+ <svcExtension>
15
+ <extURI>urn:ietf:params:xml:ns:rgp-1.0</extURI>
16
+ </svcExtension>
17
+ </svcMenu>
18
+ <dcp>
19
+ <access><all/></access>
20
+ <statement>
21
+ <purpose><admin/><prov/></purpose>
22
+ <recipient><ours/><public/></recipient>
23
+ <retention><stated/></retention>
24
+ </statement>
25
+ </dcp>
26
+ </greeting>
27
+ </epp>
@@ -0,0 +1,4 @@
1
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
2
+ <epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
3
+ <hello/>
4
+ </epp>
@@ -0,0 +1,26 @@
1
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
2
+ <epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
3
+ <greeting>
4
+ <svID>Example EPP server epp.example.com</svID>
5
+ <svDate>2000-06-08T22:00:00.0Z</svDate>
6
+ <svcMenu>
7
+ <version>1.0</version>
8
+ <lang>en</lang>
9
+ <lang>fr</lang>
10
+ <objURI>urn:ietf:params:xml:ns:obj1</objURI>
11
+ <objURI>urn:ietf:params:xml:ns:obj2</objURI>
12
+ <objURI>urn:ietf:params:xml:ns:obj3</objURI>
13
+ <svcExtension>
14
+ <extURI>http://custom/obj1ext-1.0</extURI>
15
+ </svcExtension>
16
+ </svcMenu>
17
+ <dcp>
18
+ <access><all/></access>
19
+ <statement>
20
+ <purpose><admin/><prov/></purpose>
21
+ <recipient><ours/><public/></recipient>
22
+ <retention><stated/></retention>
23
+ </statement>
24
+ </dcp>
25
+ </greeting>
26
+ </epp>
metadata CHANGED
@@ -5,9 +5,9 @@ version: !ruby/object:Gem::Version
5
5
  prerelease: false
6
6
  segments:
7
7
  - 1
8
- - 2
9
- - 2
10
- version: 1.2.2
8
+ - 3
9
+ - 0
10
+ version: 1.3.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Josh Delsman
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-07-01 00:00:00 -04:00
18
+ date: 2010-07-07 00:00:00 -04:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -33,7 +33,7 @@ dependencies:
33
33
  type: :development
34
34
  version_requirements: *id001
35
35
  - !ruby/object:Gem::Dependency
36
- name: activesupport
36
+ name: mocha
37
37
  prerelease: false
38
38
  requirement: &id002 !ruby/object:Gem::Requirement
39
39
  none: false
@@ -44,10 +44,10 @@ dependencies:
44
44
  segments:
45
45
  - 0
46
46
  version: "0"
47
- type: :runtime
47
+ type: :development
48
48
  version_requirements: *id002
49
49
  - !ruby/object:Gem::Dependency
50
- name: hpricot
50
+ name: activesupport
51
51
  prerelease: false
52
52
  requirement: &id003 !ruby/object:Gem::Requirement
53
53
  none: false
@@ -60,6 +60,20 @@ dependencies:
60
60
  version: "0"
61
61
  type: :runtime
62
62
  version_requirements: *id003
63
+ - !ruby/object:Gem::Dependency
64
+ name: hpricot
65
+ prerelease: false
66
+ requirement: &id004 !ruby/object:Gem::Requirement
67
+ none: false
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ hash: 3
72
+ segments:
73
+ - 0
74
+ version: "0"
75
+ type: :runtime
76
+ version_requirements: *id004
63
77
  description: Basic functionality for connecting and making requests on EPP (Extensible Provisioning Protocol) servers
64
78
  email: jdelsman@ultraspeed.com
65
79
  executables: []
@@ -79,8 +93,18 @@ files:
79
93
  - lib/epp/exceptions.rb
80
94
  - lib/epp/server.rb
81
95
  - lib/require_parameters.rb
82
- - test/epp_test.rb
96
+ - test/test_epp.rb
83
97
  - test/test_helper.rb
98
+ - test/xml/error.xml
99
+ - test/xml/login_request.xml
100
+ - test/xml/login_response.xml
101
+ - test/xml/login_with_extensions_request.xml
102
+ - test/xml/logout_request.xml
103
+ - test/xml/logout_response.xml
104
+ - test/xml/new_request.xml
105
+ - test/xml/socket_preparation.xml
106
+ - test/xml/test_request.xml
107
+ - test/xml/test_response.xml
84
108
  has_rdoc: true
85
109
  homepage: http://github.com/ultraspeed/epp
86
110
  licenses: []
@@ -116,5 +140,5 @@ signing_key:
116
140
  specification_version: 3
117
141
  summary: EPP (Extensible Provisioning Protocol) for Ruby
118
142
  test_files:
119
- - test/epp_test.rb
143
+ - test/test_epp.rb
120
144
  - test/test_helper.rb
@@ -1,7 +0,0 @@
1
- require 'test_helper'
2
-
3
- class EppTest < Test::Unit::TestCase
4
- should "create tests" do
5
- flunk "Tests have not been written yet. Coming soon"
6
- end
7
- end