3scale-3scale_ws_api_for_ruby 0.4.7
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.
- data/README +63 -0
- data/Rakefile +29 -0
- data/init.rb +1 -0
- data/lib/3scale/interface.rb +236 -0
- data/lib/3scale_interface.rb +1 -0
- data/test/interface_test.rb +218 -0
- metadata +67 -0
data/README
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
= Interface for 3scale web service API monitoring system
|
2
|
+
|
3
|
+
This plugin provides interface for communication with 3scale monitoring system.
|
4
|
+
|
5
|
+
== Configuration
|
6
|
+
|
7
|
+
If you are using rails 2.1 or newer, put this into your config/environment.rb
|
8
|
+
file:
|
9
|
+
|
10
|
+
config.gem "3scale_interface"
|
11
|
+
|
12
|
+
If you are using older version, put there this instead:
|
13
|
+
|
14
|
+
require "3scale_interface"
|
15
|
+
|
16
|
+
== Usage
|
17
|
+
|
18
|
+
First, create new interface object with 3scale backed hostname and Your
|
19
|
+
private authentication key:
|
20
|
+
|
21
|
+
interface = ThreeScale::Interface.new("http://3scale.net", "a3b034...")
|
22
|
+
|
23
|
+
Because the object is stateless, you can create just one and store it globally.
|
24
|
+
|
25
|
+
Then for each request to Your service:
|
26
|
+
|
27
|
+
1. Start the transaction with user key and (optionally) estimated resource
|
28
|
+
usage (in this example it is: 1 hit and 42000 kilobytes of storage space),
|
29
|
+
|
30
|
+
transaction = interface.start(user_key, 'hits' => 1, 'storage' => 42000)
|
31
|
+
|
32
|
+
This will return transaction data (if successful). It is a hash containing
|
33
|
+
these fields:
|
34
|
+
|
35
|
+
<tt>:id</tt>::
|
36
|
+
transaction id necessary for confirmation or cancellation of transaction
|
37
|
+
(see following steps).
|
38
|
+
|
39
|
+
<tt>:provider_verification_key</tt>::
|
40
|
+
the provider should send this key back to user so he/she can verify the
|
41
|
+
authenticity of the response.
|
42
|
+
|
43
|
+
<tt>:contract_name</tt>::
|
44
|
+
name of contract the user is signed for. This can be used to send
|
45
|
+
different response according to contract type, if that is desired.
|
46
|
+
|
47
|
+
2. Process the request.
|
48
|
+
|
49
|
+
2a. If the processing was successful:
|
50
|
+
Call +confirm+:
|
51
|
+
|
52
|
+
interface.confirm(transaction[:id])
|
53
|
+
|
54
|
+
Or call it with actual resource usage, if it differs from predicted one:
|
55
|
+
|
56
|
+
interface.confirm(transaction[:id], 'hits' => 1, 'storage' => 40500)
|
57
|
+
|
58
|
+
2b. If there was some error, call +cancel+:
|
59
|
+
|
60
|
+
interface.cancel(transaction[:id])
|
61
|
+
|
62
|
+
3. Send response back to the user together with +provider_verification_key+.
|
63
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'rake/rdoctask'
|
4
|
+
require 'rake/gempackagetask'
|
5
|
+
|
6
|
+
desc 'Default: run unit tests.'
|
7
|
+
task :default => :test
|
8
|
+
|
9
|
+
desc 'Run unit tests.'
|
10
|
+
Rake::TestTask.new(:test) do |t|
|
11
|
+
t.libs << 'lib'
|
12
|
+
t.pattern = 'test/**/*_test.rb'
|
13
|
+
t.verbose = true
|
14
|
+
end
|
15
|
+
|
16
|
+
desc 'Generate documentation.'
|
17
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
18
|
+
rdoc.rdoc_dir = 'rdoc'
|
19
|
+
rdoc.title = '3scale interface'
|
20
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
21
|
+
rdoc.rdoc_files.include('README')
|
22
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
23
|
+
end
|
24
|
+
|
25
|
+
spec = eval(File.read(File.dirname(__FILE__) + '/3scale_ws_api_for_ruby.gemspec'))
|
26
|
+
|
27
|
+
Rake::GemPackageTask.new(spec) do |package|
|
28
|
+
package.need_tar = true
|
29
|
+
end
|
data/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "#{File.dirname(__FILE__)}/lib/3scale_interface"
|
@@ -0,0 +1,236 @@
|
|
1
|
+
require 'cgi'
|
2
|
+
require 'hpricot'
|
3
|
+
require 'net/http'
|
4
|
+
|
5
|
+
module ThreeScale # :nodoc:
|
6
|
+
class Error < StandardError; end
|
7
|
+
|
8
|
+
# Base class for exceptions caused by user.
|
9
|
+
class UserError < Error; end
|
10
|
+
|
11
|
+
# Exception raised when contract between user and provider is not active.
|
12
|
+
# Contract can be inactive when it is pending (requires confirmation from
|
13
|
+
# provider), suspended or canceled.
|
14
|
+
class ContractNotActive < UserError; end
|
15
|
+
|
16
|
+
# Exception raised when usage limits configured for contract are already
|
17
|
+
# exceeded.
|
18
|
+
class LimitsExceeded < UserError; end
|
19
|
+
|
20
|
+
# Exception raised when +user_key+ is not valid. This can mean that contract
|
21
|
+
# between provider and user does not exists, or the passed +user_key+ does
|
22
|
+
# not correspond to the key associated with this contract.
|
23
|
+
class UserKeyInvalid < UserError; end
|
24
|
+
|
25
|
+
|
26
|
+
# Base class for exceptions caused by provider.
|
27
|
+
class ProviderError < Error; end
|
28
|
+
|
29
|
+
# Exception raised when some metric name in provider +usage+ hash does not
|
30
|
+
# correspond to metric configured for the service.
|
31
|
+
class MetricInvalid < ProviderError; end
|
32
|
+
|
33
|
+
# Exception raised when provider authentication key is not valid. The provider
|
34
|
+
# needs to make sure that the key used is the same as the one that was
|
35
|
+
# generated for him/her when he/she published a service on 3scale.
|
36
|
+
class ProviderKeyInvalid < ProviderError; end
|
37
|
+
|
38
|
+
# Exception raised when transaction corresponding to given +transaction_id+
|
39
|
+
# does not exists. Methods +confirm+ and +cancel+ need valid transaction id
|
40
|
+
# that is obtained by preceding call to +start+.
|
41
|
+
class TransactionNotFound < ProviderError; end
|
42
|
+
|
43
|
+
|
44
|
+
# Base class for exceptions caused by 3scale backend system.
|
45
|
+
class SystemError < Error; end
|
46
|
+
|
47
|
+
# Other error.
|
48
|
+
class UnknownError < SystemError; end
|
49
|
+
|
50
|
+
|
51
|
+
|
52
|
+
# This class provides interface to 3scale monitoring system.
|
53
|
+
#
|
54
|
+
# Objects of this class are stateless and can be shared through multiple
|
55
|
+
# transactions and by multiple clients.
|
56
|
+
class Interface
|
57
|
+
|
58
|
+
# Hostname of 3scale server.
|
59
|
+
attr_accessor :host
|
60
|
+
|
61
|
+
# Key that uniquely identifies the provider. This key is known only to the
|
62
|
+
# provider and to 3scale.
|
63
|
+
attr_accessor :provider_authentication_key
|
64
|
+
|
65
|
+
# Create a 3scale interface object.
|
66
|
+
#
|
67
|
+
# == Arguments
|
68
|
+
# +host+:: Hostname of 3scale backend server.
|
69
|
+
# +provider_authentication_key+:: Unique key that identifies this provider.
|
70
|
+
def initialize(host = nil, provider_authentication_key = nil)
|
71
|
+
@host = host
|
72
|
+
@provider_authentication_key = provider_authentication_key
|
73
|
+
end
|
74
|
+
|
75
|
+
|
76
|
+
# Starts a transaction. This can be used also to report estimated resource
|
77
|
+
# usage of the request.
|
78
|
+
#
|
79
|
+
# == Arguments
|
80
|
+
# +user_key+:: Key that uniquely identifies an user of the service.
|
81
|
+
# +usage+::
|
82
|
+
# A hash of metric names/values pairs that contains predicted resource
|
83
|
+
# usage of this request.
|
84
|
+
#
|
85
|
+
# For example, if this request is going to take 10MB of storage space,
|
86
|
+
# then this parameter could contain {'storage' => 10}. The values may be
|
87
|
+
# only approximate or they can be missing altogether. In these cases, the
|
88
|
+
# real values must be reported using method +confirm+.
|
89
|
+
#
|
90
|
+
# == Return values
|
91
|
+
# A hash containing there keys:
|
92
|
+
# <tt>:id</tt>::
|
93
|
+
# Transaction id. This is required for confirmation/cancellation of the
|
94
|
+
# transaction later.
|
95
|
+
# <tt>:provider_verification_key</tt>::
|
96
|
+
# This key should be sent back to the user so he/she can use it to verify
|
97
|
+
# the authenticity of the provider.
|
98
|
+
# <tt>:contract_name</tt>::
|
99
|
+
# This is name of the contract the user is singed for. This information
|
100
|
+
# can be used to serve different responses according to contract types,
|
101
|
+
# if that is desirable.
|
102
|
+
#
|
103
|
+
# == Exceptions
|
104
|
+
#
|
105
|
+
# ThreeScale::UserKeyInvalid:: +user_key+ is not valid
|
106
|
+
# ThreeScale::ProviderKeyInvalid:: +provider_authentication_key+ is not valid
|
107
|
+
# ThreeScale::MetricInvalid:: +usage+ contains invalid metrics
|
108
|
+
# ThreeScale::ContractNotActive:: contract is not active
|
109
|
+
# ThreeScale::LimitsExceeded:: usage limits are exceeded
|
110
|
+
# ThreeScale::UnknownError:: some other unexpected error
|
111
|
+
#
|
112
|
+
def start(user_key, usage = {})
|
113
|
+
uri = URI.parse("#{host}/transactions.xml")
|
114
|
+
params = {
|
115
|
+
'user_key' => prepare_key(user_key),
|
116
|
+
'provider_key' => provider_authentication_key
|
117
|
+
}
|
118
|
+
params.merge!(encode_params(usage, 'usage'))
|
119
|
+
response = Net::HTTP.post_form(uri, params)
|
120
|
+
|
121
|
+
if response.is_a?(Net::HTTPSuccess)
|
122
|
+
element = Hpricot::XML(response.body).at('transaction')
|
123
|
+
[:id, :provider_verification_key, :contract_name].inject({}) do |memo, key|
|
124
|
+
memo[key] = element.at(key).inner_text if element.at(key)
|
125
|
+
memo
|
126
|
+
end
|
127
|
+
else
|
128
|
+
handle_error(response.body)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
# Confirms a transaction.
|
133
|
+
#
|
134
|
+
# == Arguments
|
135
|
+
#
|
136
|
+
# +transaction_id+::
|
137
|
+
# A transaction id obtained from previous call to +start+.
|
138
|
+
# +usage+::
|
139
|
+
# A hash of metric names/values pairs containing actual resource usage
|
140
|
+
# of this request. This parameter is required only if no usage information
|
141
|
+
# was passed to method +start+ for this transaction, or if it was only
|
142
|
+
# approximate.
|
143
|
+
#
|
144
|
+
# == Return values
|
145
|
+
#
|
146
|
+
# If there were no exceptions raised, returns true.
|
147
|
+
#
|
148
|
+
# == Exceptions
|
149
|
+
#
|
150
|
+
# ThreeScale::TransactionNotFound:: transactions does not exits
|
151
|
+
# ThreeScale::ProviderKeyInvalid:: +provider_authentication_key+ is not valid
|
152
|
+
# ThreeScale::MetricInvalid:: +usage+ contains invalid metrics
|
153
|
+
# ThreeScale::UnknownError:: some other unexpected error
|
154
|
+
#
|
155
|
+
def confirm(transaction_id, usage = {})
|
156
|
+
uri = URI.parse("#{host}/transactions/#{CGI.escape(transaction_id.to_s)}/confirm.xml")
|
157
|
+
params = {
|
158
|
+
'provider_key' => provider_authentication_key
|
159
|
+
}
|
160
|
+
params.merge!(encode_params(usage, 'usage'))
|
161
|
+
|
162
|
+
response = Net::HTTP.post_form(uri, params)
|
163
|
+
response.is_a?(Net::HTTPSuccess) ? true : handle_error(response.body)
|
164
|
+
end
|
165
|
+
|
166
|
+
# Cancels a transaction.
|
167
|
+
#
|
168
|
+
# Use this if request processing failed. Any estimated resource usage
|
169
|
+
# reported by preceding call to +start+ will be deleted. You don't have to
|
170
|
+
# call this if call to +start+ itself failed.
|
171
|
+
#
|
172
|
+
# == Arguments
|
173
|
+
#
|
174
|
+
# +transaction_id+::
|
175
|
+
# A transaction id obtained from previous call to +start+.
|
176
|
+
#
|
177
|
+
# == Return values
|
178
|
+
#
|
179
|
+
# If there were no exceptions raised, returns true.
|
180
|
+
#
|
181
|
+
# == Exceptions
|
182
|
+
#
|
183
|
+
# ThreeScale::TransactionNotFound:: transactions does not exits
|
184
|
+
# ThreeScale::ProviderKeyInvalid:: +provider_authentication_key+ is not valid
|
185
|
+
# ThreeScale::UnknownError:: some other unexpected error
|
186
|
+
#
|
187
|
+
def cancel(transaction_id)
|
188
|
+
uri = URI.parse("#{host}/transactions/#{CGI.escape(transaction_id.to_s)}.xml" +
|
189
|
+
"?provider_key=#{CGI.escape(provider_authentication_key)}")
|
190
|
+
|
191
|
+
response = Net::HTTP.start(uri.host, uri.port) do |http|
|
192
|
+
http.delete("#{uri.path}?#{uri.query}")
|
193
|
+
end
|
194
|
+
|
195
|
+
response.is_a?(Net::HTTPSuccess) ? true : handle_error(response.body)
|
196
|
+
end
|
197
|
+
|
198
|
+
KEY_PREFIX = '3scale-' # :nodoc:
|
199
|
+
|
200
|
+
# This can be used to quickly distinguish between keys used with 3scale
|
201
|
+
# system and any other keys the provider might use. Returns true if the key
|
202
|
+
# is for 3scale system.
|
203
|
+
def system_key?(key)
|
204
|
+
# Key should start with prefix
|
205
|
+
key.index(KEY_PREFIX) == 0
|
206
|
+
end
|
207
|
+
|
208
|
+
private
|
209
|
+
|
210
|
+
# Encode hash into form suitable for sending it as params of HTTP request.
|
211
|
+
def encode_params(params, prefix)
|
212
|
+
params.inject({}) do |memo, (key, value)|
|
213
|
+
memo["#{prefix}[#{CGI.escape(key)}]"] = CGI.escape(value.to_s)
|
214
|
+
memo
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
def prepare_key(key)
|
219
|
+
system_key?(key) ? key[KEY_PREFIX.length..-1] : key
|
220
|
+
end
|
221
|
+
|
222
|
+
CODES_TO_EXCEPTIONS = {
|
223
|
+
'user.exceeded_limits' => LimitsExceeded,
|
224
|
+
'user.invalid_key' => UserKeyInvalid,
|
225
|
+
'user.inactive_contract' => ContractNotActive,
|
226
|
+
'provider.invalid_key' => ProviderKeyInvalid,
|
227
|
+
'provider.invalid_metric' => MetricInvalid,
|
228
|
+
'provider.invalid_transaction_id' => TransactionNotFound} # :nodoc:
|
229
|
+
|
230
|
+
def handle_error(response)
|
231
|
+
element = Hpricot::XML(response).at('error')
|
232
|
+
raise UnknownError unless element
|
233
|
+
raise CODES_TO_EXCEPTIONS[element[:id]] || UnknownError, element.inner_text
|
234
|
+
end
|
235
|
+
end
|
236
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require "#{File.dirname(__FILE__)}/3scale/interface"
|
@@ -0,0 +1,218 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'activesupport'
|
3
|
+
require 'fake_web'
|
4
|
+
require 'mocha'
|
5
|
+
require 'test/unit'
|
6
|
+
|
7
|
+
require "#{File.dirname(__FILE__)}/../lib/3scale/interface"
|
8
|
+
|
9
|
+
class InterfaceTest < Test::Unit::TestCase
|
10
|
+
def setup
|
11
|
+
@interface = ThreeScale::Interface.new('http://3scale.net', 'some_key')
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_start_should_raise_exception_on_invalid_user_key
|
15
|
+
FakeWeb.register_uri('http://3scale.net/transactions.xml',
|
16
|
+
:status => ['403', 'Forbidden'],
|
17
|
+
:string => stub_error('user.invalid_key'))
|
18
|
+
|
19
|
+
assert_raise ThreeScale::UserKeyInvalid do
|
20
|
+
@interface.start('invalid_key')
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_start_should_raise_exception_on_invalid_provider_key
|
25
|
+
FakeWeb.register_uri('http://3scale.net/transactions.xml',
|
26
|
+
:status => ['403', 'Forbidden'],
|
27
|
+
:string => stub_error('provider.invalid_key'))
|
28
|
+
|
29
|
+
assert_raise ThreeScale::ProviderKeyInvalid do
|
30
|
+
@interface.start('valid_key')
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_start_should_raise_exception_on_inactive_contract
|
35
|
+
FakeWeb.register_uri('http://3scale.net/transactions.xml',
|
36
|
+
:status => ['403', 'Forbidden'],
|
37
|
+
:string => stub_error('user.inactive_contract'))
|
38
|
+
|
39
|
+
assert_raise ThreeScale::ContractNotActive do
|
40
|
+
@interface.start('valid_key', 'clicks' => 1)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_start_should_raise_exception_on_invalid_metric
|
45
|
+
FakeWeb.register_uri('http://3scale.net/transactions.xml',
|
46
|
+
:status => ['400', 'Bad Request'],
|
47
|
+
:string => stub_error('provider.invalid_metric'))
|
48
|
+
|
49
|
+
assert_raise ThreeScale::MetricInvalid do
|
50
|
+
@interface.start('valid_key', 'clicks' => 1)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_start_should_raise_exception_on_exceeded_limits
|
55
|
+
FakeWeb.register_uri('http://3scale.net/transactions.xml',
|
56
|
+
:status => ['403', 'Forbidden'],
|
57
|
+
:string => stub_error('user.exceeded_limits'))
|
58
|
+
|
59
|
+
assert_raise ThreeScale::LimitsExceeded do
|
60
|
+
@interface.start('valid_key', 'clicks' => 1)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_start_should_raise_exception_on_unexpected_error
|
65
|
+
FakeWeb.register_uri('http://3scale.net/transactions.xml',
|
66
|
+
:status => ['500', 'Internal Server Error'])
|
67
|
+
|
68
|
+
assert_raise ThreeScale::UnknownError do
|
69
|
+
@interface.start('valid_key', 'clicks' => 1)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def test_start_should_send_usage_data
|
74
|
+
Net::HTTP.expects(:post_form).
|
75
|
+
with(anything, has_entries('usage[hits]' => '1')).
|
76
|
+
returns(stub_response)
|
77
|
+
|
78
|
+
@interface.start('valid_key', 'hits' => 1)
|
79
|
+
end
|
80
|
+
|
81
|
+
def test_start_should_return_transaction_data_on_success
|
82
|
+
FakeWeb.register_uri('http://3scale.net/transactions.xml',
|
83
|
+
:status => ['200', 'OK'],
|
84
|
+
:string => {:id => '42', :provider_verification_key => 'some_key',
|
85
|
+
:contract_name => 'ultimate'}.to_xml(:root => 'transaction',
|
86
|
+
:dasherize => false))
|
87
|
+
|
88
|
+
result = @interface.start('valid_key', {'clicks' => 1})
|
89
|
+
|
90
|
+
assert_equal '42', result[:id]
|
91
|
+
assert_equal 'some_key', result[:provider_verification_key]
|
92
|
+
assert_equal 'ultimate', result[:contract_name]
|
93
|
+
end
|
94
|
+
|
95
|
+
def test_start_should_strip_3scale_prefix_from_user_key_before_sending
|
96
|
+
Net::HTTP.expects(:post_form).with(anything,
|
97
|
+
has_entries('user_key' => 'foo')).returns(stub_response)
|
98
|
+
|
99
|
+
@interface.start('3scale-foo')
|
100
|
+
end
|
101
|
+
|
102
|
+
def test_start_should_leave_user_key_unchanged_if_it_does_not_contain_3scale_prefix
|
103
|
+
Net::HTTP.expects(:post_form).with(anything,
|
104
|
+
has_entries('user_key' => 'foo')).returns(stub_response)
|
105
|
+
|
106
|
+
@interface.start('foo')
|
107
|
+
end
|
108
|
+
|
109
|
+
def test_confirm_should_raise_exception_on_invalid_transaction
|
110
|
+
FakeWeb.register_uri('http://3scale.net/transactions/42/confirm.xml',
|
111
|
+
:status => ['404', 'Not Found'],
|
112
|
+
:string => stub_error('provider.invalid_transaction_id'))
|
113
|
+
|
114
|
+
assert_raise ThreeScale::TransactionNotFound do
|
115
|
+
@interface.confirm(42)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def test_confirm_should_raise_exception_on_invalid_provider_key
|
120
|
+
FakeWeb.register_uri('http://3scale.net/transactions/42/confirm.xml',
|
121
|
+
:status => ['403', 'Forbidden'],
|
122
|
+
:string => stub_error('provider.invalid_key'))
|
123
|
+
|
124
|
+
assert_raise ThreeScale::ProviderKeyInvalid do
|
125
|
+
@interface.confirm(42)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def test_confirm_should_raise_exception_on_invalid_metric
|
130
|
+
FakeWeb.register_uri('http://3scale.net/transactions/42/confirm.xml',
|
131
|
+
:status => ['400', 'Bad Request'],
|
132
|
+
:string => stub_error('provider.invalid_metric'))
|
133
|
+
|
134
|
+
assert_raise ThreeScale::MetricInvalid do
|
135
|
+
@interface.confirm(42, 'clicks' => 1)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
def test_confirm_should_raise_exception_on_unexpected_error
|
140
|
+
FakeWeb.register_uri('http://3scale.net/transactions/42/confirm.xml',
|
141
|
+
:status => ['500', 'Internal Server Error'])
|
142
|
+
|
143
|
+
assert_raise ThreeScale::UnknownError do
|
144
|
+
@interface.confirm(42)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
def test_confirm_should_return_true_on_success
|
149
|
+
FakeWeb.register_uri('http://3scale.net/transactions/42/confirm.xml',
|
150
|
+
:status => ['200', 'OK'])
|
151
|
+
|
152
|
+
result = @interface.confirm(42, 'clicks' => 1)
|
153
|
+
assert_equal true, result
|
154
|
+
end
|
155
|
+
|
156
|
+
def test_confirm_should_send_usage_data
|
157
|
+
Net::HTTP.expects(:post_form).
|
158
|
+
with(anything, has_entries('usage[hits]' => '1')).
|
159
|
+
returns(stub_response)
|
160
|
+
|
161
|
+
@interface.confirm(42, 'hits' => 1)
|
162
|
+
end
|
163
|
+
|
164
|
+
def test_cancel_should_raise_exception_on_invalid_transaction
|
165
|
+
FakeWeb.register_uri('http://3scale.net/transactions/42.xml?provider_key=some_key',
|
166
|
+
:status => ['404', 'Not Found'],
|
167
|
+
:string => stub_error('provider.invalid_transaction_id'))
|
168
|
+
|
169
|
+
assert_raise ThreeScale::TransactionNotFound do
|
170
|
+
@interface.cancel(42)
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
def test_cancel_should_raise_exception_on_invalid_provider_key
|
175
|
+
FakeWeb.register_uri('http://3scale.net/transactions/42.xml?provider_key=some_key',
|
176
|
+
:status => ['403', 'Forbidden'],
|
177
|
+
:string => stub_error('provider.invalid_key'))
|
178
|
+
|
179
|
+
assert_raise ThreeScale::ProviderKeyInvalid do
|
180
|
+
@interface.cancel(42)
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
def test_cancel_should_raise_exception_on_unexpected_error
|
185
|
+
FakeWeb.register_uri('http://3scale.net/transactions/42.xml?provider_key=some_key',
|
186
|
+
:status => ['500', 'Internal Server Error'])
|
187
|
+
|
188
|
+
assert_raise ThreeScale::UnknownError do
|
189
|
+
@interface.cancel(42)
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
def test_cancel_should_return_true_on_success
|
194
|
+
FakeWeb.register_uri('http://3scale.net/transactions/42.xml?provider_key=some_key',
|
195
|
+
:status => ['200', 'OK'])
|
196
|
+
|
197
|
+
result = @interface.cancel(42)
|
198
|
+
assert_equal true, result
|
199
|
+
end
|
200
|
+
|
201
|
+
def test_should_identify_3scale_keys
|
202
|
+
assert @interface.system_key?('3scale-foo')
|
203
|
+
assert !@interface.system_key?('foo')
|
204
|
+
end
|
205
|
+
|
206
|
+
private
|
207
|
+
|
208
|
+
def stub_error(id)
|
209
|
+
"<error id=\"#{id}\">blah blah</error>"
|
210
|
+
end
|
211
|
+
|
212
|
+
def stub_response
|
213
|
+
response = stub
|
214
|
+
response.stubs(:is_a?).with(Net::HTTPSuccess).returns(true)
|
215
|
+
response.stubs(:body).returns('<transaction></transaction>')
|
216
|
+
response
|
217
|
+
end
|
218
|
+
end
|
metadata
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: 3scale-3scale_ws_api_for_ruby
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.4.7
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- "Adam Cig\xC3\xA1nek"
|
8
|
+
- Josep M. Pujol
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2008-10-27 00:00:00 -07:00
|
14
|
+
default_executable:
|
15
|
+
dependencies:
|
16
|
+
- !ruby/object:Gem::Dependency
|
17
|
+
name: hpricot
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.6.161
|
24
|
+
version:
|
25
|
+
description:
|
26
|
+
email: adam@3scale.net
|
27
|
+
executables: []
|
28
|
+
|
29
|
+
extensions: []
|
30
|
+
|
31
|
+
extra_rdoc_files:
|
32
|
+
- README
|
33
|
+
files:
|
34
|
+
- init.rb
|
35
|
+
- lib/3scale/interface.rb
|
36
|
+
- lib/3scale_interface.rb
|
37
|
+
- README
|
38
|
+
- Rakefile
|
39
|
+
- test/interface_test.rb
|
40
|
+
has_rdoc: true
|
41
|
+
homepage: http://www.3scale.net
|
42
|
+
post_install_message:
|
43
|
+
rdoc_options: []
|
44
|
+
|
45
|
+
require_paths:
|
46
|
+
- lib
|
47
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
48
|
+
requirements:
|
49
|
+
- - ">="
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: "0"
|
52
|
+
version:
|
53
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: "0"
|
58
|
+
version:
|
59
|
+
requirements: []
|
60
|
+
|
61
|
+
rubyforge_project:
|
62
|
+
rubygems_version: 1.2.0
|
63
|
+
signing_key:
|
64
|
+
specification_version: 2
|
65
|
+
summary: 3scale web service management API for Ruby.
|
66
|
+
test_files:
|
67
|
+
- test/interface_test.rb
|