candy_check 0.1.0.pre → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|