braintree 2.76.0 → 2.77.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/lib/braintree.rb +12 -0
  3. data/lib/braintree/apple_pay.rb +29 -0
  4. data/lib/braintree/apple_pay_card.rb +1 -1
  5. data/lib/braintree/apple_pay_gateway.rb +37 -0
  6. data/lib/braintree/apple_pay_options.rb +19 -0
  7. data/lib/braintree/authorization_adjustment.rb +20 -0
  8. data/lib/braintree/dispute.rb +78 -9
  9. data/lib/braintree/dispute/evidence.rb +18 -0
  10. data/lib/braintree/dispute/history_event.rb +14 -0
  11. data/lib/braintree/dispute/transaction.rb +18 -0
  12. data/lib/braintree/dispute_gateway.rb +118 -0
  13. data/lib/braintree/dispute_search.rb +30 -0
  14. data/lib/braintree/document_upload.rb +34 -0
  15. data/lib/braintree/document_upload_gateway.rb +32 -0
  16. data/lib/braintree/error_codes.rb +17 -0
  17. data/lib/braintree/facilitated_details.rb +19 -0
  18. data/lib/braintree/gateway.rb +12 -0
  19. data/lib/braintree/http.rb +60 -12
  20. data/lib/braintree/successful_result.rb +1 -1
  21. data/lib/braintree/test/credit_card.rb +6 -0
  22. data/lib/braintree/transaction.rb +4 -0
  23. data/lib/braintree/version.rb +1 -1
  24. data/lib/braintree/webhook_testing_gateway.rb +196 -19
  25. data/spec/fixtures/files/bt_logo.png +0 -0
  26. data/spec/fixtures/files/gif_extension_bt_logo.gif +0 -0
  27. data/spec/fixtures/files/malformed_pdf.pdf +1 -0
  28. data/spec/httpsd.pid +1 -1
  29. data/spec/integration/braintree/apple_pay_spec.rb +92 -0
  30. data/spec/integration/braintree/coinbase_spec.rb +15 -12
  31. data/spec/integration/braintree/dispute_search_spec.rb +49 -0
  32. data/spec/integration/braintree/dispute_spec.rb +216 -0
  33. data/spec/integration/braintree/document_upload_spec.rb +55 -0
  34. data/spec/integration/braintree/http_spec.rb +8 -0
  35. data/spec/integration/braintree/payment_method_spec.rb +5 -16
  36. data/spec/integration/braintree/transaction_spec.rb +21 -4
  37. data/spec/spec_helper.rb +3 -2
  38. data/spec/unit/braintree/apple_pay_card_spec.rb +6 -0
  39. data/spec/unit/braintree/dispute_search_spec.rb +59 -0
  40. data/spec/unit/braintree/dispute_spec.rb +331 -8
  41. data/spec/unit/braintree/document_upload_spec.rb +35 -0
  42. data/spec/unit/braintree/http_spec.rb +21 -0
  43. data/spec/unit/braintree/transaction_spec.rb +17 -0
  44. data/spec/unit/braintree/webhook_notification_spec.rb +74 -51
  45. metadata +24 -3
@@ -0,0 +1 @@
1
+ XXXXXXXXXXX¾?^gfkbfu¶šÙú”¼Åxc¯ÄÖñ•:x„BºS·É=] óqçÅÒÐwî+= x wÁ¼/7ú7ÀݛeÀÅA¿8?À­‹6Á2[î(†¤Ö@+3[ß}
@@ -1 +1 @@
1
- 13345
1
+ 3946
@@ -0,0 +1,92 @@
1
+ require File.expand_path(File.dirname(__FILE__) + "/../../spec_helper")
2
+
3
+ describe Braintree::ApplePayGateway do
4
+ before(:each) do
5
+ gateway = Braintree::Gateway.new(
6
+ :client_id => "client_id$#{Braintree::Configuration.environment}$integration_client_id",
7
+ :client_secret => "client_secret$#{Braintree::Configuration.environment}$integration_client_secret",
8
+ :logger => Logger.new("/dev/null")
9
+ )
10
+
11
+ result = gateway.merchant.create(
12
+ :email => "name@email.com",
13
+ :country_code_alpha3 => "USA",
14
+ :payment_methods => ["credit_card", "paypal"]
15
+ )
16
+
17
+ @gateway = Braintree::Gateway.new(
18
+ :access_token => result.credentials.access_token,
19
+ :logger => Logger.new("/dev/null")
20
+ )
21
+ end
22
+
23
+ describe "register_domain" do
24
+ it "registers an apple pay domain" do
25
+ result = @gateway.apple_pay.register_domain("www.example.com")
26
+ result.should be_success
27
+ end
28
+
29
+ it "gets a validation error when attempting to register no domains" do
30
+ result = @gateway.apple_pay.register_domain("")
31
+ result.should_not be_success
32
+ result.errors.for(:apple_pay)[0].message.should eq("Domain name is required.")
33
+ end
34
+ end
35
+
36
+ describe "unregister_domain" do
37
+ it "unregisters an apple pay domain" do
38
+ domain = "example.org"
39
+ result = @gateway.apple_pay.register_domain(domain)
40
+ result.should be_success
41
+
42
+ result = @gateway.apple_pay.unregister_domain(domain)
43
+ result.should be_success
44
+ @gateway.apple_pay.registered_domains.apple_pay_options.domains.should be_empty
45
+ end
46
+
47
+ it "unregisters an apple pay domain with scheme in url" do
48
+ domain = "http://example.org"
49
+ result = @gateway.apple_pay.register_domain(domain)
50
+ result.should be_success
51
+
52
+ result = @gateway.apple_pay.unregister_domain(domain)
53
+ result.should be_success
54
+ @gateway.apple_pay.registered_domains.apple_pay_options.domains.should be_empty
55
+ end
56
+
57
+ it "does not fail when unregistering a non-registered domain" do
58
+ result = @gateway.apple_pay.unregister_domain("unregistered.com")
59
+ result.should be_success
60
+ end
61
+
62
+ it "escapes the unregistered domain query parameter" do
63
+ domain = "ex&mple.org"
64
+ result = @gateway.apple_pay.register_domain(domain)
65
+ result.should be_success
66
+ @gateway.apple_pay.registered_domains.apple_pay_options.domains.should_not be_empty
67
+
68
+ result = @gateway.apple_pay.unregister_domain(domain)
69
+ result.should be_success
70
+ @gateway.apple_pay.registered_domains.apple_pay_options.domains.should be_empty
71
+ end
72
+ end
73
+
74
+ describe "registered_domains" do
75
+ it "returns registered domains" do
76
+ result = @gateway.apple_pay.register_domain("www.example.com")
77
+ result.should be_success
78
+ result = @gateway.apple_pay.register_domain("www.example.org")
79
+ result.should be_success
80
+
81
+ result = @gateway.apple_pay.registered_domains
82
+ result.should be_success
83
+ result.apple_pay_options.domains.should =~ ["www.example.org", "www.example.com"]
84
+ end
85
+
86
+ it "returns an empty list if no domains are registered" do
87
+ result = @gateway.apple_pay.registered_domains
88
+ result.should be_success
89
+ result.apple_pay_options.domains.should == []
90
+ end
91
+ end
92
+ end
@@ -8,24 +8,27 @@ describe "Coinbase" do
8
8
  end
9
9
  end
10
10
 
11
- it "works for transaction#create" do
11
+ it "is no longer supported with transaction#create" do
12
12
  result = Braintree::Transaction.sale(:payment_method_nonce => Braintree::Test::Nonce::Coinbase, :amount => "0.02")
13
- result.should be_success
14
- assert_valid_coinbase_attrs(result.transaction.coinbase_details)
13
+ result.should_not be_success
14
+
15
+ result.errors.for(:transaction).first.code.should == Braintree::ErrorCodes::PaymentMethod::PaymentMethodNoLongerSupported
15
16
  end
16
17
 
17
- it "works for vaulting" do
18
+ it "is no longer supported for vaulting" do
18
19
  customer = Braintree::Customer.create!
19
- vaulted = Braintree::PaymentMethod.create(:customer_id => customer.id, :payment_method_nonce => Braintree::Test::Nonce::Coinbase).payment_method
20
- assert_valid_coinbase_attrs(vaulted)
20
+ result = Braintree::PaymentMethod.create(:customer_id => customer.id, :payment_method_nonce => Braintree::Test::Nonce::Coinbase)
21
+ result.should_not be_success
21
22
 
22
- found = Braintree::PaymentMethod.find(vaulted.token).payment_method
23
- assert_valid_coinbase_attrs(found)
23
+ result.errors.for(:coinbase_account).first.code.should == Braintree::ErrorCodes::PaymentMethod::PaymentMethodNoLongerSupported
24
24
  end
25
25
 
26
- it "is returned on Customers" do
27
- customer = Braintree::Customer.create!(:payment_method_nonce => Braintree::Test::Nonce::Coinbase)
28
- customer.payment_methods.should == customer.coinbase_accounts
29
- assert_valid_coinbase_attrs(customer.coinbase_accounts[0])
26
+ it "is no longer supported when creating a Customer with a Coinbase payment method nonce" do
27
+ expect do
28
+ Braintree::Customer.create!(:payment_method_nonce => Braintree::Test::Nonce::Coinbase)
29
+ end.to raise_error { |error|
30
+ error.should be_a(Braintree::ValidationsFailed)
31
+ error.error_result.errors.for(:coinbase_account).first.code.should == Braintree::ErrorCodes::PaymentMethod::PaymentMethodNoLongerSupported
32
+ }
30
33
  end
31
34
  end
@@ -0,0 +1,49 @@
1
+ require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
2
+ require File.expand_path(File.dirname(__FILE__) + "/client_api/spec_helper")
3
+
4
+ describe Braintree::Dispute, "search" do
5
+ context "advanced" do
6
+ it "correctly returns a result with no matches" do
7
+ collection = Braintree::Dispute.search do |search|
8
+ search.id.is "non_existent_dispute"
9
+ end
10
+
11
+ expect(collection.disputes.count).to eq(0)
12
+ end
13
+
14
+ it "correctly returns a single dispute by id" do
15
+ collection = Braintree::Dispute.search do |search|
16
+ search.id.is "open_dispute"
17
+ end
18
+
19
+ expect(collection.disputes.count).to eq(1)
20
+ dispute = collection.disputes.first
21
+
22
+ expect(dispute.id).to eq("open_dispute")
23
+ expect(dispute.status).to eq(Braintree::Dispute::Status::Open)
24
+ end
25
+
26
+ it "correctly returns disputes by multiple reasons" do
27
+ collection = Braintree::Dispute.search do |search|
28
+ search.reason.in [
29
+ Braintree::Dispute::Reason::ProductUnsatisfactory,
30
+ Braintree::Dispute::Reason::Retrieval
31
+ ]
32
+ end
33
+
34
+ expect(collection.disputes.count).to eq(2)
35
+ dispute = collection.disputes.first
36
+ end
37
+
38
+ it "correctly returns disputes by received_date range" do
39
+ collection = Braintree::Dispute.search do |search|
40
+ search.received_date.between("03/03/2014", "03/05/2014")
41
+ end
42
+
43
+ expect(collection.disputes.count).to eq(1)
44
+ dispute = collection.disputes.first
45
+
46
+ expect(dispute.received_date).to eq(Date.new(2014, 3, 4))
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,216 @@
1
+ # encoding: utf-8
2
+ require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
3
+ require File.expand_path(File.dirname(__FILE__) + "/client_api/spec_helper")
4
+
5
+ describe Braintree::Dispute do
6
+ let(:transaction) do
7
+ result = Braintree::Transaction.sale(
8
+ :amount => '10.00',
9
+ :credit_card => {
10
+ :expiration_date => '01/2020',
11
+ :number => Braintree::Test::CreditCardNumbers::Disputes::Chargeback
12
+ },
13
+ :options => {
14
+ :submit_for_settlement => true
15
+ }
16
+ )
17
+
18
+ result.transaction
19
+ end
20
+
21
+ let(:dispute) { transaction.disputes.first }
22
+
23
+ describe "self.accept" do
24
+ it "changes the dispute status to accepted" do
25
+ result = Braintree::Dispute.accept(dispute.id)
26
+
27
+ result.success?.should == true
28
+
29
+ refreshed_dispute = Braintree::Dispute.find(dispute.id)
30
+ refreshed_dispute.status.should == Braintree::Dispute::Status::Accepted
31
+ end
32
+
33
+ it "returns an error response if the dispute is not in open status" do
34
+ result = Braintree::Dispute.accept("wells_dispute")
35
+
36
+ result.success?.should == false
37
+ result.errors.for(:dispute)[0].code.should == Braintree::ErrorCodes::Dispute::CanOnlyAcceptOpenDispute
38
+ result.errors.for(:dispute)[0].message.should == "Disputes can only be accepted when they are in an Open state"
39
+ end
40
+
41
+ it "raises a NotFound exception if the dispute cannot be found" do
42
+ expect do
43
+ Braintree::Dispute.accept("invalid-id")
44
+ end.to raise_error(Braintree::NotFoundError, 'dispute with id invalid-id not found')
45
+ end
46
+ end
47
+
48
+ describe "self.add_file_evidence" do
49
+ let(:document_upload) do
50
+ file = File.new("#{File.dirname(__FILE__)}/../../fixtures/files/bt_logo.png", "r")
51
+ response = Braintree::DocumentUpload.create({:kind => Braintree::DocumentUpload::Kind::EvidenceDocument, :file => file})
52
+ document_upload = response.document_upload
53
+ end
54
+
55
+ it "creates text evidence for the dispute" do
56
+ result = Braintree::Dispute.add_file_evidence(dispute.id, document_upload.id)
57
+
58
+ result.success?.should == true
59
+ result.evidence.comment.should be_nil
60
+ result.evidence.created_at.between?(Time.now - 10, Time.now).should == true
61
+ result.evidence.id.should =~ /^\w{16,}$/
62
+ result.evidence.sent_to_processor_at.should == nil
63
+ result.evidence.url.should include("bt_logo.png")
64
+ end
65
+
66
+ it "returns a NotFoundError if the dispute doesn't exist" do
67
+ expect do
68
+ Braintree::Dispute.add_file_evidence("unknown_dispute_id", "b51927a6-4ed7-4a32-8404-df8ef892e1a3")
69
+ end.to raise_error(Braintree::NotFoundError)
70
+ end
71
+
72
+ it "returns an error response if the dispute is not in open status" do
73
+ Braintree::Dispute.accept(dispute.id)
74
+
75
+ result = Braintree::Dispute.add_file_evidence(dispute.id, document_upload.id)
76
+ result.success?.should == false
77
+ result.errors.for(:dispute)[0].code.should == Braintree::ErrorCodes::Dispute::CanOnlyAddEvidenceToOpenDispute
78
+ result.errors.for(:dispute)[0].message.should == "Evidence can only be attached to disputes that are in an Open state"
79
+ end
80
+
81
+ it "returns the new evidence record in subsequent dispute finds" do
82
+ result = Braintree::Dispute.add_file_evidence(dispute.id, document_upload.id)
83
+ refreshed_dispute = Braintree::Dispute.find(dispute.id)
84
+
85
+ expected_evidence = refreshed_dispute.evidence.find { |e| e.id == result.evidence.id }
86
+ expected_evidence.should_not == nil
87
+ expected_evidence.comment.should be_nil
88
+ expected_evidence.url.should include("bt_logo.png")
89
+ end
90
+ end
91
+
92
+ describe "self.add_text_evidence" do
93
+ it "creates text evidence for the dispute" do
94
+ result = Braintree::Dispute.add_text_evidence(dispute.id, "text evidence")
95
+
96
+ result.success?.should == true
97
+ result.evidence.comment.should == "text evidence"
98
+ result.evidence.created_at.between?(Time.now - 10, Time.now).should == true
99
+ result.evidence.id.should =~ /^\w{16,}$/
100
+ result.evidence.sent_to_processor_at.should == nil
101
+ result.evidence.url.should == nil
102
+ end
103
+
104
+ it "returns a NotFoundError if the dispute doesn't exist" do
105
+ expect do
106
+ Braintree::Dispute.add_text_evidence("unknown_dispute_id", "text evidence")
107
+ end.to raise_error(Braintree::NotFoundError)
108
+ end
109
+
110
+ it "returns an error response if the dispute is not in open status" do
111
+ Braintree::Dispute.accept(dispute.id)
112
+
113
+ result = Braintree::Dispute.add_text_evidence(dispute.id, "text evidence")
114
+ result.success?.should == false
115
+ result.errors.for(:dispute)[0].code.should == Braintree::ErrorCodes::Dispute::CanOnlyAddEvidenceToOpenDispute
116
+ result.errors.for(:dispute)[0].message.should == "Evidence can only be attached to disputes that are in an Open state"
117
+ end
118
+
119
+ it "returns the new evidence record in subsequent dispute finds" do
120
+ result = Braintree::Dispute.add_text_evidence(dispute.id, "text evidence")
121
+ refreshed_dispute = Braintree::Dispute.find(dispute.id)
122
+
123
+ expected_evidence = refreshed_dispute.evidence.find { |e| e.id == result.evidence.id }
124
+ expected_evidence.should_not == nil
125
+ expected_evidence.comment.should == "text evidence"
126
+ end
127
+ end
128
+
129
+ describe "self.finalize" do
130
+ it "changes the dispute status to disputed" do
131
+ result = Braintree::Dispute.finalize(dispute.id)
132
+
133
+ result.success?.should == true
134
+
135
+ refreshed_dispute = Braintree::Dispute.find(dispute.id)
136
+ refreshed_dispute.status.should == Braintree::Dispute::Status::Disputed
137
+ end
138
+
139
+ it "returns an error response if the dispute is not in open status" do
140
+ result = Braintree::Dispute.finalize("wells_dispute")
141
+
142
+ result.success?.should == false
143
+ result.errors.for(:dispute)[0].code.should == Braintree::ErrorCodes::Dispute::CanOnlyFinalizeOpenDispute
144
+ result.errors.for(:dispute)[0].message.should == "Disputes can only be finalized when they are in an Open state"
145
+ end
146
+
147
+ it "raises a NotFound exception if the dispute cannot be found" do
148
+ expect do
149
+ Braintree::Dispute.finalize("invalid-id")
150
+ end.to raise_error(Braintree::NotFoundError, 'dispute with id invalid-id not found')
151
+ end
152
+ end
153
+
154
+ describe "self.find" do
155
+ it "finds the dispute with the given id" do
156
+ dispute = Braintree::Dispute.find("open_dispute")
157
+
158
+ dispute.amount_disputed.should == 31.0
159
+ dispute.amount_won.should == 0.0
160
+ dispute.id.should == "open_dispute"
161
+ dispute.status.should == Braintree::Dispute::Status::Open
162
+ dispute.transaction.amount.should == 31.0
163
+ dispute.transaction.id.should == "open_disputed_transaction"
164
+ end
165
+
166
+ it "raises an ArgumentError if dispute_id is not a string" do
167
+ expect do
168
+ Braintree::Dispute.find(Object.new)
169
+ end.to raise_error(ArgumentError, "dispute_id contains invalid characters")
170
+ end
171
+
172
+ it "raises an ArgumentError if dispute_id is blank" do
173
+ expect do
174
+ Braintree::Dispute.find("")
175
+ end.to raise_error(ArgumentError, "dispute_id contains invalid characters")
176
+ end
177
+
178
+ it "raises a NotFoundError exception if the dispute cannot be found" do
179
+ expect do
180
+ Braintree::Dispute.find("invalid-id")
181
+ end.to raise_error(Braintree::NotFoundError, "dispute with id invalid-id not found")
182
+ end
183
+ end
184
+
185
+ describe "self.remove_evidence" do
186
+ let(:evidence) { Braintree::Dispute.add_text_evidence(dispute.id, "text evidence").evidence }
187
+
188
+ it "removes evidence from the dispute" do
189
+ result = Braintree::Dispute.remove_evidence(dispute.id, evidence.id)
190
+
191
+ result.success?.should == true
192
+ end
193
+
194
+ it "returns a NotFoundError if the dispute doesn't exist" do
195
+ expect do
196
+ Braintree::Dispute.remove_evidence("unknown_dispute_id", evidence.id)
197
+ end.to raise_error(Braintree::NotFoundError, "evidence with id #{evidence.id} for dispute with id unknown_dispute_id not found")
198
+ end
199
+
200
+ it "returns a NotFoundError if the dispute doesn't exist" do
201
+ expect do
202
+ Braintree::Dispute.remove_evidence(dispute.id, "unknown_evidence_id")
203
+ end.to raise_error(Braintree::NotFoundError, "evidence with id unknown_evidence_id for dispute with id #{dispute.id} not found")
204
+ end
205
+
206
+ it "returns an error response if the dispute is not in open status" do
207
+ evidence = Braintree::Dispute.add_text_evidence(dispute.id, "text evidence").evidence
208
+ Braintree::Dispute.accept(dispute.id)
209
+
210
+ result = Braintree::Dispute.remove_evidence(dispute.id, evidence.id)
211
+ result.success?.should == false
212
+ result.errors.for(:dispute)[0].code.should == Braintree::ErrorCodes::Dispute::CanOnlyRemoveEvidenceFromOpenDispute
213
+ result.errors.for(:dispute)[0].message.should == "Evidence can only be removed from disputes that are in an Open state"
214
+ end
215
+ end
216
+ end
@@ -0,0 +1,55 @@
1
+ require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
2
+
3
+ describe Braintree::DocumentUploadGateway do
4
+ describe "create" do
5
+ it "returns successful with valid request" do
6
+ file = File.new("#{File.dirname(__FILE__)}/../../fixtures/files/bt_logo.png", "r")
7
+ response = Braintree::DocumentUpload.create({:kind => Braintree::DocumentUpload::Kind::EvidenceDocument, :file => file})
8
+ document_upload = response.document_upload
9
+
10
+ response.success?.should == true
11
+ document_upload.id.should_not be_nil
12
+ document_upload.content_type.should == "image/png"
13
+ document_upload.kind.should == Braintree::DocumentUpload::Kind::EvidenceDocument
14
+ document_upload.name.should == "bt_logo.png"
15
+ document_upload.size.should == 2443
16
+ end
17
+
18
+ it "returns file type error with unsupported file type" do
19
+ file = File.new("#{File.dirname(__FILE__)}/../../fixtures/files/gif_extension_bt_logo.gif", "r")
20
+ response = Braintree::DocumentUpload.create({:kind => Braintree::DocumentUpload::Kind::EvidenceDocument, :file => file})
21
+ response.errors.for(:document_upload).first.code.should == Braintree::ErrorCodes::DocumentUpload::FileTypeIsInvalid
22
+ end
23
+
24
+ it "returns malformed error with malformed file" do
25
+ file = File.new("#{File.dirname(__FILE__)}/../../fixtures/files/malformed_pdf.pdf", "r")
26
+ response = Braintree::DocumentUpload.create({:kind => Braintree::DocumentUpload::Kind::EvidenceDocument, :file => file})
27
+ response.errors.for(:document_upload).first.code.should == Braintree::ErrorCodes::DocumentUpload::FileIsMalformedOrEncrypted
28
+ end
29
+
30
+ it "returns invalid kind error with invalid kind" do
31
+ file = File.new("#{File.dirname(__FILE__)}/../../fixtures/files/bt_logo.png", "r")
32
+ response = Braintree::DocumentUpload.create({:kind => "invalid_kind", :file => file})
33
+ response.errors.for(:document_upload).first.code.should == Braintree::ErrorCodes::DocumentUpload::KindIsInvalid
34
+ end
35
+
36
+ it "returns file too large error with file over 4mb" do
37
+ filename = "#{File.dirname(__FILE__)}/../../fixtures/files/large_file.png"
38
+ begin
39
+ write_times = 1048577 * 4
40
+ File.open(filename, "w+") { |f| write_times.times { f.write "a" } }
41
+ file = File.new(filename, "r")
42
+ response = Braintree::DocumentUpload.create({:kind => Braintree::DocumentUpload::Kind::EvidenceDocument, :file => file})
43
+ response.errors.for(:document_upload).first.code.should == Braintree::ErrorCodes::DocumentUpload::FileIsTooLarge
44
+ ensure
45
+ File.delete(filename)
46
+ end
47
+ end
48
+
49
+ it "returns invalid keys error if signature is invalid" do
50
+ expect do
51
+ response = Braintree::DocumentUpload.create({:invalid_key => "do not add", :kind => Braintree::DocumentUpload::Kind::EvidenceDocument})
52
+ end.to raise_error(ArgumentError, "invalid keys: invalid_key")
53
+ end
54
+ end
55
+ end