active_utils 1.0.0

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,63 @@
1
+ module ActiveMerchant #:nodoc:
2
+ module PostsData #:nodoc:
3
+
4
+ def self.included(base)
5
+ base.superclass_delegating_accessor :ssl_strict
6
+ base.ssl_strict = true
7
+
8
+ base.class_attribute :retry_safe
9
+ base.retry_safe = false
10
+
11
+ base.superclass_delegating_accessor :open_timeout
12
+ base.open_timeout = 60
13
+
14
+ base.superclass_delegating_accessor :read_timeout
15
+ base.read_timeout = 60
16
+
17
+ base.superclass_delegating_accessor :logger
18
+ base.superclass_delegating_accessor :wiredump_device
19
+ end
20
+
21
+ def ssl_get(endpoint, headers={})
22
+ ssl_request(:get, endpoint, nil, headers)
23
+ end
24
+
25
+ def ssl_post(endpoint, data, headers = {})
26
+ ssl_request(:post, endpoint, data, headers)
27
+ end
28
+
29
+ def ssl_request(method, endpoint, data, headers)
30
+ handle_response(raw_ssl_request(method, endpoint, data, headers))
31
+ end
32
+
33
+ def raw_ssl_request(method, endpoint, data, headers = {})
34
+ connection = Connection.new(endpoint)
35
+ connection.open_timeout = open_timeout
36
+ connection.read_timeout = read_timeout
37
+ connection.retry_safe = retry_safe
38
+ connection.verify_peer = ssl_strict
39
+ connection.logger = logger
40
+ connection.tag = self.class.name
41
+ connection.wiredump_device = wiredump_device
42
+
43
+ connection.pem = @options[:pem] if @options
44
+ connection.pem_password = @options[:pem_password] if @options
45
+
46
+ connection.ignore_http_status = @options[:ignore_http_status] if @options
47
+
48
+ connection.request(method, data, headers)
49
+ end
50
+
51
+ private
52
+
53
+ def handle_response(response)
54
+ case response.code.to_i
55
+ when 200...300
56
+ response.body
57
+ else
58
+ raise ResponseError.new(response)
59
+ end
60
+ end
61
+
62
+ end
63
+ end
@@ -0,0 +1,16 @@
1
+ module ActiveMerchant #:nodoc:
2
+ module RequiresParameters #:nodoc:
3
+ def requires!(hash, *params)
4
+ params.each do |param|
5
+ if param.is_a?(Array)
6
+ raise ArgumentError.new("Missing required parameter: #{param.first}") unless hash.has_key?(param.first)
7
+
8
+ valid_options = param[1..-1]
9
+ raise ArgumentError.new("Parameter: #{param.first} must be one of #{valid_options.to_sentence(:words_connector => 'or')}") unless valid_options.include?(hash[param.first])
10
+ else
11
+ raise ArgumentError.new("Missing required parameter: #{param}") unless hash.has_key?(param)
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,22 @@
1
+ require 'digest/md5'
2
+
3
+ module ActiveMerchant #:nodoc:
4
+ module Utils #:nodoc:
5
+ def generate_unique_id
6
+ md5 = Digest::MD5.new
7
+ now = Time.now
8
+ md5 << now.to_s
9
+ md5 << String(now.usec)
10
+ md5 << String(rand(0))
11
+ md5 << String($$)
12
+ md5 << self.class.name
13
+ md5.hexdigest
14
+ end
15
+
16
+ module_function :generate_unique_id
17
+
18
+ def deprecated(message)
19
+ warn(Kernel.caller[1] + message)
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,81 @@
1
+ module ActiveMerchant #:nodoc:
2
+ module Validateable #:nodoc:
3
+ def valid?
4
+ errors.clear
5
+
6
+ before_validate if respond_to?(:before_validate, true)
7
+ validate if respond_to?(:validate, true)
8
+
9
+ errors.empty?
10
+ end
11
+
12
+ def initialize(attributes = {})
13
+ self.attributes = attributes
14
+ end
15
+
16
+ def errors
17
+ @errors ||= Errors.new(self)
18
+ end
19
+
20
+ private
21
+
22
+ def attributes=(attributes)
23
+ unless attributes.nil?
24
+ for key, value in attributes
25
+ send("#{key}=", value )
26
+ end
27
+ end
28
+ end
29
+
30
+ # This hash keeps the errors of the object
31
+ class Errors < HashWithIndifferentAccess
32
+
33
+ def initialize(base)
34
+ super() { |h, k| h[k] = [] ; h[k] }
35
+ @base = base
36
+ end
37
+
38
+ def count
39
+ size
40
+ end
41
+
42
+ def empty?
43
+ all? { |k, v| v && v.empty? }
44
+ end
45
+
46
+ # returns a specific fields error message.
47
+ # if more than one error is available we will only return the first. If no error is available
48
+ # we return an empty string
49
+ def on(field)
50
+ self[field].to_a.first
51
+ end
52
+
53
+ def add(field, error)
54
+ self[field] << error
55
+ end
56
+
57
+ def add_to_base(error)
58
+ add(:base, error)
59
+ end
60
+
61
+ def each_full
62
+ full_messages.each { |msg| yield msg }
63
+ end
64
+
65
+ def full_messages
66
+ result = []
67
+
68
+ self.each do |key, messages|
69
+ next if messages.blank?
70
+ if key == 'base'
71
+ result << "#{messages.first}"
72
+ else
73
+ result << "#{key.to_s.humanize} #{messages.first}"
74
+ end
75
+ end
76
+
77
+ result
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,3 @@
1
+ module ActiveUtils
2
+ VERSION = "1.0.0"
3
+ end
@@ -0,0 +1,19 @@
1
+ require 'active_support/core_ext/hash/indifferent_access'
2
+ require 'active_support/core_ext/hash/conversions'
3
+ require 'active_support/core_ext/class/attribute'
4
+
5
+ module ActiveMerchant
6
+ autoload :Connection, 'active_utils/common/connection'
7
+ autoload :Country, 'active_utils/common/country'
8
+ autoload :CountryCode, 'active_utils/common/country'
9
+ autoload :ActiveMerchantError, 'active_utils/common/error'
10
+ autoload :ConnectionError, 'active_utils/common/error'
11
+ autoload :RetriableConnectionError, 'active_utils/common/error'
12
+ autoload :ResponseError, 'active_utils/common/error'
13
+ autoload :ClientCertificateError, 'active_utils/common/error'
14
+ autoload :PostData, 'active_utils/common/post_data'
15
+ autoload :PostsData, 'active_utils/common/posts_data'
16
+ autoload :RequiresParameters, 'active_utils/common/requires_parameters'
17
+ autoload :Utils, 'active_utils/common/utils'
18
+ autoload :Validateable, 'active_utils/common/validateable'
19
+ end
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env ruby
2
+ $:.unshift(File.dirname(__FILE__) + '/../lib')
3
+
4
+ require 'rubygems'
5
+ require 'bundler'
6
+ Bundler.setup
7
+
8
+ require 'test/unit'
9
+ require 'active_utils'
10
+ require 'mocha'
11
+
12
+ include ActiveMerchant
@@ -0,0 +1,131 @@
1
+ require 'test_helper'
2
+
3
+ class ConnectionTest < Test::Unit::TestCase
4
+
5
+ def setup
6
+ @ok = stub(:code => 200, :message => 'OK', :body => 'success')
7
+
8
+ @endpoint = 'https://example.com/tx.php'
9
+ @connection = ActiveMerchant::Connection.new(@endpoint)
10
+ end
11
+
12
+ def test_connection_endpoint_parses_string_to_uri
13
+ assert_equal URI.parse(@endpoint), @connection.endpoint
14
+ end
15
+
16
+ def test_connection_endpoint_accepts_uri
17
+ endpoint = URI.parse(@endpoint)
18
+ connection = ActiveMerchant::Connection.new(endpoint)
19
+ assert_equal endpoint, connection.endpoint
20
+ end
21
+
22
+ def test_connection_endpoint_raises_uri_error
23
+ assert_raises URI::InvalidURIError do
24
+ ActiveMerchant::Connection.new("not a URI")
25
+ end
26
+ end
27
+
28
+ def test_successful_get_request
29
+ Net::HTTP.any_instance.expects(:get).with('/tx.php', {}).returns(@ok)
30
+ response = @connection.request(:get, nil, {})
31
+ assert_equal 'success', response.body
32
+ end
33
+
34
+ def test_successful_post_request
35
+ Net::HTTP.any_instance.expects(:post).with('/tx.php', 'data', ActiveMerchant::Connection::RUBY_184_POST_HEADERS).returns(@ok)
36
+ response = @connection.request(:post, 'data', {})
37
+ assert_equal 'success', response.body
38
+ end
39
+
40
+ def test_get_raises_argument_error_if_passed_data
41
+ assert_raise(ArgumentError) do
42
+ @connection.request(:get, 'data', {})
43
+ end
44
+ end
45
+
46
+ def test_request_raises_when_request_method_not_supported
47
+ assert_raise(ArgumentError) do
48
+ @connection.request(:delete, nil, {})
49
+ end
50
+ end
51
+
52
+
53
+
54
+ def test_default_read_timeout
55
+ assert_equal ActiveMerchant::Connection::READ_TIMEOUT, @connection.read_timeout
56
+ end
57
+
58
+ def test_override_read_timeout
59
+ @connection.read_timeout = 20
60
+ assert_equal 20, @connection.read_timeout
61
+ end
62
+
63
+ def test_default_open_timeout
64
+ @connection.open_timeout = 20
65
+ assert_equal 20, @connection.open_timeout
66
+ end
67
+
68
+ def test_default_verify_peer
69
+ assert_equal ActiveMerchant::Connection::VERIFY_PEER, @connection.verify_peer
70
+ end
71
+
72
+ def test_override_verify_peer
73
+ @connection.verify_peer = false
74
+ assert_equal false, @connection.verify_peer
75
+ end
76
+
77
+ def test_unrecoverable_exception
78
+ Net::HTTP.any_instance.expects(:post).raises(EOFError)
79
+
80
+ assert_raises(ActiveMerchant::ConnectionError) do
81
+ @connection.request(:post, '')
82
+ end
83
+ end
84
+
85
+ def test_failure_then_success_with_recoverable_exception
86
+ Net::HTTP.any_instance.expects(:post).times(2).raises(Errno::ECONNREFUSED).then.returns(@ok)
87
+
88
+ assert_nothing_raised do
89
+ @connection.request(:post, '')
90
+ end
91
+ end
92
+
93
+ def test_failure_limit_reached
94
+ Net::HTTP.any_instance.expects(:post).times(ActiveMerchant::Connection::MAX_RETRIES).raises(Errno::ECONNREFUSED)
95
+
96
+ assert_raises(ActiveMerchant::ConnectionError) do
97
+ @connection.request(:post, '')
98
+ end
99
+ end
100
+
101
+ def test_failure_then_success_with_retry_safe_enabled
102
+ Net::HTTP.any_instance.expects(:post).times(2).raises(EOFError).then.returns(@ok)
103
+
104
+ @connection.retry_safe = true
105
+
106
+ assert_nothing_raised do
107
+ @connection.request(:post, '')
108
+ end
109
+ end
110
+
111
+ def test_mixture_of_failures_with_retry_safe_enabled
112
+ Net::HTTP.any_instance.expects(:post).times(3).raises(Errno::ECONNRESET).
113
+ raises(Errno::ECONNREFUSED).
114
+ raises(EOFError)
115
+
116
+ @connection.retry_safe = true
117
+
118
+ assert_raises(ActiveMerchant::ConnectionError) do
119
+ @connection.request(:post, '')
120
+ end
121
+ end
122
+
123
+ def test_failure_with_ssl_certificate
124
+ Net::HTTP.any_instance.expects(:post).raises(OpenSSL::X509::CertificateError)
125
+
126
+ assert_raises(ActiveMerchant::ClientCertificateError) do
127
+ @connection.request(:post, '')
128
+ end
129
+ end
130
+
131
+ end
@@ -0,0 +1,31 @@
1
+ require 'test_helper'
2
+
3
+ class CountryCodeTest < Test::Unit::TestCase
4
+ def test_alpha2_country_code
5
+ code = CountryCode.new('CA')
6
+ assert_equal 'CA', code.value
7
+ assert_equal 'CA', code.to_s
8
+ assert_equal :alpha2, code.format
9
+ end
10
+
11
+ def test_lower_alpha2_country_code
12
+ code = CountryCode.new('ca')
13
+ assert_equal 'CA', code.value
14
+ assert_equal 'CA', code.to_s
15
+ assert_equal :alpha2, code.format
16
+ end
17
+
18
+ def test_alpha2_country_code
19
+ code = CountryCode.new('CAN')
20
+ assert_equal :alpha3, code.format
21
+ end
22
+
23
+ def test_numeric_code
24
+ code = CountryCode.new('004')
25
+ assert_equal :numeric, code.format
26
+ end
27
+
28
+ def test_invalid_code_format
29
+ assert_raise(CountryCodeFormatError){ CountryCode.new('Canada') }
30
+ end
31
+ end
@@ -0,0 +1,68 @@
1
+ require 'test_helper'
2
+
3
+ class CountryTest < Test::Unit::TestCase
4
+ def test_country_from_hash
5
+ country = Country.new(:name => 'Canada', :alpha2 => 'CA', :alpha3 => 'CAN', :numeric => '124')
6
+ assert_equal 'CA', country.code(:alpha2).value
7
+ assert_equal 'CAN', country.code(:alpha3).value
8
+ assert_equal '124', country.code(:numeric).value
9
+ assert_equal 'Canada', country.to_s
10
+ end
11
+
12
+ def test_country_for_alpha2_code
13
+ country = Country.find('CA')
14
+ assert_equal 'CA', country.code(:alpha2).value
15
+ assert_equal 'CAN', country.code(:alpha3).value
16
+ assert_equal '124', country.code(:numeric).value
17
+ assert_equal 'Canada', country.to_s
18
+ end
19
+
20
+ def test_country_for_alpha3_code
21
+ country = Country.find('CAN')
22
+ assert_equal 'Canada', country.to_s
23
+ end
24
+
25
+ def test_country_for_numeric_code
26
+ country = Country.find('124')
27
+ assert_equal 'Canada', country.to_s
28
+ end
29
+
30
+ def test_find_country_by_name
31
+ country = Country.find('Canada')
32
+ assert_equal 'Canada', country.to_s
33
+ end
34
+
35
+ def test_find_unknown_country_name
36
+ assert_raise(InvalidCountryCodeError) do
37
+ Country.find('Asskickistan')
38
+ end
39
+ end
40
+
41
+ def test_find_australia
42
+ country = Country.find('AU')
43
+ assert_equal 'AU', country.code(:alpha2).value
44
+
45
+ country = Country.find('Australia')
46
+ assert_equal 'AU', country.code(:alpha2).value
47
+ end
48
+
49
+ def test_find_united_kingdom
50
+ country = Country.find('GB')
51
+ assert_equal 'GB', country.code(:alpha2).value
52
+
53
+ country = Country.find('United Kingdom')
54
+ assert_equal 'GB', country.code(:alpha2).value
55
+ end
56
+
57
+ def test_raise_on_nil_name
58
+ assert_raise(InvalidCountryCodeError) do
59
+ Country.find(nil)
60
+ end
61
+ end
62
+
63
+ def test_country_names_are_alphabetized
64
+ country_names = Country::COUNTRIES.map { | each | each[:name] }
65
+ assert_equal(country_names.sort, country_names)
66
+ end
67
+
68
+ end
@@ -0,0 +1,50 @@
1
+ require 'test_helper'
2
+
3
+ class MyPost < ActiveMerchant::PostData
4
+ self.required_fields = [ :ccnumber, :ccexp, :firstname, :lastname, :username, :password, :order_id, :key, :time ]
5
+ end
6
+
7
+ class PostDataTest < Test::Unit::TestCase
8
+ def teardown
9
+ ActiveMerchant::PostData.required_fields = []
10
+ end
11
+
12
+ def test_element_assignment
13
+ name = 'Cody Fauser'
14
+ post = ActiveMerchant::PostData.new
15
+
16
+ post[:name] = name
17
+ assert_equal name, post[:name]
18
+ end
19
+
20
+ def test_ignore_blank_fields
21
+ post = ActiveMerchant::PostData.new
22
+ assert_equal 0, post.keys.size
23
+
24
+ post[:name] = ''
25
+ assert_equal 0, post.keys.size
26
+
27
+ post[:name] = nil
28
+ assert_equal 0, post.keys.size
29
+ end
30
+
31
+ def test_dont_ignore_required_blank_fields
32
+ ActiveMerchant::PostData.required_fields = [ :name ]
33
+ post = ActiveMerchant::PostData.new
34
+
35
+ assert_equal 0, post.keys.size
36
+
37
+ post[:name] = ''
38
+ assert_equal 1, post.keys.size
39
+ assert_equal '', post[:name]
40
+
41
+ post[:name] = nil
42
+ assert_equal 1, post.keys.size
43
+ assert_nil post[:name]
44
+ end
45
+
46
+ def test_subclass
47
+ post = MyPost.new
48
+ assert_equal [ :ccnumber, :ccexp, :firstname, :lastname, :username, :password, :order_id, :key, :time ], post.required_fields
49
+ end
50
+ end
@@ -0,0 +1,7 @@
1
+ require 'test_helper'
2
+
3
+ class UtilsTest < Test::Unit::TestCase
4
+ def test_unique_id_should_be_32_chars_and_alphanumeric
5
+ assert_match /^\w{32}$/, ActiveMerchant::Utils.generate_unique_id
6
+ end
7
+ end
@@ -0,0 +1,59 @@
1
+ require 'test_helper'
2
+
3
+ class Dood
4
+ include ActiveMerchant::Validateable
5
+
6
+ attr_accessor :name, :email, :country
7
+
8
+ def validate
9
+ errors.add "name", "cannot be empty" if name.blank?
10
+ errors.add "email", "cannot be empty" if email.blank?
11
+ errors.add_to_base "The country cannot be blank" if country.blank?
12
+ end
13
+
14
+ end
15
+
16
+ class ValidateableTest < Test::Unit::TestCase
17
+
18
+ def setup
19
+ @dood = Dood.new
20
+ end
21
+
22
+ def test_validation
23
+ assert ! @dood.valid?
24
+ assert ! @dood.errors.empty?
25
+ end
26
+
27
+ def test_assigns
28
+ @dood = Dood.new(:name => "tobi", :email => "tobi@neech.de", :country => 'DE')
29
+
30
+ assert_equal "tobi", @dood.name
31
+ assert_equal "tobi@neech.de", @dood.email
32
+ assert @dood.valid?
33
+ end
34
+
35
+ def test_multiple_calls
36
+ @dood.name = "tobi"
37
+ assert !@dood.valid?
38
+
39
+ @dood.email = "tobi@neech.de"
40
+ assert !@dood.valid?
41
+
42
+ @dood.country = 'DE'
43
+ assert @dood.valid?
44
+ end
45
+
46
+ def test_messages
47
+ @dood.valid?
48
+ assert_equal "cannot be empty", @dood.errors.on('name')
49
+ assert_equal "cannot be empty", @dood.errors.on('email')
50
+ assert_equal nil, @dood.errors.on('doesnt_exist')
51
+
52
+ end
53
+
54
+ def test_full_messages
55
+ @dood.valid?
56
+ assert_equal ["Email cannot be empty", "Name cannot be empty", "The country cannot be blank"], @dood.errors.full_messages.sort
57
+ end
58
+
59
+ end