candy_check 0.1.0.pre → 0.3.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.
- checksums.yaml +5 -5
- data/.rubocop.yml +23 -0
- data/.ruby-version +1 -1
- data/.travis.yml +7 -8
- data/Guardfile +42 -0
- data/MIGRATION_GUIDE_0_2_0.md +141 -0
- data/README.md +86 -26
- data/Rakefile +1 -1
- data/candy_check.gemspec +33 -25
- data/lib/candy_check/app_store/receipt_collection.rb +5 -3
- data/lib/candy_check/app_store/subscription_verification.rb +25 -1
- data/lib/candy_check/app_store/verification.rb +1 -1
- data/lib/candy_check/app_store/verifier.rb +11 -11
- data/lib/candy_check/cli/app.rb +16 -33
- data/lib/candy_check/cli/commands/play_store.rb +12 -13
- data/lib/candy_check/play_store.rb +20 -10
- data/lib/candy_check/play_store/acknowledger.rb +19 -0
- data/lib/candy_check/play_store/android_publisher_service.rb +6 -0
- data/lib/candy_check/play_store/product_acknowledgements/acknowledgement.rb +45 -0
- data/lib/candy_check/play_store/product_acknowledgements/response.rb +24 -0
- data/lib/candy_check/play_store/product_purchases/product_purchase.rb +90 -0
- data/lib/candy_check/play_store/product_purchases/product_verification.rb +53 -0
- data/lib/candy_check/play_store/subscription_purchases/subscription_purchase.rb +154 -0
- data/lib/candy_check/play_store/subscription_purchases/subscription_verification.rb +55 -0
- data/lib/candy_check/play_store/verification_failure.rb +8 -6
- data/lib/candy_check/play_store/verifier.rb +24 -49
- data/lib/candy_check/utils/config.rb +5 -3
- data/lib/candy_check/version.rb +1 -1
- data/spec/app_store/receipt_collection_spec.rb +33 -0
- data/spec/app_store/subscription_verification_spec.rb +35 -2
- data/spec/app_store/verifier_spec.rb +24 -5
- data/spec/candy_check_spec.rb +2 -2
- data/spec/cli/commands/play_store_spec.rb +10 -43
- data/spec/fixtures/play_store/random_dummy_key.json +12 -0
- data/spec/fixtures/vcr_cassettes/play_store/product_acknowledgements/acknowledged.yml +105 -0
- data/spec/fixtures/vcr_cassettes/play_store/product_acknowledgements/already_acknowledged.yml +124 -0
- data/spec/fixtures/vcr_cassettes/play_store/product_acknowledgements/refunded.yml +122 -0
- data/spec/fixtures/vcr_cassettes/play_store/product_purchases/permission_denied.yml +196 -0
- data/spec/fixtures/vcr_cassettes/play_store/product_purchases/response_with_empty_body.yml +183 -0
- data/spec/fixtures/vcr_cassettes/play_store/product_purchases/valid_but_not_consumed.yml +122 -0
- data/spec/fixtures/vcr_cassettes/play_store/subscription_purchases/permission_denied.yml +196 -0
- data/spec/fixtures/vcr_cassettes/play_store/subscription_purchases/valid_but_expired.yml +127 -0
- data/spec/play_store/acknowledger_spec.rb +48 -0
- data/spec/play_store/product_acknowledgements/acknowledgement_spec.rb +54 -0
- data/spec/play_store/product_acknowledgements/response_spec.rb +66 -0
- data/spec/play_store/product_purchases/product_purchase_spec.rb +110 -0
- data/spec/play_store/product_purchases/product_verification_spec.rb +49 -0
- data/spec/play_store/subscription_purchases/subscription_purchase_spec.rb +237 -0
- data/spec/play_store/subscription_purchases/subscription_verification_spec.rb +65 -0
- data/spec/play_store/verification_failure_spec.rb +18 -18
- data/spec/play_store/verifier_spec.rb +32 -96
- data/spec/spec_helper.rb +32 -10
- metadata +175 -75
- data/lib/candy_check/play_store/client.rb +0 -126
- data/lib/candy_check/play_store/config.rb +0 -51
- data/lib/candy_check/play_store/discovery_repository.rb +0 -33
- data/lib/candy_check/play_store/receipt.rb +0 -81
- data/lib/candy_check/play_store/subscription.rb +0 -138
- data/lib/candy_check/play_store/subscription_verification.rb +0 -30
- data/lib/candy_check/play_store/verification.rb +0 -48
- data/spec/fixtures/api_cache.dump +0 -1
- data/spec/fixtures/play_store/api_cache.dump +0 -1
- data/spec/fixtures/play_store/auth_failure.txt +0 -18
- data/spec/fixtures/play_store/auth_success.txt +0 -20
- data/spec/fixtures/play_store/discovery.txt +0 -2841
- data/spec/fixtures/play_store/dummy.p12 +0 -0
- data/spec/fixtures/play_store/empty.txt +0 -17
- data/spec/fixtures/play_store/products_failure.txt +0 -29
- data/spec/fixtures/play_store/products_success.txt +0 -22
- data/spec/play_store/client_spec.rb +0 -125
- data/spec/play_store/config_spec.rb +0 -96
- data/spec/play_store/discovery_respository_spec.rb +0 -31
- data/spec/play_store/receipt_spec.rb +0 -88
- data/spec/play_store/subscription_spec.rb +0 -138
- data/spec/play_store/subscription_verification_spec.rb +0 -98
- data/spec/play_store/verification_spec.rb +0 -82
Binary file
|
@@ -1,17 +0,0 @@
|
|
1
|
-
HTTP/1.1 200 OK
|
2
|
-
Expires: Mon, 19 Jan 2015 12:14:41 GMT
|
3
|
-
Date: Mon, 19 Jan 2015 12:09:41 GMT
|
4
|
-
Cache-Control: public, max-age=300, must-revalidate, no-transform
|
5
|
-
ETag: "ye6orv2F-1npMW3u9suM3a7C5Bo/xy4W57xFkYdtUdm4rpPIU-7grtg"
|
6
|
-
Vary: Origin
|
7
|
-
Vary: X-Origin
|
8
|
-
Content-Type: application/json; charset=UTF-8
|
9
|
-
X-Content-Type-Options: nosniff
|
10
|
-
X-Frame-Options: SAMEORIGIN
|
11
|
-
X-XSS-Protection: 1; mode=block
|
12
|
-
Content-Length: 83495
|
13
|
-
Server: GSE
|
14
|
-
Alternate-Protocol: 443:quic,p=0.02
|
15
|
-
|
16
|
-
{
|
17
|
-
}
|
@@ -1,29 +0,0 @@
|
|
1
|
-
HTTP/1.1 401 Unauthorized
|
2
|
-
Expires: Mon, 19 Jan 2015 12:14:41 GMT
|
3
|
-
Date: Mon, 19 Jan 2015 12:09:41 GMT
|
4
|
-
Cache-Control: public, max-age=300, must-revalidate, no-transform
|
5
|
-
ETag: "ye6orv2F-1npMW3u9suM3a7C5Bo/xy4W57xFkYdtUdm4rpPIU-7grtg"
|
6
|
-
Vary: Origin
|
7
|
-
Vary: X-Origin
|
8
|
-
WWW-Authenticate: Bearer realm="https://accounts.google.com/AuthSubRequest"
|
9
|
-
Content-Type: application/json; charset=UTF-8
|
10
|
-
X-Content-Type-Options: nosniff
|
11
|
-
X-Frame-Options: SAMEORIGIN
|
12
|
-
X-XSS-Protection: 1; mode=block
|
13
|
-
Content-Length: 83495
|
14
|
-
Server: GSE
|
15
|
-
Alternate-Protocol: 443:quic,p=0.02
|
16
|
-
|
17
|
-
{
|
18
|
-
"error": {
|
19
|
-
"errors": [
|
20
|
-
{
|
21
|
-
"domain": "androidpublisher",
|
22
|
-
"reason": "permissionDenied",
|
23
|
-
"message": "The current user has insufficient permissions to perform the requested operation."
|
24
|
-
}
|
25
|
-
],
|
26
|
-
"code": 401,
|
27
|
-
"message": "The current user has insufficient permissions to perform the requested operation."
|
28
|
-
}
|
29
|
-
}
|
@@ -1,22 +0,0 @@
|
|
1
|
-
HTTP/1.1 200 OK
|
2
|
-
Expires: Mon, 19 Jan 2015 12:14:41 GMT
|
3
|
-
Date: Mon, 19 Jan 2015 12:09:41 GMT
|
4
|
-
Cache-Control: public, max-age=300, must-revalidate, no-transform
|
5
|
-
ETag: "ye6orv2F-1npMW3u9suM3a7C5Bo/xy4W57xFkYdtUdm4rpPIU-7grtg"
|
6
|
-
Vary: Origin
|
7
|
-
Vary: X-Origin
|
8
|
-
Content-Type: application/json; charset=UTF-8
|
9
|
-
X-Content-Type-Options: nosniff
|
10
|
-
X-Frame-Options: SAMEORIGIN
|
11
|
-
X-XSS-Protection: 1; mode=block
|
12
|
-
Content-Length: 83495
|
13
|
-
Server: GSE
|
14
|
-
Alternate-Protocol: 443:quic,p=0.02
|
15
|
-
|
16
|
-
{
|
17
|
-
"kind": "androidpublisher#productPurchase",
|
18
|
-
"purchaseTimeMillis": "1421676237413",
|
19
|
-
"purchaseState": 0,
|
20
|
-
"consumptionState": 0,
|
21
|
-
"developerPayload": "payload that gets stored and returned"
|
22
|
-
}
|
@@ -1,125 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe CandyCheck::PlayStore::Client do
|
4
|
-
include WithTempFile
|
5
|
-
include WithFixtures
|
6
|
-
|
7
|
-
with_temp_file :cache_file
|
8
|
-
|
9
|
-
subject { CandyCheck::PlayStore::Client.new(config) }
|
10
|
-
|
11
|
-
let(:config) do
|
12
|
-
CandyCheck::PlayStore::Config.new(
|
13
|
-
application_name: 'demo_app',
|
14
|
-
application_version: '1.0',
|
15
|
-
issuer: 'test_issuer',
|
16
|
-
key_file: fixture_path('play_store', 'dummy.p12'),
|
17
|
-
cache_file: cache_file_path,
|
18
|
-
key_secret: 'notasecret'
|
19
|
-
)
|
20
|
-
end
|
21
|
-
|
22
|
-
describe 'discovery' do
|
23
|
-
describe 'w/o cache file' do
|
24
|
-
it 'boot loads and dumps discovery file' do
|
25
|
-
mock_discovery!('discovery.txt')
|
26
|
-
mock_authorize!('auth_success.txt')
|
27
|
-
subject.boot!
|
28
|
-
File.exist?(cache_file_path).must_be_true
|
29
|
-
end
|
30
|
-
|
31
|
-
it 'fails if discovery fails' do
|
32
|
-
mock_discovery!('empty.txt')
|
33
|
-
proc { subject.boot! }.must_raise \
|
34
|
-
CandyCheck::PlayStore::Client::DiscoveryError
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
describe 'with cache file' do
|
39
|
-
let(:cache_file_path) { fixture_path('play_store', 'api_cache.dump') }
|
40
|
-
|
41
|
-
it 'loads the discovery from cache file' do
|
42
|
-
mock_authorize!('auth_success.txt')
|
43
|
-
subject.boot!
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
it 'fails if authentication fails' do
|
49
|
-
mock_discovery!('discovery.txt')
|
50
|
-
mock_authorize!('auth_failure.txt')
|
51
|
-
proc { subject.boot! }.must_raise Signet::AuthorizationError
|
52
|
-
end
|
53
|
-
|
54
|
-
it 'returns the products call result\'s data even if it is a failure' do
|
55
|
-
bootup!
|
56
|
-
|
57
|
-
mock_request!('products_failure.txt')
|
58
|
-
result = subject.verify('the_package', 'the_id', 'the_token')
|
59
|
-
result.must_be_instance_of Hash
|
60
|
-
|
61
|
-
result['error']['code'].must_equal 401
|
62
|
-
result['error']['message'].must_equal 'The current user has insufficient' \
|
63
|
-
' permissions to perform the requested operation.'
|
64
|
-
result['error']['errors'].size.must_equal 1
|
65
|
-
end
|
66
|
-
|
67
|
-
it 'returns the products call result\'s data even if it is a failure' \
|
68
|
-
' when verifying subscription' do
|
69
|
-
bootup!
|
70
|
-
|
71
|
-
mock_subscriptions_request!('products_failure.txt')
|
72
|
-
result = subject.verify_subscription('the_package', 'the_id', 'the_token')
|
73
|
-
result.must_be_instance_of Hash
|
74
|
-
|
75
|
-
result['error']['code'].must_equal 401
|
76
|
-
result['error']['message'].must_equal 'The current user has insufficient' \
|
77
|
-
' permissions to perform the requested operation.'
|
78
|
-
result['error']['errors'].size.must_equal 1
|
79
|
-
end
|
80
|
-
|
81
|
-
it 'returns the products call result\'s data for a successful call' do
|
82
|
-
bootup!
|
83
|
-
mock_request!('products_success.txt')
|
84
|
-
result = subject.verify('the_package', 'the_id', 'the_token')
|
85
|
-
result.must_be_instance_of Hash
|
86
|
-
result['purchaseState'].must_equal 0
|
87
|
-
result['consumptionState'].must_equal 0
|
88
|
-
result['developerPayload'].must_equal \
|
89
|
-
'payload that gets stored and returned'
|
90
|
-
result['purchaseTimeMillis'].must_equal '1421676237413'
|
91
|
-
result['kind'].must_equal 'androidpublisher#productPurchase'
|
92
|
-
end
|
93
|
-
|
94
|
-
private
|
95
|
-
|
96
|
-
def bootup!
|
97
|
-
mock_discovery!('discovery.txt')
|
98
|
-
mock_authorize!('auth_success.txt')
|
99
|
-
subject.boot!
|
100
|
-
end
|
101
|
-
|
102
|
-
def mock_discovery!(file)
|
103
|
-
stub_request(:get, 'https://www.googleapis.com/discovery/' \
|
104
|
-
'v1/apis/androidpublisher/v2/rest')
|
105
|
-
.to_return(fixture_content('play_store', file))
|
106
|
-
end
|
107
|
-
|
108
|
-
def mock_authorize!(file)
|
109
|
-
stub_request(:post, 'https://accounts.google.com/o/oauth2/token')
|
110
|
-
.to_return(fixture_content('play_store', file))
|
111
|
-
end
|
112
|
-
|
113
|
-
def mock_request!(file)
|
114
|
-
stub_request(:get, 'https://www.googleapis.com/androidpublisher/v2/' \
|
115
|
-
'applications/the_package/purchases/products/the_id/tokens/the_token')
|
116
|
-
.to_return(fixture_content('play_store', file))
|
117
|
-
end
|
118
|
-
|
119
|
-
def mock_subscriptions_request!(file)
|
120
|
-
stub_request(:get, 'https://www.googleapis.com/androidpublisher/v2/' \
|
121
|
-
'applications/the_package/purchases/subscriptions/' \
|
122
|
-
'the_id/tokens/the_token')
|
123
|
-
.to_return(fixture_content('play_store', file))
|
124
|
-
end
|
125
|
-
end
|
@@ -1,96 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe CandyCheck::PlayStore::Config do
|
4
|
-
subject { CandyCheck::PlayStore::Config.new(attributes) }
|
5
|
-
|
6
|
-
let(:attributes) do
|
7
|
-
{
|
8
|
-
application_name: 'the_name',
|
9
|
-
application_version: 'the_version',
|
10
|
-
issuer: 'the_issuer',
|
11
|
-
key_file: 'the_key_file',
|
12
|
-
key_secret: 'the_key_secret'
|
13
|
-
}
|
14
|
-
end
|
15
|
-
|
16
|
-
describe 'minimal attributes' do
|
17
|
-
it 'initializes and validates correctly' do
|
18
|
-
subject.application_name.must_equal 'the_name'
|
19
|
-
subject.application_version.must_equal 'the_version'
|
20
|
-
subject.issuer.must_equal 'the_issuer'
|
21
|
-
subject.key_file.must_equal 'the_key_file'
|
22
|
-
subject.key_secret.must_equal 'the_key_secret'
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
describe 'maximal attributes' do
|
27
|
-
let(:attributes) do
|
28
|
-
{
|
29
|
-
application_name: 'the_name',
|
30
|
-
application_version: 'the_version',
|
31
|
-
issuer: 'the_issuer',
|
32
|
-
key_file: 'the_key_file',
|
33
|
-
key_secret: 'the_key_secret',
|
34
|
-
cache_file: 'the_cache_file'
|
35
|
-
}
|
36
|
-
end
|
37
|
-
|
38
|
-
it 'initializes and validates correctly' do
|
39
|
-
subject.application_name.must_equal 'the_name'
|
40
|
-
subject.application_version.must_equal 'the_version'
|
41
|
-
subject.issuer.must_equal 'the_issuer'
|
42
|
-
subject.key_file.must_equal 'the_key_file'
|
43
|
-
subject.key_secret.must_equal 'the_key_secret'
|
44
|
-
subject.cache_file.must_equal 'the_cache_file'
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
describe 'invalid attributes' do
|
49
|
-
it 'needs application_name' do
|
50
|
-
assert_raises_missing :application_name
|
51
|
-
end
|
52
|
-
|
53
|
-
it 'needs application_version' do
|
54
|
-
assert_raises_missing :application_version
|
55
|
-
end
|
56
|
-
|
57
|
-
it 'needs issuer' do
|
58
|
-
assert_raises_missing :issuer
|
59
|
-
end
|
60
|
-
|
61
|
-
it 'needs key_file' do
|
62
|
-
assert_raises_missing :key_file
|
63
|
-
end
|
64
|
-
|
65
|
-
it 'needs key_secret' do
|
66
|
-
assert_raises_missing :key_secret
|
67
|
-
end
|
68
|
-
|
69
|
-
private
|
70
|
-
|
71
|
-
def assert_raises_missing(name)
|
72
|
-
attributes.delete(name)
|
73
|
-
proc do
|
74
|
-
subject
|
75
|
-
end.must_raise ArgumentError
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
describe 'p12 certificate' do
|
80
|
-
include WithFixtures
|
81
|
-
|
82
|
-
let(:attributes) do
|
83
|
-
{
|
84
|
-
application_name: 'the_name',
|
85
|
-
application_version: 'the_version',
|
86
|
-
issuer: 'the_issuer',
|
87
|
-
key_file: fixture_path('play_store', 'dummy.p12'),
|
88
|
-
key_secret: 'notasecret'
|
89
|
-
}
|
90
|
-
end
|
91
|
-
|
92
|
-
it 'load the api_key from a file' do
|
93
|
-
subject.api_key.wont_be_nil
|
94
|
-
end
|
95
|
-
end
|
96
|
-
end
|
@@ -1,31 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe CandyCheck::PlayStore::DiscoveryRepository do
|
4
|
-
subject { CandyCheck::PlayStore::DiscoveryRepository.new(discovery_path) }
|
5
|
-
|
6
|
-
let(:data) do
|
7
|
-
{ 'demo' => 1 }
|
8
|
-
end
|
9
|
-
|
10
|
-
describe 'empty file path' do
|
11
|
-
let(:discovery_path) { nil }
|
12
|
-
|
13
|
-
it 'returns nil for nil path' do
|
14
|
-
subject.load.must_be_nil
|
15
|
-
end
|
16
|
-
|
17
|
-
it 'does not save' do
|
18
|
-
subject.save(data)
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
describe 'valid file path' do
|
23
|
-
include WithTempFile
|
24
|
-
with_temp_file :discovery
|
25
|
-
|
26
|
-
it 'saves and loads the file content' do
|
27
|
-
subject.save(data)
|
28
|
-
subject.load.must_equal data
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
@@ -1,88 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe CandyCheck::PlayStore::Receipt do
|
4
|
-
subject { CandyCheck::PlayStore::Receipt.new(attributes) }
|
5
|
-
|
6
|
-
describe 'valid and non-consumed product' do
|
7
|
-
let(:attributes) do
|
8
|
-
{
|
9
|
-
'kind' => 'androidpublisher#productPurchase',
|
10
|
-
'purchaseTimeMillis' => '1421676237413',
|
11
|
-
'purchaseState' => 0,
|
12
|
-
'consumptionState' => 0,
|
13
|
-
'developerPayload' => 'payload that gets stored and returned'
|
14
|
-
}
|
15
|
-
end
|
16
|
-
|
17
|
-
it 'is valid?' do
|
18
|
-
subject.valid?.must_be_true
|
19
|
-
end
|
20
|
-
|
21
|
-
it 'is not consumed' do
|
22
|
-
subject.consumed?.must_be_false
|
23
|
-
end
|
24
|
-
|
25
|
-
it 'returns the purchase_state' do
|
26
|
-
subject.purchase_state.must_equal 0
|
27
|
-
end
|
28
|
-
|
29
|
-
it 'returns the consumption_state' do
|
30
|
-
subject.consumption_state.must_equal 0
|
31
|
-
end
|
32
|
-
|
33
|
-
it 'returns the developer_payload' do
|
34
|
-
subject.developer_payload.must_equal \
|
35
|
-
'payload that gets stored and returned'
|
36
|
-
end
|
37
|
-
|
38
|
-
it 'returns the kind' do
|
39
|
-
subject.kind.must_equal \
|
40
|
-
'androidpublisher#productPurchase'
|
41
|
-
end
|
42
|
-
|
43
|
-
it 'returns the purchase_time_millis' do
|
44
|
-
subject.purchase_time_millis.must_equal 1_421_676_237_413
|
45
|
-
end
|
46
|
-
|
47
|
-
it 'returns the purchased_at' do
|
48
|
-
expected = DateTime.new(2015, 1, 19, 14, 03, 57)
|
49
|
-
subject.purchased_at.must_equal expected
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
describe 'valid and consumed product' do
|
54
|
-
let(:attributes) do
|
55
|
-
{
|
56
|
-
'kind' => 'androidpublisher#productPurchase',
|
57
|
-
'purchaseTimeMillis' => '1421676237413',
|
58
|
-
'purchaseState' => 0,
|
59
|
-
'consumptionState' => 1,
|
60
|
-
'developerPayload' => 'payload that gets stored and returned'
|
61
|
-
}
|
62
|
-
end
|
63
|
-
|
64
|
-
it 'is valid?' do
|
65
|
-
subject.valid?.must_be_true
|
66
|
-
end
|
67
|
-
|
68
|
-
it 'is consumed?' do
|
69
|
-
subject.consumed?.must_be_true
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
describe 'non-valid product' do
|
74
|
-
let(:attributes) do
|
75
|
-
{
|
76
|
-
'kind' => 'androidpublisher#productPurchase',
|
77
|
-
'purchaseTimeMillis' => '1421676237413',
|
78
|
-
'purchaseState' => 1,
|
79
|
-
'consumptionState' => 0,
|
80
|
-
'developerPayload' => 'payload that gets stored and returned'
|
81
|
-
}
|
82
|
-
end
|
83
|
-
|
84
|
-
it 'is valid?' do
|
85
|
-
subject.valid?.must_be_false
|
86
|
-
end
|
87
|
-
end
|
88
|
-
end
|
@@ -1,138 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe CandyCheck::PlayStore::Subscription do
|
4
|
-
subject { CandyCheck::PlayStore::Subscription.new(attributes) }
|
5
|
-
|
6
|
-
describe 'expired and canceled subscription' do
|
7
|
-
let(:attributes) do
|
8
|
-
{
|
9
|
-
'kind' => 'androidpublisher#subscriptionPurchase',
|
10
|
-
'startTimeMillis' => '1459540113244',
|
11
|
-
'expiryTimeMillis' => '1462132088610',
|
12
|
-
'autoRenewing' => false,
|
13
|
-
'developerPayload' => 'payload that gets stored and returned',
|
14
|
-
'cancelReason' => 0,
|
15
|
-
'paymentState' => '1'
|
16
|
-
}
|
17
|
-
end
|
18
|
-
|
19
|
-
it 'is expired?' do
|
20
|
-
subject.expired?.must_be_true
|
21
|
-
end
|
22
|
-
|
23
|
-
it 'is canceled by user' do
|
24
|
-
subject.canceled_by_user?.must_be_true
|
25
|
-
end
|
26
|
-
|
27
|
-
it 'returns the payment_state' do
|
28
|
-
subject.payment_state.must_equal 1
|
29
|
-
end
|
30
|
-
|
31
|
-
it 'considers a payment as valid' do
|
32
|
-
subject.payment_received?.must_be_true
|
33
|
-
end
|
34
|
-
|
35
|
-
it 'checks that auto renewal status is false' do
|
36
|
-
subject.auto_renewing?.must_be_false
|
37
|
-
end
|
38
|
-
|
39
|
-
it 'returns the developer_payload' do
|
40
|
-
subject.developer_payload.must_equal \
|
41
|
-
'payload that gets stored and returned'
|
42
|
-
end
|
43
|
-
|
44
|
-
it 'returns the kind' do
|
45
|
-
subject.kind.must_equal 'androidpublisher#subscriptionPurchase'
|
46
|
-
end
|
47
|
-
|
48
|
-
it 'returns the start_time_millis' do
|
49
|
-
subject.start_time_millis.must_equal 145_954_011_324_4
|
50
|
-
end
|
51
|
-
|
52
|
-
it 'returns the expiry_time_millis' do
|
53
|
-
subject.expiry_time_millis.must_equal 146_213_208_861_0
|
54
|
-
end
|
55
|
-
|
56
|
-
it 'returns the starts_at' do
|
57
|
-
expected = DateTime.new(2016, 4, 1, 19, 48, 33)
|
58
|
-
subject.starts_at.must_equal expected
|
59
|
-
end
|
60
|
-
|
61
|
-
it 'returns the expires_at' do
|
62
|
-
expected = DateTime.new(2016, 5, 1, 19, 48, 8)
|
63
|
-
subject.expires_at.must_equal expected
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
describe 'unexpired and renewing subscription' do
|
68
|
-
two_days_from_now = DateTime.now + 2
|
69
|
-
let(:attributes) do
|
70
|
-
{
|
71
|
-
'expiryTimeMillis' => (two_days_from_now.to_time.to_i * 1000).to_s,
|
72
|
-
'autoRenewing' => true
|
73
|
-
}
|
74
|
-
end
|
75
|
-
|
76
|
-
it 'is expired?' do
|
77
|
-
subject.expired?.must_be_false
|
78
|
-
end
|
79
|
-
|
80
|
-
it 'is two days left until it is overdue' do
|
81
|
-
subject.overdue_days.must_equal(-2)
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
describe 'expired due to payment failure' do
|
86
|
-
let(:attributes) do
|
87
|
-
{
|
88
|
-
'expiryTimeMillis' => '1462132088610',
|
89
|
-
'autoRenewing' => true,
|
90
|
-
'cancelReason' => 1
|
91
|
-
}
|
92
|
-
end
|
93
|
-
|
94
|
-
it 'is expired?' do
|
95
|
-
subject.expired?.must_be_true
|
96
|
-
end
|
97
|
-
|
98
|
-
it 'is payment_failed?' do
|
99
|
-
subject.payment_failed?.must_be_true
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
|
-
describe 'expired with pending payment' do
|
104
|
-
let(:attributes) do
|
105
|
-
{
|
106
|
-
'expiryTimeMillis' => '1462132088610',
|
107
|
-
'autoRenewing' => true,
|
108
|
-
'paymentState' => 0
|
109
|
-
}
|
110
|
-
end
|
111
|
-
|
112
|
-
it 'is expired?' do
|
113
|
-
subject.expired?.must_be_true
|
114
|
-
end
|
115
|
-
|
116
|
-
it 'is payment_pending?' do
|
117
|
-
subject.payment_pending?.must_be_true
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
|
-
describe 'trial' do
|
122
|
-
let(:attributes) do
|
123
|
-
{
|
124
|
-
'paymentState' => 1,
|
125
|
-
'priceCurrencyCode' => 'SOMECODE',
|
126
|
-
'priceAmountMicros' => '0'
|
127
|
-
}
|
128
|
-
end
|
129
|
-
|
130
|
-
it 'is trual?' do
|
131
|
-
subject.trial?.must_be_true
|
132
|
-
end
|
133
|
-
|
134
|
-
it 'returns the price_currency_code' do
|
135
|
-
subject.price_currency_code.must_equal 'SOMECODE'
|
136
|
-
end
|
137
|
-
end
|
138
|
-
end
|