candy_check 0.0.1
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 +7 -0
- data/.gitignore +5 -0
- data/.rubocop.yml +6 -0
- data/.ruby-version +1 -0
- data/.travis.yml +16 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +157 -0
- data/Rakefile +15 -0
- data/bin/cc_appstore +90 -0
- data/bin/cc_playstore +119 -0
- data/candy_check.gemspec +31 -0
- data/lib/candy_check/app_store/client.rb +57 -0
- data/lib/candy_check/app_store/config.rb +30 -0
- data/lib/candy_check/app_store/receipt.rb +83 -0
- data/lib/candy_check/app_store/verification.rb +49 -0
- data/lib/candy_check/app_store/verification_failure.rb +60 -0
- data/lib/candy_check/app_store/verifier.rb +69 -0
- data/lib/candy_check/app_store.rb +12 -0
- data/lib/candy_check/play_store/client.rb +102 -0
- data/lib/candy_check/play_store/config.rb +51 -0
- data/lib/candy_check/play_store/discovery_repository.rb +33 -0
- data/lib/candy_check/play_store/receipt.rb +81 -0
- data/lib/candy_check/play_store/verification.rb +46 -0
- data/lib/candy_check/play_store/verification_failure.rb +30 -0
- data/lib/candy_check/play_store/verifier.rb +52 -0
- data/lib/candy_check/play_store.rb +15 -0
- data/lib/candy_check/utils/attribute_reader.rb +30 -0
- data/lib/candy_check/utils/config.rb +40 -0
- data/lib/candy_check/utils.rb +2 -0
- data/lib/candy_check/version.rb +4 -0
- data/lib/candy_check.rb +8 -0
- data/spec/app_store/client_spec.rb +55 -0
- data/spec/app_store/config_spec.rb +41 -0
- data/spec/app_store/receipt_spec.rb +92 -0
- data/spec/app_store/verifcation_failure_spec.rb +28 -0
- data/spec/app_store/verification_spec.rb +66 -0
- data/spec/app_store/verifier_spec.rb +110 -0
- data/spec/candy_check_spec.rb +9 -0
- data/spec/fixtures/api_cache.dump +1 -0
- data/spec/fixtures/play_store/api_cache.dump +1 -0
- data/spec/fixtures/play_store/auth_failure.txt +18 -0
- data/spec/fixtures/play_store/auth_success.txt +20 -0
- data/spec/fixtures/play_store/discovery.txt +2841 -0
- data/spec/fixtures/play_store/dummy.p12 +0 -0
- data/spec/fixtures/play_store/empty.txt +17 -0
- data/spec/fixtures/play_store/products_failure.txt +29 -0
- data/spec/fixtures/play_store/products_success.txt +22 -0
- data/spec/play_store/client_spec.rb +104 -0
- data/spec/play_store/config_spec.rb +96 -0
- data/spec/play_store/discovery_respository_spec.rb +31 -0
- data/spec/play_store/receipt_spec.rb +88 -0
- data/spec/play_store/verification_failure_spec.rb +35 -0
- data/spec/play_store/verification_spec.rb +80 -0
- data/spec/play_store/verifier_spec.rb +95 -0
- data/spec/spec_helper.rb +35 -0
- data/spec/support/with_fixtures.rb +9 -0
- data/spec/support/with_temp_file.rb +23 -0
- metadata +270 -0
Binary file
|
@@ -0,0 +1,17 @@
|
|
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
|
+
}
|
@@ -0,0 +1,29 @@
|
|
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
|
+
}
|
@@ -0,0 +1,22 @@
|
|
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
|
+
}
|
@@ -0,0 +1,104 @@
|
|
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 for a successful call' do
|
68
|
+
bootup!
|
69
|
+
mock_request!('products_success.txt')
|
70
|
+
result = subject.verify('the_package', 'the_id', 'the_token')
|
71
|
+
result.must_be_instance_of Hash
|
72
|
+
result['purchaseState'].must_equal 0
|
73
|
+
result['consumptionState'].must_equal 0
|
74
|
+
result['developerPayload'].must_equal \
|
75
|
+
'payload that gets stored and returned'
|
76
|
+
result['purchaseTimeMillis'].must_equal '1421676237413'
|
77
|
+
result['kind'].must_equal 'androidpublisher#productPurchase'
|
78
|
+
end
|
79
|
+
|
80
|
+
private
|
81
|
+
|
82
|
+
def bootup!
|
83
|
+
mock_discovery!('discovery.txt')
|
84
|
+
mock_authorize!('auth_success.txt')
|
85
|
+
subject.boot!
|
86
|
+
end
|
87
|
+
|
88
|
+
def mock_discovery!(file)
|
89
|
+
stub_request(:get, 'https://www.googleapis.com/discovery/' \
|
90
|
+
'v1/apis/androidpublisher/v2/rest')
|
91
|
+
.to_return(fixture_content('play_store', file))
|
92
|
+
end
|
93
|
+
|
94
|
+
def mock_authorize!(file)
|
95
|
+
stub_request(:post, 'https://accounts.google.com/o/oauth2/token')
|
96
|
+
.to_return(fixture_content('play_store', file))
|
97
|
+
end
|
98
|
+
|
99
|
+
def mock_request!(file)
|
100
|
+
stub_request(:get, 'https://www.googleapis.com/androidpublisher/v2/' \
|
101
|
+
'applications/the_package/purchases/products/the_id/tokens/the_token')
|
102
|
+
.to_return(fixture_content('play_store', file))
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,96 @@
|
|
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
|
@@ -0,0 +1,31 @@
|
|
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
|
@@ -0,0 +1,88 @@
|
|
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
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe CandyCheck::PlayStore::VerificationFailure do
|
4
|
+
subject { CandyCheck::PlayStore::VerificationFailure.new(attributes) }
|
5
|
+
|
6
|
+
describe 'denied' do
|
7
|
+
let(:attributes) do
|
8
|
+
{
|
9
|
+
'errors' => [],
|
10
|
+
'code' => 401,
|
11
|
+
'message' => 'The current user has insufficient permissions'
|
12
|
+
}
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'returns the code' do
|
16
|
+
subject.code.must_equal 401
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'returns the message' do
|
20
|
+
subject.message.must_equal 'The current user has insufficient permissions'
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe 'empty' do
|
25
|
+
let(:attributes) { nil }
|
26
|
+
|
27
|
+
it 'returns an unknown code' do
|
28
|
+
subject.code.must_equal(-1)
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'returns an unknown message' do
|
32
|
+
subject.message.must_equal 'Unknown error'
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe CandyCheck::PlayStore::Verification do
|
4
|
+
subject do
|
5
|
+
CandyCheck::PlayStore::Verification.new(client, package, product_id, token)
|
6
|
+
end
|
7
|
+
let(:client) { DummyGoogleClient.new(response) }
|
8
|
+
let(:package) { 'the_package' }
|
9
|
+
let(:product_id) { 'the_product' }
|
10
|
+
let(:token) { 'the_token' }
|
11
|
+
|
12
|
+
describe 'valid' do
|
13
|
+
let(:response) do
|
14
|
+
{
|
15
|
+
'kind' => 'androidpublisher#productPurchase',
|
16
|
+
'purchaseTimeMillis' => '1421676237413',
|
17
|
+
'purchaseState' => 0,
|
18
|
+
'consumptionState' => 0,
|
19
|
+
'developerPayload' => 'payload that gets stored and returned'
|
20
|
+
}
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'calls the client with the correct paramters' do
|
24
|
+
subject.call!
|
25
|
+
client.package.must_equal package
|
26
|
+
client.product_id.must_equal product_id
|
27
|
+
client.token.must_equal token
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'returns a receipt' do
|
31
|
+
result = subject.call!
|
32
|
+
result.must_be_instance_of CandyCheck::PlayStore::Receipt
|
33
|
+
result.valid?.must_be_true
|
34
|
+
result.consumed?.must_be_false
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe 'failure' do
|
39
|
+
let(:response) do
|
40
|
+
{
|
41
|
+
'error' => {
|
42
|
+
'code' => 401,
|
43
|
+
'message' => 'The current user has insufficient permissions'
|
44
|
+
}
|
45
|
+
}
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'returns a verification failure' do
|
49
|
+
result = subject.call!
|
50
|
+
result.must_be_instance_of CandyCheck::PlayStore::VerificationFailure
|
51
|
+
result.code.must_equal 401
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
describe 'empty' do
|
56
|
+
let(:response) do
|
57
|
+
{}
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'returns a verification failure' do
|
61
|
+
result = subject.call!
|
62
|
+
result.must_be_instance_of CandyCheck::PlayStore::VerificationFailure
|
63
|
+
result.code.must_equal(-1)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
class DummyGoogleClient < Struct.new(:response)
|
70
|
+
attr_reader :package, :product_id, :token
|
71
|
+
|
72
|
+
def boot!
|
73
|
+
end
|
74
|
+
|
75
|
+
def verify(package, product_id, token)
|
76
|
+
@package, @product_id, @token = package, product_id, token
|
77
|
+
response
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|