candy_check 0.1.1 → 0.4.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.
Files changed (86) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +2 -1
  3. data/.rubocop.yml +6 -0
  4. data/.ruby-version +1 -1
  5. data/.travis.yml +7 -10
  6. data/Guardfile +42 -0
  7. data/MIGRATION_GUIDE_0_2_0.md +141 -0
  8. data/README.md +85 -27
  9. data/Rakefile +1 -1
  10. data/candy_check.gemspec +32 -26
  11. data/lib/candy_check/app_store/receipt_collection.rb +4 -2
  12. data/lib/candy_check/app_store/subscription_verification.rb +25 -1
  13. data/lib/candy_check/app_store/verification.rb +1 -1
  14. data/lib/candy_check/app_store/verifier.rb +11 -11
  15. data/lib/candy_check/cli/app.rb +20 -33
  16. data/lib/candy_check/cli/commands/play_store.rb +12 -13
  17. data/lib/candy_check/play_store.rb +20 -10
  18. data/lib/candy_check/play_store/acknowledger.rb +19 -0
  19. data/lib/candy_check/play_store/android_publisher_service.rb +6 -0
  20. data/lib/candy_check/play_store/product_acknowledgements/acknowledgement.rb +45 -0
  21. data/lib/candy_check/play_store/product_acknowledgements/response.rb +24 -0
  22. data/lib/candy_check/play_store/product_purchases/product_purchase.rb +90 -0
  23. data/lib/candy_check/play_store/product_purchases/product_verification.rb +53 -0
  24. data/lib/candy_check/play_store/subscription_purchases/subscription_purchase.rb +154 -0
  25. data/lib/candy_check/play_store/subscription_purchases/subscription_verification.rb +55 -0
  26. data/lib/candy_check/play_store/verification_failure.rb +8 -6
  27. data/lib/candy_check/play_store/verifier.rb +24 -49
  28. data/lib/candy_check/version.rb +1 -1
  29. data/spec/app_store/client_spec.rb +2 -2
  30. data/spec/app_store/config_spec.rb +5 -5
  31. data/spec/app_store/receipt_collection_spec.rb +35 -8
  32. data/spec/app_store/receipt_spec.rb +16 -16
  33. data/spec/app_store/subscription_verification_spec.rb +49 -16
  34. data/spec/app_store/verifcation_failure_spec.rb +6 -6
  35. data/spec/app_store/verification_spec.rb +12 -12
  36. data/spec/app_store/verifier_spec.rb +36 -17
  37. data/spec/candy_check_spec.rb +3 -3
  38. data/spec/cli/app_spec.rb +10 -6
  39. data/spec/cli/commands/app_store_spec.rb +6 -6
  40. data/spec/cli/commands/play_store_spec.rb +10 -43
  41. data/spec/cli/commands/version_spec.rb +1 -1
  42. data/spec/cli/out_spec.rb +4 -4
  43. data/spec/fixtures/play_store/random_dummy_key.json +12 -0
  44. data/spec/fixtures/vcr_cassettes/play_store/product_acknowledgements/acknowledged.yml +105 -0
  45. data/spec/fixtures/vcr_cassettes/play_store/product_acknowledgements/already_acknowledged.yml +124 -0
  46. data/spec/fixtures/vcr_cassettes/play_store/product_acknowledgements/refunded.yml +122 -0
  47. data/spec/fixtures/vcr_cassettes/play_store/product_purchases/permission_denied.yml +196 -0
  48. data/spec/fixtures/vcr_cassettes/play_store/product_purchases/response_with_empty_body.yml +183 -0
  49. data/spec/fixtures/vcr_cassettes/play_store/product_purchases/valid_but_not_consumed.yml +122 -0
  50. data/spec/fixtures/vcr_cassettes/play_store/subscription_purchases/permission_denied.yml +196 -0
  51. data/spec/fixtures/vcr_cassettes/play_store/subscription_purchases/valid_but_expired.yml +127 -0
  52. data/spec/play_store/acknowledger_spec.rb +48 -0
  53. data/spec/play_store/product_acknowledgements/acknowledgement_spec.rb +54 -0
  54. data/spec/play_store/product_acknowledgements/response_spec.rb +66 -0
  55. data/spec/play_store/product_purchases/product_purchase_spec.rb +110 -0
  56. data/spec/play_store/product_purchases/product_verification_spec.rb +49 -0
  57. data/spec/play_store/subscription_purchases/subscription_purchase_spec.rb +237 -0
  58. data/spec/play_store/subscription_purchases/subscription_verification_spec.rb +65 -0
  59. data/spec/play_store/verification_failure_spec.rb +20 -20
  60. data/spec/play_store/verifier_spec.rb +32 -96
  61. data/spec/spec_helper.rb +31 -11
  62. data/spec/support/with_command.rb +0 -3
  63. metadata +167 -81
  64. data/lib/candy_check/play_store/client.rb +0 -126
  65. data/lib/candy_check/play_store/config.rb +0 -51
  66. data/lib/candy_check/play_store/discovery_repository.rb +0 -33
  67. data/lib/candy_check/play_store/receipt.rb +0 -81
  68. data/lib/candy_check/play_store/subscription.rb +0 -139
  69. data/lib/candy_check/play_store/subscription_verification.rb +0 -30
  70. data/lib/candy_check/play_store/verification.rb +0 -48
  71. data/spec/fixtures/api_cache.dump +0 -1
  72. data/spec/fixtures/play_store/api_cache.dump +0 -1
  73. data/spec/fixtures/play_store/auth_failure.txt +0 -18
  74. data/spec/fixtures/play_store/auth_success.txt +0 -20
  75. data/spec/fixtures/play_store/discovery.txt +0 -2841
  76. data/spec/fixtures/play_store/dummy.p12 +0 -0
  77. data/spec/fixtures/play_store/empty.txt +0 -17
  78. data/spec/fixtures/play_store/products_failure.txt +0 -29
  79. data/spec/fixtures/play_store/products_success.txt +0 -22
  80. data/spec/play_store/client_spec.rb +0 -125
  81. data/spec/play_store/config_spec.rb +0 -96
  82. data/spec/play_store/discovery_respository_spec.rb +0 -31
  83. data/spec/play_store/receipt_spec.rb +0 -88
  84. data/spec/play_store/subscription_spec.rb +0 -138
  85. data/spec/play_store/subscription_verification_spec.rb +0 -97
  86. data/spec/play_store/verification_spec.rb +0 -81
@@ -8,64 +8,91 @@ describe CandyCheck::AppStore::ReceiptCollection do
8
8
  [{
9
9
  'expires_date' => '2014-04-15 12:52:40 Etc/GMT',
10
10
  'expires_date_pst' => '2014-04-15 05:52:40 America/Los_Angeles',
11
+ 'purchase_date' => '2014-04-14 12:52:40 Etc/GMT',
11
12
  'is_trial_period' => 'false'
12
13
  }, {
13
14
  'expires_date' => '2015-04-15 12:52:40 Etc/GMT',
14
15
  'expires_date_pst' => '2015-04-15 05:52:40 America/Los_Angeles',
16
+ 'purchase_date' => '2015-04-14 12:52:40 Etc/GMT',
15
17
  'is_trial_period' => 'false'
16
18
  }]
17
19
  end
18
20
 
19
21
  it 'is expired' do
20
- subject.expired?.must_be_true
22
+ _(subject.expired?).must_be_true
21
23
  end
22
24
 
23
25
  it 'is not a trial' do
24
- subject.trial?.must_be_false
26
+ _(subject.trial?).must_be_false
25
27
  end
26
28
 
27
29
  it 'has positive overdue days' do
28
30
  overdue = subject.overdue_days
29
- overdue.must_be_instance_of Fixnum
31
+ _(overdue).must_be_instance_of Fixnum
30
32
  assert overdue > 0
31
33
  end
32
34
 
33
35
  it 'has a last expires date' do
34
36
  expected = DateTime.new(2015, 4, 15, 12, 52, 40)
35
- subject.expires_at.must_equal expected
37
+ _(subject.expires_at).must_equal expected
36
38
  end
37
39
 
38
40
  it 'is expired? at same pointin time' do
39
41
  Timecop.freeze(Time.utc(2015, 4, 15, 12, 52, 40)) do
40
- subject.expired?.must_be_true
42
+ _(subject.expired?).must_be_true
41
43
  end
42
44
  end
43
45
  end
44
46
 
47
+ describe 'unordered receipts' do
48
+ let(:attributes) do
49
+ [{
50
+ 'expires_date' => '2015-04-15 12:52:40 Etc/GMT',
51
+ 'expires_date_pst' => '2015-04-15 05:52:40 America/Los_Angeles',
52
+ 'purchase_date' => '2015-04-14 12:52:40 Etc/GMT',
53
+ 'is_trial_period' => 'false'
54
+ }, {
55
+ 'expires_date' => '2014-04-15 12:52:40 Etc/GMT',
56
+ 'expires_date_pst' => '2014-04-15 05:52:40 America/Los_Angeles',
57
+ 'purchase_date' => '2014-04-14 12:52:40 Etc/GMT',
58
+ 'is_trial_period' => 'false'
59
+ }]
60
+ end
61
+
62
+ it 'the expires date is the latest one in time' do
63
+ expected = DateTime.new(2015, 4, 15, 12, 52, 40)
64
+ _(subject.expires_at).must_equal expected
65
+ end
66
+
67
+ end
68
+
45
69
  describe 'unexpired trial subscription' do
46
70
  two_days_from_now = DateTime.now + 2
47
71
 
48
72
  let(:attributes) do
49
73
  [{
50
74
  'expires_date' => '2016-04-15 12:52:40 Etc/GMT',
75
+ 'purchase_date' => '2016-04-15 12:52:40 Etc/GMT',
51
76
  'is_trial_period' => 'true'
52
77
  }, {
53
78
  'expires_date' =>
54
79
  two_days_from_now.strftime('%Y-%m-%d %H:%M:%S Etc/GMT'),
80
+ 'purchase_date' => '2016-04-15 12:52:40 Etc/GMT',
55
81
  'is_trial_period' => 'true'
56
82
  }]
57
83
  end
58
84
 
59
85
  it 'has not expired' do
60
- subject.expired?.must_be_false
86
+ _(subject.expired?).must_be_false
61
87
  end
62
88
 
63
89
  it 'it is a trial' do
64
- subject.trial?.must_be_true
90
+ _(subject.trial?).must_be_true
65
91
  end
66
92
 
67
93
  it 'expires in two days' do
68
- subject.overdue_days.must_equal(-2)
94
+ _(subject.overdue_days).must_equal(-2)
69
95
  end
70
96
  end
97
+
71
98
  end
@@ -31,62 +31,62 @@ describe CandyCheck::AppStore::Receipt do
31
31
 
32
32
  describe 'valid transaction' do
33
33
  it 'is valid' do
34
- subject.valid?.must_be_true
34
+ _(subject.valid?).must_be_true
35
35
  end
36
36
 
37
37
  it 'returns the item\'s id' do
38
- subject.item_id.must_equal 'some_item_id'
38
+ _(subject.item_id).must_equal 'some_item_id'
39
39
  end
40
40
 
41
41
  it 'returns the item\'s product_id' do
42
- subject.product_id.must_equal 'some_product'
42
+ _(subject.product_id).must_equal 'some_product'
43
43
  end
44
44
 
45
45
  it 'returns the quantity' do
46
- subject.quantity.must_equal 1
46
+ _(subject.quantity).must_equal 1
47
47
  end
48
48
 
49
49
  it 'returns the app version' do
50
- subject.app_version.must_equal '2.0'
50
+ _(subject.app_version).must_equal '2.0'
51
51
  end
52
52
 
53
53
  it 'returns the bundle identifier' do
54
- subject.bundle_identifier.must_equal 'some.test.app'
54
+ _(subject.bundle_identifier).must_equal 'some.test.app'
55
55
  end
56
56
 
57
57
  it 'returns the purchase date' do
58
58
  expected = DateTime.new(2015, 1, 9, 11, 40, 46)
59
- subject.purchase_date.must_equal expected
59
+ _(subject.purchase_date).must_equal expected
60
60
  end
61
61
 
62
62
  it 'returns the original purchase date' do
63
63
  expected = DateTime.new(2015, 1, 8, 11, 40, 46)
64
- subject.original_purchase_date.must_equal expected
64
+ _(subject.original_purchase_date).must_equal expected
65
65
  end
66
66
 
67
67
  it 'returns the transaction id' do
68
- subject.transaction_id.must_equal 'some_transaction_id'
68
+ _(subject.transaction_id).must_equal 'some_transaction_id'
69
69
  end
70
70
 
71
71
  it 'returns the original transaction id' do
72
- subject.original_transaction_id.must_equal 'some_original_transaction_id'
72
+ _(subject.original_transaction_id).must_equal 'some_original_transaction_id'
73
73
  end
74
74
 
75
75
  it 'return nil for cancellation date' do
76
- subject.cancellation_date.must_be_nil
76
+ _(subject.cancellation_date).must_be_nil
77
77
  end
78
78
 
79
79
  it 'returns raw attributes' do
80
- subject.attributes.must_be_same_as attributes
80
+ _(subject.attributes).must_be_same_as attributes
81
81
  end
82
82
 
83
83
  it 'returns the subscription expiration date' do
84
84
  expected = DateTime.new(2016, 6, 9, 13, 59, 40)
85
- subject.expires_date.must_equal expected
85
+ _(subject.expires_date).must_equal expected
86
86
  end
87
87
 
88
88
  it 'returns the trial status' do
89
- subject.is_trial_period.must_be_false
89
+ _(subject.is_trial_period).must_be_false
90
90
  end
91
91
  end
92
92
 
@@ -96,12 +96,12 @@ describe CandyCheck::AppStore::Receipt do
96
96
  end
97
97
 
98
98
  it 'isn\'t valid' do
99
- subject.valid?.must_be_false
99
+ _(subject.valid?).must_be_false
100
100
  end
101
101
 
102
102
  it 'return nil for cancellation date' do
103
103
  expected = DateTime.new(2015, 1, 12, 11, 40, 46)
104
- subject.cancellation_date.must_equal expected
104
+ _(subject.cancellation_date).must_equal expected
105
105
  end
106
106
  end
107
107
  end
@@ -11,26 +11,26 @@ describe CandyCheck::AppStore::SubscriptionVerification do
11
11
  it 'returns a verification failure for status != 0' do
12
12
  with_mocked_response('status' => 21_000) do |client, recorded|
13
13
  result = subject.call!
14
- client.receipt_data.must_equal data
15
- client.secret.must_equal secret
14
+ _(client.receipt_data).must_equal data
15
+ _(client.secret).must_equal secret
16
16
 
17
- recorded.first.must_equal [endpoint]
17
+ _(recorded.first).must_equal [endpoint]
18
18
 
19
- result.must_be_instance_of CandyCheck::AppStore::VerificationFailure
20
- result.code.must_equal 21_000
19
+ _(result).must_be_instance_of CandyCheck::AppStore::VerificationFailure
20
+ _(result.code).must_equal 21_000
21
21
  end
22
22
  end
23
23
 
24
24
  it 'returns a verification failure when receipt is missing' do
25
25
  with_mocked_response({}) do |client, recorded|
26
26
  result = subject.call!
27
- client.receipt_data.must_equal data
28
- client.secret.must_equal secret
27
+ _(client.receipt_data).must_equal data
28
+ _(client.secret).must_equal secret
29
29
 
30
- recorded.first.must_equal [endpoint]
30
+ _(recorded.first).must_equal [endpoint]
31
31
 
32
- result.must_be_instance_of CandyCheck::AppStore::VerificationFailure
33
- result.code.must_equal(-1)
32
+ _(result).must_be_instance_of CandyCheck::AppStore::VerificationFailure
33
+ _(result.code).must_equal(-1)
34
34
  end
35
35
  end
36
36
 
@@ -38,17 +38,50 @@ describe CandyCheck::AppStore::SubscriptionVerification do
38
38
  response = {
39
39
  'status' => 0,
40
40
  'latest_receipt_info' => [
41
- { 'item_id' => 'some_id' },
42
- { 'item_id' => 'some_other_id' }
41
+ { 'item_id' => 'some_id', 'purchase_date' => '2016-04-15 12:52:40 Etc/GMT' },
42
+ { 'item_id' => 'some_other_id', 'purchase_date' => '2016-04-15 12:52:40 Etc/GMT' }
43
43
  ]
44
44
  }
45
45
  with_mocked_response(response) do
46
46
  result = subject.call!
47
- result.must_be_instance_of CandyCheck::AppStore::ReceiptCollection
48
- result.receipts.must_be_instance_of Array
47
+ _(result).must_be_instance_of CandyCheck::AppStore::ReceiptCollection
48
+ _(result.receipts).must_be_instance_of Array
49
+ _(result.receipts.size).must_equal(2)
49
50
  last = result.receipts.last
50
- last.must_be_instance_of CandyCheck::AppStore::Receipt
51
- last.item_id.must_equal('some_other_id')
51
+ _(last).must_be_instance_of CandyCheck::AppStore::Receipt
52
+ _(last.item_id).must_equal('some_other_id')
53
+ end
54
+ end
55
+
56
+ describe 'filtered product_ids' do
57
+ subject do
58
+ CandyCheck::AppStore::SubscriptionVerification.new(
59
+ endpoint,
60
+ data,
61
+ secret,
62
+ product_ids
63
+ )
64
+ end
65
+ let(:product_ids) { ['product_1'] }
66
+
67
+ it 'returns only filtered reciepts when specifc product_ids are reqested' do
68
+ response = {
69
+ 'status' => 0,
70
+ 'latest_receipt_info' => [
71
+ { 'item_id' => 'some_id', 'product_id' => 'product_1', 'purchase_date' => '2016-04-15 12:52:40 Etc/GMT' },
72
+ { 'item_id' => 'some_other_id', 'product_id' => 'product_1', 'purchase_date' => '2016-04-15 12:52:40 Etc/GMT' },
73
+ { 'item_id' => 'some_id', 'product_id' => 'product_2', 'purchase_date' => '2016-04-15 12:52:40 Etc/GMT' }
74
+ ]
75
+ }
76
+ with_mocked_response(response) do
77
+ result = subject.call!
78
+ _(result).must_be_instance_of CandyCheck::AppStore::ReceiptCollection
79
+ _(result.receipts).must_be_instance_of Array
80
+ _(result.receipts.size).must_equal(2)
81
+ last = result.receipts.last
82
+ _(last).must_be_instance_of CandyCheck::AppStore::Receipt
83
+ _(last.item_id).must_equal('some_other_id')
84
+ end
52
85
  end
53
86
  end
54
87
 
@@ -9,20 +9,20 @@ describe CandyCheck::AppStore::VerificationFailure do
9
9
  it 'fetched an failure with message for every known code' do
10
10
  known.each do |code|
11
11
  got = subject.fetch(code)
12
- got.code.must_equal code
13
- got.message.wont_equal 'Unknown error'
12
+ _(got.code).must_equal code
13
+ _(got.message).wont_equal 'Unknown error'
14
14
  end
15
15
  end
16
16
 
17
17
  it 'fetched an failure for unknown codes' do
18
18
  got = subject.fetch(1234)
19
- got.code.must_equal 1234
20
- got.message.must_equal 'Unknown error'
19
+ _(got.code).must_equal 1234
20
+ _(got.message).must_equal 'Unknown error'
21
21
  end
22
22
 
23
23
  it 'fetched an failure for nil code' do
24
24
  got = subject.fetch(nil)
25
- got.code.must_equal(-1)
26
- got.message.must_equal 'Unknown error'
25
+ _(got.code).must_equal(-1)
26
+ _(got.message).must_equal 'Unknown error'
27
27
  end
28
28
  end
@@ -9,26 +9,26 @@ describe CandyCheck::AppStore::Verification do
9
9
  it 'returns a verification failure for status != 0' do
10
10
  with_mocked_response('status' => 21_000) do |client, recorded|
11
11
  result = subject.call!
12
- client.receipt_data.must_equal data
13
- client.secret.must_equal secret
12
+ _(client.receipt_data).must_equal data
13
+ _(client.secret).must_equal secret
14
14
 
15
- recorded.first.must_equal [endpoint]
15
+ _(recorded.first).must_equal [endpoint]
16
16
 
17
- result.must_be_instance_of CandyCheck::AppStore::VerificationFailure
18
- result.code.must_equal 21_000
17
+ _(result).must_be_instance_of CandyCheck::AppStore::VerificationFailure
18
+ _(result.code).must_equal 21_000
19
19
  end
20
20
  end
21
21
 
22
22
  it 'returns a verification failure when receipt is missing' do
23
23
  with_mocked_response({}) do |client, recorded|
24
24
  result = subject.call!
25
- client.receipt_data.must_equal data
26
- client.secret.must_equal secret
25
+ _(client.receipt_data).must_equal data
26
+ _(client.secret).must_equal secret
27
27
 
28
- recorded.first.must_equal [endpoint]
28
+ _(recorded.first).must_equal [endpoint]
29
29
 
30
- result.must_be_instance_of CandyCheck::AppStore::VerificationFailure
31
- result.code.must_equal(-1)
30
+ _(result).must_be_instance_of CandyCheck::AppStore::VerificationFailure
31
+ _(result.code).must_equal(-1)
32
32
  end
33
33
  end
34
34
 
@@ -36,8 +36,8 @@ describe CandyCheck::AppStore::Verification do
36
36
  response = { 'status' => 0, 'receipt' => { 'item_id' => 'some_id' } }
37
37
  with_mocked_response(response) do
38
38
  result = subject.call!
39
- result.must_be_instance_of CandyCheck::AppStore::Receipt
40
- result.item_id.must_equal('some_id')
39
+ _(result).must_be_instance_of CandyCheck::AppStore::Receipt
40
+ _(result.item_id).must_equal('some_id')
41
41
  end
42
42
  end
43
43
 
@@ -18,7 +18,7 @@ describe CandyCheck::AppStore::Verifier do
18
18
  end
19
19
 
20
20
  it 'holds the config' do
21
- subject.config.must_be_same_as config
21
+ _(subject.config).must_be_same_as config
22
22
  end
23
23
 
24
24
  describe 'sandbox' do
@@ -26,7 +26,7 @@ describe CandyCheck::AppStore::Verifier do
26
26
 
27
27
  it 'uses sandbox endpoint without retry on success' do
28
28
  with_mocked_verifier(receipt) do
29
- subject.verify(data, secret).must_be_same_as receipt
29
+ _(subject.verify(data, secret)).must_be_same_as receipt
30
30
  assert_recorded([sandbox_endpoint, data, secret])
31
31
  end
32
32
  end
@@ -34,7 +34,7 @@ describe CandyCheck::AppStore::Verifier do
34
34
  it 'only uses sandbox endpoint for normal failures' do
35
35
  failure = get_failure(21_000)
36
36
  with_mocked_verifier(failure) do
37
- subject.verify(data, secret).must_be_same_as failure
37
+ _(subject.verify(data, secret)).must_be_same_as failure
38
38
  assert_recorded([sandbox_endpoint, data, secret])
39
39
  end
40
40
  end
@@ -42,7 +42,7 @@ describe CandyCheck::AppStore::Verifier do
42
42
  it 'retries production endpoint for redirect error' do
43
43
  failure = get_failure(21_008)
44
44
  with_mocked_verifier(failure, receipt) do
45
- subject.verify(data, secret).must_be_same_as receipt
45
+ _(subject.verify(data, secret)).must_be_same_as receipt
46
46
  assert_recorded(
47
47
  [sandbox_endpoint, data, secret],
48
48
  [production_endpoint, data, secret]
@@ -56,7 +56,7 @@ describe CandyCheck::AppStore::Verifier do
56
56
 
57
57
  it 'uses production endpoint without retry on success' do
58
58
  with_mocked_verifier(receipt) do
59
- subject.verify(data, secret).must_be_same_as receipt
59
+ _(subject.verify(data, secret)).must_be_same_as receipt
60
60
  assert_recorded([production_endpoint, data, secret])
61
61
  end
62
62
  end
@@ -64,7 +64,7 @@ describe CandyCheck::AppStore::Verifier do
64
64
  it 'only uses production endpoint for normal failures' do
65
65
  failure = get_failure(21_000)
66
66
  with_mocked_verifier(failure) do
67
- subject.verify(data, secret).must_be_same_as failure
67
+ _(subject.verify(data, secret)).must_be_same_as failure
68
68
  assert_recorded([production_endpoint, data, secret])
69
69
  end
70
70
  end
@@ -72,7 +72,7 @@ describe CandyCheck::AppStore::Verifier do
72
72
  it 'retries production endpoint for redirect error' do
73
73
  failure = get_failure(21_007)
74
74
  with_mocked_verifier(failure, receipt) do
75
- subject.verify(data, secret).must_be_same_as receipt
75
+ _(subject.verify(data, secret)).must_be_same_as receipt
76
76
  assert_recorded(
77
77
  [production_endpoint, data, secret],
78
78
  [sandbox_endpoint, data, secret]
@@ -86,31 +86,41 @@ describe CandyCheck::AppStore::Verifier do
86
86
 
87
87
  it 'uses production endpoint without retry on success' do
88
88
  with_mocked_verifier(receipt_collection) do
89
- subject.verify_subscription(
89
+ _(subject.verify_subscription(
90
90
  data, secret
91
- ).must_be_same_as receipt_collection
92
- assert_recorded([production_endpoint, data, secret])
91
+ )).must_be_same_as receipt_collection
92
+ assert_recorded([production_endpoint, data, secret, nil])
93
93
  end
94
94
  end
95
95
 
96
96
  it 'only uses production endpoint for normal failures' do
97
97
  failure = get_failure(21_000)
98
98
  with_mocked_verifier(failure) do
99
- subject.verify_subscription(data, secret).must_be_same_as failure
100
- assert_recorded([production_endpoint, data, secret])
99
+ _(subject.verify_subscription(data, secret)).must_be_same_as failure
100
+ assert_recorded([production_endpoint, data, secret, nil])
101
101
  end
102
102
  end
103
103
 
104
104
  it 'retries production endpoint for redirect error' do
105
105
  failure = get_failure(21_007)
106
106
  with_mocked_verifier(failure, receipt) do
107
- subject.verify_subscription(data, secret).must_be_same_as receipt
107
+ _(subject.verify_subscription(data, secret)).must_be_same_as receipt
108
108
  assert_recorded(
109
- [production_endpoint, data, secret],
110
- [sandbox_endpoint, data, secret]
109
+ [production_endpoint, data, secret, nil],
110
+ [sandbox_endpoint, data, secret, nil]
111
111
  )
112
112
  end
113
113
  end
114
+
115
+ it 'passed the product_ids' do
116
+ product_ids = ['product_1']
117
+ with_mocked_verifier(receipt_collection) do
118
+ _(subject.verify_subscription(
119
+ data, secret, product_ids
120
+ )).must_be_same_as receipt_collection
121
+ assert_recorded([production_endpoint, data, secret, product_ids])
122
+ end
123
+ end
114
124
  end
115
125
 
116
126
  private
@@ -127,15 +137,24 @@ describe CandyCheck::AppStore::Verifier do
127
137
  end
128
138
 
129
139
  def assert_recorded(*calls)
130
- @recorded.must_equal calls
140
+ _(@recorded).must_equal calls
131
141
  end
132
142
 
133
143
  def get_failure(code)
134
144
  CandyCheck::AppStore::VerificationFailure.fetch(code)
135
145
  end
136
146
 
137
- DummyAppStoreVerification = Struct.new(:endpoint, :data, :secret) do
147
+ class DummyAppStoreVerification
148
+ attr_reader :endpoint, :data, :secret, :product_ids
138
149
  attr_accessor :results
150
+
151
+ def initialize(endpoint, data, secret, product_ids = nil)
152
+ @endpoint = endpoint
153
+ @data = data
154
+ @secret = secret
155
+ @product_ids = product_ids
156
+ end
157
+
139
158
  def call!
140
159
  results.shift
141
160
  end