sage_pay 0.2.5 → 0.2.6

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.
@@ -1,28 +1,28 @@
1
1
  module SagePay
2
2
  module Server
3
- class TransactionRegistrationResponse
4
- attr_reader :vps_protocol, :status, :status_detail
3
+ class Response
4
+ class_inheritable_hash :key_converter, :value_converter, :instance_writer => false
5
5
 
6
- def self.from_response_body(response_body)
7
- key_converter = {
8
- "VPSProtocol" => :vps_protocol,
9
- "Status" => :status,
10
- "StatusDetail" => :status_detail,
11
- "VPSTxId" => :vps_tx_id,
12
- "SecurityKey" => :security_key,
13
- "NextURL" => :next_url
14
- }
6
+ self.key_converter = {
7
+ "VPSProtocol" => :vps_protocol,
8
+ "Status" => :status,
9
+ "StatusDetail" => :status_detail,
10
+ }
15
11
 
16
- value_converter = {
17
- :status => {
18
- "OK" => :ok,
19
- "MALFORMED" => :malformed,
20
- "INVALID" => :invalid,
21
- "ERROR" => :error
22
- }
12
+ self.value_converter = {
13
+ :status => {
14
+ "OK" => :ok,
15
+ "MALFORMED" => :malformed,
16
+ "INVALID" => :invalid,
17
+ "ERROR" => :error
23
18
  }
19
+ }
20
+
21
+ attr_reader :vps_protocol, :status, :status_detail
24
22
 
23
+ def self.from_response_body(response_body)
25
24
  attributes = {}
25
+
26
26
  response_body.each_line do |line|
27
27
  key, value = line.split('=', 2)
28
28
  unless key.nil? || value.nil?
@@ -65,30 +65,6 @@ module SagePay
65
65
  def error?
66
66
  status == :error
67
67
  end
68
-
69
- def vps_tx_id
70
- if ok?
71
- @vps_tx_id
72
- else
73
- raise RuntimeError, "Unable to retrieve the transaction id as the status was not OK."
74
- end
75
- end
76
-
77
- def security_key
78
- if ok?
79
- @security_key
80
- else
81
- raise RuntimeError, "Unable to retrieve the security key as the status was not OK."
82
- end
83
- end
84
-
85
- def next_url
86
- if ok?
87
- @next_url
88
- else
89
- raise RuntimeError, "Unable to retrieve the next URL as the status was not OK."
90
- end
91
- end
92
68
  end
93
69
  end
94
70
  end
@@ -7,7 +7,7 @@ Gem::Specification.new do |s|
7
7
  ## If your rubyforge_project name is different, then edit it and comment out
8
8
  ## the sub! line in the Rakefile
9
9
  s.name = 'sage_pay'
10
- s.version = '0.2.5'
10
+ s.version = '0.2.6'
11
11
  s.date = '2010-04-25'
12
12
  s.rubyforge_project = 'sage_pay'
13
13
 
@@ -56,24 +56,27 @@ gateway for accepting credit card payments through your web app.
56
56
  lib/sage_pay.rb
57
57
  lib/sage_pay/server.rb
58
58
  lib/sage_pay/server/address.rb
59
+ lib/sage_pay/server/command.rb
60
+ lib/sage_pay/server/notification.rb
61
+ lib/sage_pay/server/notification_response.rb
62
+ lib/sage_pay/server/registration.rb
63
+ lib/sage_pay/server/registration_response.rb
64
+ lib/sage_pay/server/release.rb
65
+ lib/sage_pay/server/response.rb
59
66
  lib/sage_pay/server/signature_verification_details.rb
60
67
  lib/sage_pay/server/transaction_code.rb
61
- lib/sage_pay/server/transaction_notification.rb
62
- lib/sage_pay/server/transaction_notification_response.rb
63
- lib/sage_pay/server/transaction_registration.rb
64
- lib/sage_pay/server/transaction_registration_response.rb
65
68
  lib/sage_pay/uri_fixups.rb
66
69
  lib/validatable-ext.rb
67
70
  lib/validations/validates_inclusion_of.rb
68
71
  sage_pay.gemspec
69
72
  spec/integration/sage_pay/server_spec.rb
70
73
  spec/sage_pay/server/address_spec.rb
74
+ spec/sage_pay/server/notification_response_spec.rb
75
+ spec/sage_pay/server/notification_spec.rb
76
+ spec/sage_pay/server/registration_response_spec.rb
77
+ spec/sage_pay/server/registration_spec.rb
71
78
  spec/sage_pay/server/signature_verification_details_spec.rb
72
79
  spec/sage_pay/server/transaction_code_spec.rb
73
- spec/sage_pay/server/transaction_notification_response_spec.rb
74
- spec/sage_pay/server/transaction_notification_spec.rb
75
- spec/sage_pay/server/transaction_registration_response_spec.rb
76
- spec/sage_pay/server/transaction_registration_spec.rb
77
80
  spec/sage_pay/server_spec.rb
78
81
  spec/sage_pay_spec.rb
79
82
  spec/spec_helper.rb
@@ -2,14 +2,20 @@ require 'spec_helper'
2
2
 
3
3
  if run_integration_specs?
4
4
  describe SagePay::Server, "integration specs" do
5
+ before(:each) do
6
+ SagePay::Server.default_registration_options = {
7
+ :mode => :simulator,
8
+ :vendor => "rubaidh",
9
+ :notification_url => "http://test.host/notification"
10
+ }
11
+ end
12
+
13
+ after(:each) do
14
+ SagePay::Server.default_registration_options = {}
15
+ end
16
+
5
17
  describe ".payment" do
6
18
  before(:each) do
7
- SagePay::Server.default_registration_options = {
8
- :mode => :simulator,
9
- :vendor => "rubaidh",
10
- :notification_url => "http://test.host/notification"
11
- }
12
-
13
19
  @payment = SagePay::Server.payment(
14
20
  :description => "Demo payment",
15
21
  :amount => 12.34,
@@ -18,26 +24,67 @@ if run_integration_specs?
18
24
  )
19
25
  end
20
26
 
21
- after(:each) do
22
- SagePay::Server.default_registration_options = {}
23
- end
24
-
25
27
  it "should successfully register the payment with SagePay" do
26
- @payment.register!.should_not be_nil
28
+ @payment.run!.should_not be_nil
27
29
  end
28
30
 
29
31
  it "should be a valid registered payment" do
30
- registration = @payment.register!
32
+ registration = @payment.run!
33
+ registration.should be_ok
34
+ end
35
+
36
+ it "should have a next URL" do
37
+ registration = @payment.run!
38
+ registration.next_url.should_not be_nil
39
+ end
40
+
41
+ it "should allow us to follow the next URL and the response should be successful" do
42
+ registration = @payment.run!
43
+ uri = URI.parse(registration.next_url)
44
+ request = Net::HTTP::Get.new(uri.request_uri)
45
+ http = Net::HTTP.new(uri.host, uri.port)
46
+ http.use_ssl = true if uri.scheme == "https"
47
+ http.start { |http|
48
+ http.request(request)
49
+ }
50
+ end
51
+
52
+ it "should allow us to retrieve signature verification details" do
53
+ @payment.run!
54
+ sig_details = @payment.signature_verification_details
55
+
56
+ sig_details.should_not be_nil
57
+ sig_details.security_key.should_not be_nil
58
+ sig_details.vendor.should_not be_nil
59
+ end
60
+ end
61
+
62
+ describe ".deferred" do
63
+ before(:each) do
64
+ @payment = SagePay::Server.deferred(
65
+ :description => "Demo payment",
66
+ :amount => 12.34,
67
+ :currency => "GBP",
68
+ :billing_address => address_factory
69
+ )
70
+ end
71
+
72
+ it "should successfully register the deferred payment with SagePay" do
73
+ @payment.run!.should_not be_nil
74
+ end
75
+
76
+ it "should be a valid deferred payment" do
77
+ registration = @payment.run!
31
78
  registration.should be_ok
32
79
  end
33
80
 
34
81
  it "should have a next URL" do
35
- registration = @payment.register!
82
+ registration = @payment.run!
36
83
  registration.next_url.should_not be_nil
37
84
  end
38
85
 
39
86
  it "should allow us to follow the next URL and the response should be successful" do
40
- registration = @payment.register!
87
+ registration = @payment.run!
41
88
  uri = URI.parse(registration.next_url)
42
89
  request = Net::HTTP::Get.new(uri.request_uri)
43
90
  http = Net::HTTP.new(uri.host, uri.port)
@@ -48,7 +95,7 @@ if run_integration_specs?
48
95
  end
49
96
 
50
97
  it "should allow us to retrieve signature verification details" do
51
- @payment.register!
98
+ @payment.run!
52
99
  sig_details = @payment.signature_verification_details
53
100
 
54
101
  sig_details.should_not be_nil
@@ -0,0 +1,75 @@
1
+ require 'spec_helper'
2
+
3
+ include SagePay::Server
4
+
5
+ describe NotificationResponse do
6
+ it "should work straight from the factory" do
7
+ lambda {
8
+ notification_response_factory.should be_valid
9
+ }.should_not raise_error
10
+ end
11
+
12
+ describe "validations" do
13
+ it { validates_the_presence_of(:notification_response, :status) }
14
+ it { validates_the_presence_of(:notification_response, :redirect_url) }
15
+
16
+ it "validates the presence of the status_detail field only if the status is something other than OK" do
17
+ notification_response = notification_response_factory(:status => :ok, :status_detail => nil)
18
+ notification_response.should be_valid
19
+
20
+ notification_response = notification_response_factory(:status => :invalid, :status_detail => "Invalid request!")
21
+ notification_response.should be_valid
22
+
23
+ notification_response = notification_response_factory(:status => :invalid, :status_detail => "")
24
+ notification_response.should_not be_valid
25
+ notification_response.errors.on(:status_detail).should include("can't be empty")
26
+ end
27
+
28
+ it { validates_the_length_of(:notification_response, :redirect_url, :max => 255) }
29
+ it { validates_the_length_of(:notification_response, :status_detail, :max => 255) }
30
+
31
+ it "should allow the status to be one of :ok, :invalid or :error" do
32
+ notification_response = notification_response_factory(:status => :ok)
33
+ notification_response.should be_valid
34
+
35
+ notification_response = notification_response_factory(:status => :invalid)
36
+ notification_response.should be_valid
37
+
38
+ notification_response = notification_response_factory(:status => :error)
39
+ notification_response.should be_valid
40
+
41
+ notification_response = notification_response_factory(:status => :chickens)
42
+ notification_response.should_not be_valid
43
+ notification_response.errors.on(:status).should include("is not in the list")
44
+ end
45
+ end
46
+
47
+ describe "#response" do
48
+ it "should produce the expected response for an OK status" do
49
+ notification_response = notification_response_factory(
50
+ :status => :ok,
51
+ :redirect_url => "http://test.host/some/redirect",
52
+ :status_detail => nil
53
+ )
54
+ notification_response.response.should == <<-RESPONSE.chomp
55
+ Status=OK\r
56
+ RedirectURL=http://test.host/some/redirect
57
+ RESPONSE
58
+ end
59
+
60
+ it "should produce the expected response for an invalid status" do
61
+ notification_response = notification_response_factory(
62
+ :status => :invalid,
63
+ :redirect_url => "http://test.host/some/redirect",
64
+ :status_detail => "Totally didn't expect that notification, dude."
65
+ )
66
+ # FIXME: I'm asserting here that I don't have to URI-encode the body
67
+ # here. OK?
68
+ notification_response.response.should == <<-RESPONSE.chomp
69
+ Status=INVALID\r
70
+ RedirectURL=http://test.host/some/redirect\r
71
+ StatusDetail=Totally didn't expect that notification, dude.\r
72
+ RESPONSE
73
+ end
74
+ end
75
+ end
@@ -2,14 +2,40 @@ require 'spec_helper'
2
2
 
3
3
  include SagePay::Server
4
4
 
5
- describe TransactionNotification do
5
+ describe Notification do
6
6
  it "should work straight from the factory" do
7
7
  lambda {
8
- transaction_notification_factory.should_not be_nil
8
+ notification_factory.should_not be_nil
9
9
  }.should_not raise_error
10
10
  end
11
11
 
12
12
  describe ".from_params" do
13
+ before(:each) do
14
+ @params = {
15
+ "VPSProtocol" => "2.23",
16
+ "TxType" => "PAYMENT",
17
+ "VendorTxCode" => "unique-tx-code",
18
+ "VPSTxId" => "{728A5721-B45F-4570-937E-90A16B0A5000}",
19
+ "Status" => "OK",
20
+ "StatusDetail" => "2000 : Card processed successfully.", # FIXME: Make this match reality
21
+ "TxAuthNo" => "1234567890",
22
+ "AVSCV2" => "ALL MATCH",
23
+ "AddressResult" => "MATCHED",
24
+ "PostCodeResult" => "MATCHED",
25
+ "CV2Result" => "MATCHED",
26
+ "GiftAid" => "0",
27
+ "3DSecureStatus" => "OK",
28
+ "CAVV" => "Something?",
29
+ "AddressStatus" => "CONFIRMED",
30
+ "PayerStatus" => "VERIFIED",
31
+ "CardType" => "VISA",
32
+ "Last4Digits" => "1234",
33
+ # FIXME: Calculated manually using the information above. Should
34
+ # really get one from a sample transaction...
35
+ "VPSSignature" => "6AB7A7FFB5369AF953CD57A84D5C2979"
36
+ }
37
+ end
38
+
13
39
  context "with an OK status" do
14
40
  before(:each) do
15
41
  signature_verification_details = mock("Signature verification details",
@@ -17,36 +43,12 @@ describe TransactionNotification do
17
43
  :security_key => "17F13DCBD8"
18
44
  )
19
45
 
20
- @params = {
21
- "VPSProtocol" => "2.23",
22
- "TxType" => "PAYMENT",
23
- "VendorTxCode" => "unique-tx-code",
24
- "VPSTxId" => "{728A5721-B45F-4570-937E-90A16B0A5000}",
25
- "Status" => "OK",
26
- "StatusDetail" => "2000 : Card processed successfully.", # FIXME: Make this match reality
27
- "TxAuthNo" => "1234567890",
28
- "AVSCV2" => "ALL MATCH",
29
- "AddressResult" => "MATCHED",
30
- "PostCodeResult" => "MATCHED",
31
- "CV2Result" => "MATCHED",
32
- "GiftAid" => "0",
33
- "3DSecureStatus" => "OK",
34
- "CAVV" => "Something?",
35
- "AddressStatus" => "CONFIRMED",
36
- "PayerStatus" => "VERIFIED",
37
- "CardType" => "VISA",
38
- "Last4Digits" => "1234",
39
- # FIXME: Calculated manually using the information above. Should
40
- # really get one from a sample transaction...
41
- "VPSSignature" => "6AB7A7FFB5369AF953CD57A84D5C2979"
42
- }
43
-
44
- @notification = TransactionNotification.from_params(@params, signature_verification_details)
46
+ @notification = Notification.from_params(@params, signature_verification_details)
45
47
  end
46
48
 
47
49
  it "should successfully parse the params" do
48
50
  lambda {
49
- TransactionNotification.from_params(@params).should_not be_nil
51
+ Notification.from_params(@params).should_not be_nil
50
52
  }.should_not raise_error
51
53
  end
52
54
 
@@ -149,6 +151,42 @@ describe TransactionNotification do
149
151
  it "should report that the vps signature is valid" do
150
152
  @notification.should be_valid_signature
151
153
  end
154
+
155
+ it "should generate a successful response" do
156
+ mock_notification_response = mock(NotificationResponse, :response => "some response")
157
+ NotificationResponse.should_receive(:new).with(:status => :ok, :redirect_url => "mock redirect url").and_return(mock_notification_response)
158
+ @notification.response("mock redirect url").should == "some response"
159
+ end
160
+ end
161
+
162
+ context "with an invalid signature" do
163
+ before(:each) do
164
+ signature_verification_details = mock("Signature verification details",
165
+ :vendor => "rubaidh",
166
+ :security_key => "different security key"
167
+ )
168
+
169
+ @notification = Notification.from_params(@params, signature_verification_details)
170
+ end
171
+
172
+ it "should generate a failed response" do
173
+ mock_notification_response = mock(NotificationResponse, :response => "can haz failure")
174
+ NotificationResponse.should_receive(:new).with(:status => :invalid, :redirect_url => "mock redirect url", :status_detail => "Signature did not match our expectations").and_return(mock_notification_response)
175
+ @notification.response("mock redirect url").should == "can haz failure"
176
+ end
177
+ end
178
+
179
+ context "with a block supplied for the signature verification details" do
180
+ it "should still validate the signature correctly" do
181
+ notification = Notification.from_params(@params) do |attributes|
182
+ mock("Signature verification details",
183
+ :vendor => "rubaidh",
184
+ :security_key => "17F13DCBD8"
185
+ )
186
+ end
187
+
188
+ notification.should be_valid_signature
189
+ end
152
190
  end
153
191
  end
154
192
  end
@@ -2,10 +2,10 @@ require 'spec_helper'
2
2
 
3
3
  include SagePay::Server
4
4
 
5
- describe TransactionRegistrationResponse do
5
+ describe RegistrationResponse do
6
6
  it "should work straight from the factory" do
7
7
  lambda {
8
- transaction_registration_response_factory.should_not be_nil
8
+ registration_response_factory.should_not be_nil
9
9
  }.should_not raise_error
10
10
  end
11
11
 
@@ -17,12 +17,12 @@ VPSProtocol=2.23
17
17
  Status=INVALID
18
18
  StatusDetail=4000 : The VendorName is invalid or the account is not active.
19
19
  RESPONSE
20
- @response = TransactionRegistrationResponse.from_response_body(@response_body)
20
+ @response = RegistrationResponse.from_response_body(@response_body)
21
21
  end
22
22
 
23
23
  it "should successfully parse the body" do
24
24
  lambda {
25
- TransactionRegistrationResponse.from_response_body(@response_body)
25
+ RegistrationResponse.from_response_body(@response_body)
26
26
  }.should_not raise_error
27
27
  end
28
28
 
@@ -72,12 +72,12 @@ VPSProtocol=2.23
72
72
  Status=MALFORMED
73
73
  StatusDetail=5000 : Your request had too many toes.
74
74
  RESPONSE
75
- @response = TransactionRegistrationResponse.from_response_body(@response_body)
75
+ @response = RegistrationResponse.from_response_body(@response_body)
76
76
  end
77
77
 
78
78
  it "should successfully parse the body" do
79
79
  lambda {
80
- TransactionRegistrationResponse.from_response_body(@response_body)
80
+ RegistrationResponse.from_response_body(@response_body)
81
81
  }.should_not raise_error
82
82
  end
83
83
 
@@ -127,12 +127,12 @@ VPSProtocol=2.23
127
127
  Status=ERROR
128
128
  StatusDetail=5000 : SagePay blew up.
129
129
  RESPONSE
130
- @response = TransactionRegistrationResponse.from_response_body(@response_body)
130
+ @response = RegistrationResponse.from_response_body(@response_body)
131
131
  end
132
132
 
133
133
  it "should successfully parse the body" do
134
134
  lambda {
135
- TransactionRegistrationResponse.from_response_body(@response_body)
135
+ RegistrationResponse.from_response_body(@response_body)
136
136
  }.should_not raise_error
137
137
  end
138
138
 
@@ -186,12 +186,12 @@ SecurityKey=17F13DCBD8
186
186
  NextURL=https://test.sagepay.com/Simulator/VSPServerPaymentPage.asp?TransactionID={728A5721-B45F-4570-937E-90A16B0A5000}
187
187
  RESPONSE
188
188
 
189
- @response = TransactionRegistrationResponse.from_response_body(@response_body)
189
+ @response = RegistrationResponse.from_response_body(@response_body)
190
190
  end
191
191
 
192
192
  it "should successfully parse the body" do
193
193
  lambda {
194
- TransactionRegistrationResponse.from_response_body(@response_body)
194
+ RegistrationResponse.from_response_body(@response_body)
195
195
  }.should_not raise_error
196
196
  end
197
197