amaze_sns 1.3.0 → 2.0.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.
- data/README.md +26 -14
- data/lib/amaze/request.rb +18 -28
- data/lib/amaze/topic.rb +40 -31
- data/lib/amaze_sns.rb +31 -32
- data/spec/amaze_sns_spec.rb +123 -77
- data/spec/em_http_request_spec_helper.rb +74 -0
- data/spec/request_spec.rb +0 -0
- data/spec/spec.opts +0 -1
- data/spec/spec_helper.rb +21 -39
- data/spec/subscription_spec.rb +0 -0
- data/spec/topic_spec.rb +495 -5
- metadata +23 -57
data/spec/amaze_sns_spec.rb
CHANGED
@@ -1,14 +1,17 @@
|
|
1
|
-
require File.dirname(__FILE__) + '/spec_helper.rb'
|
1
|
+
#require File.dirname(__FILE__) + '/spec_helper.rb'
|
2
|
+
require File.expand_path('../spec_helper', __FILE__)
|
3
|
+
|
4
|
+
require 'em-http'
|
2
5
|
|
3
6
|
describe AmazeSNS do
|
4
|
-
|
5
|
-
before(:each) do
|
6
|
-
EventMachine::MockHttpRequest.reset_counts!
|
7
|
+
before :each do
|
7
8
|
EventMachine::MockHttpRequest.reset_registry!
|
9
|
+
EventMachine::MockHttpRequest.reset_counts!
|
10
|
+
EventMachine::MockHttpRequest.pass_through_requests = false
|
8
11
|
end
|
9
12
|
|
10
|
-
describe 'in its initial state' do
|
11
13
|
|
14
|
+
describe 'in its initial state' do
|
12
15
|
it "should return the preconfigured host endpoint" do
|
13
16
|
AmazeSNS.host.should == 'sns.us-east-1.amazonaws.com'
|
14
17
|
end
|
@@ -17,18 +20,35 @@ describe AmazeSNS do
|
|
17
20
|
AmazeSNS.topics.should == {}
|
18
21
|
end
|
19
22
|
|
23
|
+
it "should return a blank Subscriptions hash" do
|
24
|
+
AmazeSNS.subscriptions.should == {}
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'should have the logger instantiated' do
|
28
|
+
AmazeSNS.logger.debug('some message')
|
29
|
+
AmazeSNS.logger.should be_kind_of(Logger)
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'should be able to accept any kind of logger' do
|
33
|
+
a_logger = mock("MyLogger")
|
34
|
+
a_logger.should_receive(:debug).with('some data')
|
35
|
+
AmazeSNS.logger = a_logger
|
36
|
+
AmazeSNS.logger.debug('some data')
|
37
|
+
AmazeSNS.logger = nil
|
38
|
+
end
|
20
39
|
end
|
21
40
|
|
22
41
|
describe 'without the keys' do
|
23
42
|
it 'should raise an ArgumentError if no keys are present' do
|
43
|
+
AmazeSNS.skey=''
|
44
|
+
AmazeSNS.akey=''
|
24
45
|
lambda{
|
25
46
|
AmazeSNS['test']
|
26
47
|
}.should raise_error(AmazeSNS::CredentialError)
|
27
48
|
end
|
28
49
|
end
|
29
50
|
|
30
|
-
describe 'with the keys configured' do
|
31
|
-
|
51
|
+
describe 'with the keys configured' do
|
32
52
|
before do
|
33
53
|
AmazeSNS.akey = '123456'
|
34
54
|
AmazeSNS.skey = '123456'
|
@@ -39,97 +59,123 @@ describe AmazeSNS do
|
|
39
59
|
@topic.should be_kind_of(Topic)
|
40
60
|
@topic.topic.should == 'Test'
|
41
61
|
end
|
42
|
-
|
43
62
|
end
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
join('&')
|
54
|
-
else
|
55
|
-
query.to_s
|
56
|
-
end
|
57
|
-
if !uri_query.to_s.empty?
|
58
|
-
encoded_query = [encoded_query, uri_query].reject {|part| part.empty?}.join("&")
|
59
|
-
end
|
60
|
-
return path if encoded_query.to_s.empty?
|
61
|
-
"#{path}?#{encoded_query}"
|
62
|
-
end
|
63
|
-
end
|
63
|
+
|
64
|
+
describe 'making the api calls' do
|
65
|
+
before :each do
|
66
|
+
@url = 'http://sns.us-east-1.amazonaws.com:80/?Action=ListTopics&Signature=ItTAjeexIPC43pHMZLCL7utnpK8j8AbTUZ3KGUSMzNc%3D&AWSAccessKeyId=123456&Timestamp=123&SignatureVersion=2&SignatureMethod=HmacSHA256'
|
67
|
+
EventMachine::MockHttpRequest.reset_registry!
|
68
|
+
EventMachine::MockHttpRequest.reset_counts!
|
69
|
+
EventMachine::MockHttpRequest.pass_through_requests = false #set to false to not hit the actual API endpoint
|
70
|
+
|
71
|
+
@time_stub = stub("A")
|
64
72
|
end
|
65
73
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
EM::HttpRequest.reset_counts!
|
70
|
-
EM::HttpRequest.pass_through_requests = false
|
74
|
+
it 'should be able to access the API endpoint' do
|
75
|
+
@time_stub.should_receive(:iso8601).and_return(123)
|
76
|
+
Time.stub(:now).and_return(@time_stub)
|
71
77
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
78
|
+
EventMachine::MockHttpRequest.use {
|
79
|
+
data = <<-RESPONSE.gsub(/^ +/, '')
|
80
|
+
HTTP/1.0 200 OK
|
81
|
+
Date: Mon, 16 Nov 2009 20:39:15 GMT
|
82
|
+
Expires: -1
|
83
|
+
Cache-Control: private, max-age=0
|
84
|
+
Content-Type: text/html; charset=ISO-8859-1
|
85
|
+
Via: 1.0 .:80 (squid)
|
86
|
+
Connection: close
|
79
87
|
|
80
|
-
|
88
|
+
This is my awesome content
|
89
|
+
RESPONSE
|
90
|
+
|
91
|
+
EventMachine::MockHttpRequest.register(@url,:get,{},data)
|
92
|
+
|
93
|
+
EM.run{
|
94
|
+
d = AmazeSNS.list_topics
|
95
|
+
d.callback{
|
96
|
+
EM::HttpRequest.count(@url, :get).should == 1
|
97
|
+
EM.stop
|
98
|
+
}
|
99
|
+
d.errback{|error|
|
100
|
+
EM.stop
|
101
|
+
}
|
102
|
+
}
|
81
103
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
104
|
+
} #end EM:MockHttpRequest block
|
105
|
+
end
|
106
|
+
|
107
|
+
it 'should return a deferrable on fail' do
|
108
|
+
@time_stub.should_receive(:iso8601).and_return(123)
|
109
|
+
Time.stub(:now).and_return(@time_stub)
|
110
|
+
|
111
|
+
EventMachine::MockHttpRequest.use {
|
112
|
+
data = <<-RESPONSE.gsub(/^ +/, '')
|
113
|
+
HTTP/1.0 403 Unauthorized
|
114
|
+
Date: Mon, 16 Nov 2009 20:39:15 GMT
|
115
|
+
Expires: -1
|
116
|
+
Cache-Control: private, max-age=0
|
117
|
+
Content-Type: text/html; charset=ISO-8859-1
|
118
|
+
Via: 1.0 .:80 (squid)
|
119
|
+
Connection: close
|
86
120
|
|
87
|
-
|
88
|
-
|
89
|
-
signature = Base64.encode64(hmac.digest).chomp
|
121
|
+
403 UNAUTHORIZED: Some error
|
122
|
+
RESPONSE
|
90
123
|
|
91
|
-
|
92
|
-
|
93
|
-
|
124
|
+
EventMachine::MockHttpRequest.register(@url,:get,{},data)
|
125
|
+
|
126
|
+
EM.run{
|
127
|
+
d= AmazeSNS.list_topics
|
128
|
+
d.callback{
|
129
|
+
fail
|
130
|
+
}
|
131
|
+
d.errback{|error|
|
132
|
+
EM::HttpRequest.count(@url, :get).should == 1
|
133
|
+
error.should be_kind_of(AuthorizationError)
|
134
|
+
EM.stop
|
135
|
+
}
|
136
|
+
|
137
|
+
}
|
138
|
+
|
139
|
+
} #end EM:MockHttpRequest block
|
94
140
|
end
|
95
141
|
|
96
|
-
it
|
97
|
-
|
98
|
-
|
99
|
-
data = <<-RESPONSE.gsub(/^ +/, '')
|
100
|
-
HTTP/1.1 202 Accepted
|
101
|
-
Content-Type: text/html
|
102
|
-
Content-Length: 13
|
103
|
-
Connection: keep-alive
|
104
|
-
Server: thin 1.2.7 codename No Hup
|
105
|
-
|
106
|
-
202 ACCEPTED
|
107
|
-
RESPONSE
|
142
|
+
it 'should call method_missing and process_query' do
|
143
|
+
@time_stub.should_receive(:iso8601).and_return(123)
|
144
|
+
Time.stub(:now).and_return(@time_stub)
|
108
145
|
|
109
|
-
|
146
|
+
#rspec expectations matchers
|
147
|
+
AmazeSNS.should respond_to(:method_missing)
|
148
|
+
AmazeSNS.should respond_to(:process_query).with(1).argument
|
110
149
|
|
111
|
-
|
150
|
+
data = <<-RESPONSE.gsub(/^ +/, '')
|
151
|
+
HTTP/1.0 200 OK
|
152
|
+
Date: Mon, 16 Nov 2009 20:39:15 GMT
|
153
|
+
Expires: -1
|
154
|
+
Cache-Control: private, max-age=0
|
155
|
+
Content-Type: text/html; charset=ISO-8859-1
|
156
|
+
Via: 1.0 .:80 (squid)
|
157
|
+
Connection: close
|
158
|
+
|
159
|
+
This is my awesome content
|
160
|
+
RESPONSE
|
112
161
|
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
AmazeSNS.
|
162
|
+
EventMachine::MockHttpRequest.use{
|
163
|
+
EventMachine::MockHttpRequest.register(@url,:get,{},data)
|
164
|
+
|
165
|
+
EM.run{
|
166
|
+
AmazeSNS.list_topics
|
118
167
|
EM.stop
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
168
|
+
}
|
169
|
+
|
170
|
+
} #end EM:MockHttpRequest block
|
123
171
|
end
|
124
172
|
|
125
173
|
|
126
174
|
end
|
127
175
|
|
128
|
-
|
129
|
-
|
130
|
-
|
131
176
|
after do
|
132
177
|
AmazeSNS.topics={}
|
178
|
+
AmazeSNS.subscriptions={}
|
133
179
|
end
|
134
180
|
|
135
181
|
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module EMHttpRequestSpecHelper
|
2
|
+
|
3
|
+
def failed
|
4
|
+
EventMachine.stop
|
5
|
+
fail
|
6
|
+
end
|
7
|
+
|
8
|
+
def http_request(method, uri, options = {}, &block)
|
9
|
+
response = nil
|
10
|
+
error = nil
|
11
|
+
uri = Addressable::URI.heuristic_parse(uri)
|
12
|
+
EventMachine.run {
|
13
|
+
request = EventMachine::HttpRequest.new("#{uri.omit(:userinfo).normalize.to_s}")
|
14
|
+
http = request.send(:setup_request, method, {
|
15
|
+
:timeout => 10,
|
16
|
+
:body => options[:body],
|
17
|
+
:query => options[:query],
|
18
|
+
'authorization' => [uri.user, uri.password],
|
19
|
+
:head => options[:headers]}, &block)
|
20
|
+
http.errback {
|
21
|
+
error = if http.respond_to?(:errors)
|
22
|
+
http.errors
|
23
|
+
else
|
24
|
+
http.error
|
25
|
+
end
|
26
|
+
failed
|
27
|
+
}
|
28
|
+
http.callback {
|
29
|
+
response = OpenStruct.new({
|
30
|
+
:body => http.response,
|
31
|
+
:headers => WebMock::Util::Headers.normalize_headers(extract_response_headers(http)),
|
32
|
+
:message => http.response_header.http_reason,
|
33
|
+
:status => http.response_header.status.to_s
|
34
|
+
})
|
35
|
+
EventMachine.stop
|
36
|
+
}
|
37
|
+
}
|
38
|
+
raise error if error
|
39
|
+
response
|
40
|
+
end
|
41
|
+
|
42
|
+
def client_timeout_exception_class
|
43
|
+
"WebMock timeout error"
|
44
|
+
end
|
45
|
+
|
46
|
+
def connection_refused_exception_class
|
47
|
+
""
|
48
|
+
end
|
49
|
+
|
50
|
+
def default_client_request_headers(request_method = nil, has_body = false)
|
51
|
+
nil
|
52
|
+
end
|
53
|
+
|
54
|
+
def setup_expectations_for_real_request(options = {})
|
55
|
+
end
|
56
|
+
|
57
|
+
def http_library
|
58
|
+
:em_http_request
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
def extract_response_headers(http)
|
64
|
+
headers = {}
|
65
|
+
if http.response_header
|
66
|
+
http.response_header.each do |k,v|
|
67
|
+
v = v.join(", ") if v.is_a?(Array)
|
68
|
+
headers[k] = v
|
69
|
+
end
|
70
|
+
end
|
71
|
+
headers
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
File without changes
|
data/spec/spec.opts
CHANGED
@@ -1 +0,0 @@
|
|
1
|
-
--colour
|
data/spec/spec_helper.rb
CHANGED
@@ -1,47 +1,29 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require '
|
4
|
-
require '
|
5
|
-
require 'amaze_sns'
|
6
|
-
require 'eventmachine'
|
1
|
+
require 'rubygems'
|
2
|
+
|
3
|
+
require 'rspec'
|
4
|
+
require 'rspec/autorun'
|
7
5
|
require 'em-http'
|
8
|
-
require '
|
6
|
+
require 'webmock'
|
7
|
+
require 'webmock/rspec'
|
8
|
+
require 'vcr'
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
# # Switching out EM's defer since it makes tests just a tad more unreliable
|
13
|
-
# alias :defer_original :defer
|
14
|
-
# def defer
|
15
|
-
# yield
|
16
|
-
# end
|
17
|
-
# end unless EM.respond_to?(:defer_original)
|
18
|
-
#
|
19
|
-
#
|
20
|
-
# def run_in_em_loop
|
21
|
-
# EM.run {
|
22
|
-
# yield
|
23
|
-
# }
|
24
|
-
# end
|
25
|
-
#
|
26
|
-
# class Request
|
27
|
-
# self.module_eval do
|
28
|
-
# def http_class
|
29
|
-
# EventMachine::MockHttpRequest
|
30
|
-
# end
|
31
|
-
# end
|
32
|
-
# end
|
10
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
11
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
33
12
|
|
13
|
+
require 'amaze_sns'
|
14
|
+
require 'eventmachine'
|
15
|
+
#require 'support/vcr'
|
34
16
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
17
|
+
VCR.config do |c|
|
18
|
+
c.cassette_library_dir = 'fixtures/cassette_library'
|
19
|
+
c.stub_with :webmock
|
20
|
+
c.ignore_localhost = true
|
21
|
+
c.default_cassette_options = { :record => :none }
|
39
22
|
end
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
end #end configure
|
45
23
|
|
24
|
+
RSpec.configure do |config|
|
25
|
+
config.include WebMock::API
|
26
|
+
config.extend VCR::RSpec::Macros
|
46
27
|
|
28
|
+
end
|
47
29
|
|
File without changes
|
data/spec/topic_spec.rb
CHANGED
@@ -1,11 +1,28 @@
|
|
1
1
|
require File.dirname(__FILE__) + '/spec_helper.rb'
|
2
2
|
|
3
3
|
describe Topic do
|
4
|
-
before do
|
5
|
-
@topic = Topic.new('my_test_topic', 'arn:123456')
|
6
|
-
end
|
7
|
-
|
8
4
|
describe 'in its initial state' do
|
5
|
+
before :each do
|
6
|
+
@attrs_hash = { "SubscriptionsConfirmed"=>"2",
|
7
|
+
"SubscriptionsPending"=>"0",
|
8
|
+
"Owner"=>"365155214602",
|
9
|
+
"TopicArn"=>"arn:aws:sns:us-east-1:365155214602:my_test_topic",
|
10
|
+
"SubscriptionsDeleted"=>"0",
|
11
|
+
"Policy"=>{"Version"=>"2008-10-17",
|
12
|
+
"Id"=>"us-east-1/365155214602/cars55__default_policy_ID",
|
13
|
+
"Statement"=>[{"Action"=>["SNS:GetTopicAttributes", "SNS:SetTopicAttributes", "SNS:AddPermission", "SNS:RemovePermission", "SNS:DeleteTopic", "SNS:Subscribe", "SNS:ListSubscriptionsByTopic", "SNS:Publish", "SNS:Receive"],
|
14
|
+
"Sid"=>"us-east-1/365155214602/my_test_topic__default_statement_ID",
|
15
|
+
"Resource"=>"arn:aws:sns:us-east-1:365155214602:my_test_topic",
|
16
|
+
"Principal"=>{"AWS"=>"*"},
|
17
|
+
"Condition"=>{"StringLike"=>{"AWS:SourceArn"=>"arn:aws:*:*:365155214602:*"}}, "Effect"=>"Allow"}]
|
18
|
+
}# end policy hash
|
19
|
+
} # end outer hash
|
20
|
+
|
21
|
+
@topic = Topic.new('my_test_topic', 'arn:123456')
|
22
|
+
@topic.attributes = @attrs_hash
|
23
|
+
@topic.stub!(:attrs).and_return(@attrs_hash)
|
24
|
+
end
|
25
|
+
|
9
26
|
it 'should be an instance of Topic class' do
|
10
27
|
@topic.should be_kind_of(Topic)
|
11
28
|
end
|
@@ -15,9 +32,482 @@ describe Topic do
|
|
15
32
|
@topic.arn.should == 'arn:123456'
|
16
33
|
end
|
17
34
|
|
35
|
+
it 'should return the attributes when requested' do
|
36
|
+
@topic.attrs.should be_kind_of(Hash)
|
37
|
+
@topic.attrs["SubscriptionsConfirmed"].should == "2"
|
38
|
+
@topic.attrs["Owner"].should == "365155214602"
|
39
|
+
|
40
|
+
@topic.attributes.should == @topic.attrs
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe 'making requests to SNS API' do
|
45
|
+
|
46
|
+
before :each do
|
47
|
+
AmazeSNS.akey = '123456'
|
48
|
+
AmazeSNS.skey = '123456'
|
49
|
+
@time_stub = stub("Time")
|
50
|
+
|
51
|
+
@data = <<-RESPONSE.gsub(/^ +/, '')
|
52
|
+
<CreateTopicResponse xmlns="http://sns.amazonaws.com/doc/2010-03-31/">
|
53
|
+
<CreateTopicResult>
|
54
|
+
<TopicArn>arn:aws:sns:us-east-1:365155214602:MyTopic</TopicArn>
|
55
|
+
</CreateTopicResult>
|
56
|
+
<ResponseMetadata>
|
57
|
+
<RequestId>0a7225aa-e9cb-11df-a5a1-293a0b8d0fcb</RequestId>
|
58
|
+
</ResponseMetadata>
|
59
|
+
</CreateTopicResponse>
|
60
|
+
RESPONSE
|
61
|
+
|
62
|
+
WebMock.reset!
|
63
|
+
WebMock.disable_net_connect!
|
64
|
+
|
65
|
+
@regexp = %r{/?Action=CreateTopic&Name=MyTopic}
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'should send data to the API' do
|
69
|
+
@time_stub.should_receive(:iso8601).and_return(123)
|
70
|
+
Time.stub(:now).and_return(@time_stub)
|
71
|
+
|
72
|
+
stub_http_request(:get, @regexp).to_return(:body => @data,
|
73
|
+
:status => 200,
|
74
|
+
:headers => {'Content-Type' => 'text/xml', 'Connection' => 'close'})
|
75
|
+
|
76
|
+
@arn = AmazeSNS["MyTopic"].create
|
77
|
+
@arn.should == "arn:aws:sns:us-east-1:365155214602:MyTopic"
|
78
|
+
WebMock.should have_requested(:get, %r{http://sns.us-east-1.amazonaws.com:80})
|
79
|
+
end
|
80
|
+
|
81
|
+
it 'should return a deferrable' do
|
82
|
+
t = Topic.new('MyTopic')
|
83
|
+
|
84
|
+
@time_stub.should_receive(:iso8601).and_return(123)
|
85
|
+
Time.stub(:now).and_return(@time_stub)
|
86
|
+
|
87
|
+
stub_http_request(:get, @regexp).to_return(:body => @data, :status => 200)
|
88
|
+
|
89
|
+
params = {
|
90
|
+
'Name' => "MyTopic",
|
91
|
+
'Action' => 'CreateTopic',
|
92
|
+
'SignatureMethod' => 'HmacSHA256',
|
93
|
+
'SignatureVersion' => 2,
|
94
|
+
'Timestamp' => Time.now.iso8601,
|
95
|
+
'AWSAccessKeyId' => AmazeSNS.akey
|
96
|
+
}
|
97
|
+
|
98
|
+
EM.run{
|
99
|
+
d = t.generate_request(params)
|
100
|
+
d.callback{
|
101
|
+
WebMock.should have_requested(:get, @regexp)
|
102
|
+
EM.stop
|
103
|
+
}
|
104
|
+
d.errback{
|
105
|
+
fail
|
106
|
+
EM.stop
|
107
|
+
}
|
108
|
+
}
|
109
|
+
end
|
110
|
+
|
111
|
+
it 'should return a deferrable which fails if exception occurs' do
|
112
|
+
t = Topic.new('MyTopic')
|
113
|
+
|
114
|
+
@time_stub.should_receive(:iso8601).and_return(123)
|
115
|
+
Time.stub(:now).and_return(@time_stub)
|
116
|
+
AmazeSNS.akey = ''
|
117
|
+
|
118
|
+
stub_http_request(:get, @regexp).to_return(:body => @data, :status => 403)
|
119
|
+
|
120
|
+
params = {
|
121
|
+
'Name' => "MyTopic",
|
122
|
+
'Action' => 'CreateTopic',
|
123
|
+
'SignatureMethod' => 'HmacSHA256',
|
124
|
+
'SignatureVersion' => 2,
|
125
|
+
'Timestamp' => Time.now.iso8601,
|
126
|
+
'AWSAccessKeyId' => AmazeSNS.akey
|
127
|
+
}
|
128
|
+
|
129
|
+
EM.run{
|
130
|
+
d = t.generate_request(params)
|
131
|
+
d.callback{
|
132
|
+
fail
|
133
|
+
}
|
134
|
+
d.errback{|error|
|
135
|
+
WebMock.should have_requested(:get, @regexp)
|
136
|
+
error.should be_kind_of(AuthorizationError)
|
137
|
+
EM.stop
|
138
|
+
}
|
139
|
+
}
|
140
|
+
end
|
141
|
+
|
18
142
|
end
|
143
|
+
|
144
|
+
describe 'operations through the API' do
|
145
|
+
before :each do
|
146
|
+
AmazeSNS.akey = '123456'
|
147
|
+
AmazeSNS.skey = '123456'
|
148
|
+
@time_stub = stub("Time")
|
149
|
+
@subscriptions = {}
|
150
|
+
WebMock.reset!
|
151
|
+
WebMock.disable_net_connect!
|
152
|
+
end
|
153
|
+
|
154
|
+
context 'listing topics' do
|
155
|
+
|
156
|
+
before :each do
|
157
|
+
# store the request and response in webmock's own blocks for comparisons
|
158
|
+
WebMock.after_request do |request, response|
|
159
|
+
@response = response
|
160
|
+
@request = request
|
161
|
+
end
|
162
|
+
|
163
|
+
@list_data = <<-RESPONSE.gsub(/^ +/, '')
|
164
|
+
<ListTopicsResponse xmlns="http://sns.amazonaws.com/doc/2010-03-31/">
|
165
|
+
<ListTopicsResult>
|
166
|
+
<Topics>
|
167
|
+
<member>
|
168
|
+
<TopicArn>arn:aws:sns:us-east-1:123456789012:My-Topic</TopicArn>
|
169
|
+
</member>
|
170
|
+
</Topics>
|
171
|
+
</ListTopicsResult>
|
172
|
+
<ResponseMetadata>
|
173
|
+
<RequestId>3f1478c7-33a9-11df-9540-99d0768312d3</RequestId>
|
174
|
+
</ResponseMetadata>
|
175
|
+
</ListTopicsResponse>
|
176
|
+
RESPONSE
|
177
|
+
|
178
|
+
@regexp = %r{/?Action=ListTopics}
|
179
|
+
end
|
180
|
+
|
181
|
+
use_vcr_cassette "topic/list", {:record => :new_episodes, :match_requests_on => [:uri,:method,:body]}
|
182
|
+
|
183
|
+
it 'should be able to get the data through the api' do
|
184
|
+
@time_stub.should_receive(:iso8601).and_return(123)
|
185
|
+
Time.stub(:now).and_return(@time_stub)
|
186
|
+
|
187
|
+
stub_http_request(:get, @regexp).to_return(:body => @list_data,
|
188
|
+
:status => 200,
|
189
|
+
:headers => {'Content-Type' => 'text/xml', 'Connection' => 'close'})
|
190
|
+
|
191
|
+
EM.run{
|
192
|
+
AmazeSNS.list_topics
|
193
|
+
EM.stop
|
194
|
+
}
|
195
|
+
|
196
|
+
WebMock.should have_requested(:get, %r{/?Action=ListTopics}).once
|
197
|
+
WebMock.should have_requested(:get, %r{http://sns.us-east-1.amazonaws.com:80}).once
|
198
|
+
|
199
|
+
@request.to_s.split(" ")[1].should == "http://sns.us-east-1.amazonaws.com/?AWSAccessKeyId=123456&Action=ListTopics&Signature=ItTAjeexIPC43pHMZLCL7utnpK8j8AbTUZ3KGUSMzNc=&SignatureMethod=HmacSHA256&SignatureVersion=2&Timestamp=123"
|
200
|
+
@response.body.should == @list_data
|
201
|
+
@response.headers["Content-Type"].should == "text/xml"
|
202
|
+
end
|
203
|
+
|
204
|
+
it 'should populate the topics hash' do
|
205
|
+
AmazeSNS.topics.has_key?("My-Topic").should be_true
|
206
|
+
end
|
207
|
+
|
208
|
+
end # end list topic spec
|
209
|
+
|
210
|
+
context 'creating a topic' do
|
211
|
+
before :each do
|
212
|
+
|
213
|
+
@data = <<-RESPONSE.gsub(/^ +/, '')
|
214
|
+
<CreateTopicResponse xmlns="http://sns.amazonaws.com/doc/2010-03-31/">
|
215
|
+
<CreateTopicResult>
|
216
|
+
<TopicArn>arn:aws:sns:us-east-1:365155214602:MyTopic</TopicArn>
|
217
|
+
</CreateTopicResult>
|
218
|
+
<ResponseMetadata>
|
219
|
+
<RequestId>0a7225aa-e9cb-11df-a5a1-293a0b8d0fcb</RequestId>
|
220
|
+
</ResponseMetadata>
|
221
|
+
</CreateTopicResponse>
|
222
|
+
RESPONSE
|
223
|
+
|
224
|
+
@regexp = %r{/?Action=CreateTopic&Name=MyTopic}
|
225
|
+
end
|
226
|
+
|
227
|
+
use_vcr_cassette "topic/create", {:record => :new_episodes, :match_requests_on => [:uri,:method,:body]}
|
228
|
+
|
229
|
+
it 'should send data to the API' do
|
230
|
+
@time_stub.should_receive(:iso8601).and_return(123)
|
231
|
+
Time.stub(:now).and_return(@time_stub)
|
232
|
+
|
233
|
+
stub_http_request(:get, @regexp).to_return(:body => @data,
|
234
|
+
:status => 200,
|
235
|
+
:headers => {'Content-Type' => 'text/xml', 'Connection' => 'close'})
|
236
|
+
|
237
|
+
@arn = AmazeSNS["MyTopic"].create
|
238
|
+
@arn.should == "arn:aws:sns:us-east-1:365155214602:MyTopic"
|
239
|
+
WebMock.should have_requested(:get, %r{http://sns.us-east-1.amazonaws.com:80}).once
|
240
|
+
end
|
241
|
+
|
242
|
+
it 'should add the new topic to the topics hash' do
|
243
|
+
AmazeSNS.topics.has_key?("MyTopic").should == true
|
244
|
+
end
|
245
|
+
|
246
|
+
end # end create topic spec
|
247
|
+
|
248
|
+
context 'getting a topic attrs' do
|
249
|
+
before :each do
|
250
|
+
@attrs_data = <<-RESPONSE.gsub(/^ +/, '')
|
251
|
+
<GetTopicAttributesResponse xmlns=\"http://sns.amazonaws.com/doc/2010-03-31/\">
|
252
|
+
<GetTopicAttributesResult>
|
253
|
+
<Attributes>
|
254
|
+
<entry>
|
255
|
+
<key>Owner</key>
|
256
|
+
<value>365155214602</value>
|
257
|
+
</entry>
|
258
|
+
<entry>
|
259
|
+
<key>SubscriptionsPending</key>
|
260
|
+
<value>0</value>
|
261
|
+
</entry>
|
262
|
+
<entry>
|
263
|
+
<key>Policy</key>
|
264
|
+
<value>{ "Version":"2008-10-17","Id":"us-east-1/365155214602/MyTopic__default_policy_ID","Statement":[{"Sid":"us-east-1/365155214602/MyTopic__default_statement_ID","Effect":"Allow","Principal":{"AWS":"*"},"Action":["SNS:Publish","SNS:RemovePermission","SNS:SetTopicAttributes","SNS:DeleteTopic","SNS:ListSubscriptionsByTopic","SNS:GetTopicAttributes","SNS:Receive","SNS:AddPermission","SNS:Subscribe"],"Resource":"arn:aws:sns:us-east-1:365155214602:MyTopic","Condition":{"StringLike":{"AWS:SourceArn":"arn:aws:*:*:365155214602:*"}}}]}</value>
|
265
|
+
</entry>
|
266
|
+
<entry>
|
267
|
+
<key>SubscriptionsConfirmed</key>
|
268
|
+
<value>2</value>
|
269
|
+
</entry>
|
270
|
+
<entry>
|
271
|
+
<key>SubscriptionsDeleted</key>
|
272
|
+
<value>0</value>
|
273
|
+
</entry>
|
274
|
+
<entry>
|
275
|
+
<key>TopicArn</key>
|
276
|
+
<value>arn:aws:sns:us-east-1:365155214602:MyTopic</value>
|
277
|
+
</entry>
|
278
|
+
</Attributes>
|
279
|
+
</GetTopicAttributesResult>
|
280
|
+
<ResponseMetadata>
|
281
|
+
<RequestId>54c67339-0acd-11e0-8483-c91fbf41249a</RequestId>
|
282
|
+
</ResponseMetadata>
|
283
|
+
</GetTopicAttributesResponse>
|
284
|
+
RESPONSE
|
285
|
+
|
286
|
+
@regexp = %r{/?Action=GetTopicAttributes}
|
287
|
+
end
|
288
|
+
|
289
|
+
use_vcr_cassette "topic/attrs", {:record => :new_episodes, :match_requests_on => [:uri,:method,:body]}
|
290
|
+
|
291
|
+
it 'should make the API call' do
|
292
|
+
@time_stub.should_receive(:iso8601).and_return(123)
|
293
|
+
Time.stub(:now).and_return(@time_stub)
|
294
|
+
|
295
|
+
stub_http_request(:get, @regexp).to_return(:body => @attrs_data,
|
296
|
+
:status => 200,
|
297
|
+
:headers => {})
|
298
|
+
|
299
|
+
AmazeSNS["MyTopic"].attrs
|
300
|
+
WebMock.should have_requested(:get, %r{http://sns.us-east-1.amazonaws.com:80}).once
|
301
|
+
WebMock.should have_requested(:get, @regexp).once
|
302
|
+
end
|
303
|
+
|
304
|
+
it 'should store its attributes into a hash' do
|
305
|
+
@outcome = AmazeSNS["MyTopic"].attributes
|
306
|
+
@outcome.should be_kind_of(Hash)
|
307
|
+
@outcome.has_key?("Owner").should be_true
|
308
|
+
@outcome.has_key?("TopicArn").should be_true
|
309
|
+
|
310
|
+
@outcome["Owner"].should == "365155214602"
|
311
|
+
@outcome["TopicArn"].should == "arn:aws:sns:us-east-1:365155214602:MyTopic"
|
312
|
+
@outcome["Policy"]["Version"].should == "2008-10-17"
|
313
|
+
@outcome["Policy"]["Id"].should == "us-east-1/365155214602/MyTopic__default_policy_ID"
|
314
|
+
@outcome["Policy"]["Statement"][0]["Action"].should == ["SNS:Publish","SNS:RemovePermission","SNS:SetTopicAttributes","SNS:DeleteTopic","SNS:ListSubscriptionsByTopic","SNS:GetTopicAttributes","SNS:Receive","SNS:AddPermission","SNS:Subscribe"]
|
315
|
+
@outcome["Policy"]["Statement"][0]["Resource"].should == "arn:aws:sns:us-east-1:365155214602:MyTopic"
|
316
|
+
end
|
317
|
+
|
318
|
+
|
319
|
+
end # end of topic attrs
|
320
|
+
|
321
|
+
context 'subscribing to a topic' do
|
322
|
+
before :each do
|
323
|
+
@sub_data = <<-RESPONSE.gsub(/^ +/, '')
|
324
|
+
<SubscribeResponse xmlns="http://sns.amazonaws.com/doc/2010-03-31/">
|
325
|
+
<SubscribeResult>
|
326
|
+
<SubscriptionArn>pending confirmation</SubscriptionArn>
|
327
|
+
</SubscribeResult>
|
328
|
+
<ResponseMetadata>
|
329
|
+
<RequestId>a169c740-3766-11df-8963-01868b7c937a</RequestId>
|
330
|
+
</ResponseMetadata>
|
331
|
+
</SubscribeResponse>
|
332
|
+
RESPONSE
|
333
|
+
|
334
|
+
@regexp = %r{/?Action=Subscribe}
|
335
|
+
end
|
336
|
+
|
337
|
+
use_vcr_cassette "topic/subscribe", {:record => :new_episodes, :match_requests_on => [:uri,:method,:body]}
|
338
|
+
|
339
|
+
it 'should recive a pending confirmation on subscription' do
|
340
|
+
@time_stub.should_receive(:iso8601).and_return(123)
|
341
|
+
Time.stub(:now).and_return(@time_stub)
|
342
|
+
|
343
|
+
stub_http_request(:get, @regexp).to_return(:body => @sub_data,
|
344
|
+
:status => 200,
|
345
|
+
:headers => {'Content-Type' => 'text/xml', 'Connection' => 'close'})
|
346
|
+
|
347
|
+
res = AmazeSNS["MyTopic"].subscribe(:endpoint => "example@amazon.com", :protocol => "email")
|
348
|
+
WebMock.should have_requested(:get, %r{http://sns.us-east-1.amazonaws.com:80}).once
|
349
|
+
WebMock.should have_requested(:get, @regexp).once
|
350
|
+
res.should == "pending confirmation"
|
351
|
+
end
|
352
|
+
end
|
353
|
+
|
354
|
+
context 'setting a topic attrs' do
|
355
|
+
before :each do
|
356
|
+
@data = <<-RESPONSE.gsub(/^ +/, '')
|
357
|
+
<SetTopicAttributesResponse xmlns="http://sns.amazonaws.com/doc/2010-03-31/">
|
358
|
+
<ResponseMetadata>
|
359
|
+
<RequestId>a8763b99-33a7-11df-a9b7-05d48da6f042</RequestId>
|
360
|
+
</ResponseMetadata>
|
361
|
+
</SetTopicAttributesResponse>
|
362
|
+
RESPONSE
|
363
|
+
|
364
|
+
@regexp = %r{/?Action=SetTopicAttributes}
|
365
|
+
end
|
366
|
+
|
367
|
+
use_vcr_cassette "topic/set_attrs", {:record => :new_episodes, :match_requests_on => [:uri,:method,:body]}
|
368
|
+
|
369
|
+
it 'should set the topics attrs' do
|
370
|
+
@time_stub.should_receive(:iso8601).and_return(123)
|
371
|
+
Time.stub(:now).and_return(@time_stub)
|
372
|
+
|
373
|
+
stub_http_request(:get, @regexp).to_return(:body => @data,
|
374
|
+
:status => 200,
|
375
|
+
:headers => {'Content-Type' => 'text/xml', 'Connection' => 'close','Status' => 200})
|
376
|
+
|
377
|
+
AmazeSNS["MyTopic"].set_attrs({:name => "TopicArn", :value => 'lorem ipsum'})
|
378
|
+
|
379
|
+
WebMock.should have_requested(:get, %r{http://sns.us-east-1.amazonaws.com:80}).once
|
380
|
+
WebMock.should have_requested(:get, @regexp).once
|
381
|
+
end
|
382
|
+
|
383
|
+
it 'should update the attributes hash' do
|
384
|
+
AmazeSNS["MyTopic"].attributes["TopicArn"].should == 'lorem ipsum'
|
385
|
+
end
|
386
|
+
end
|
387
|
+
|
388
|
+
context 'subscriptions to a topic' do
|
389
|
+
before :each do
|
390
|
+
@sub_data = <<-RESPONSE.gsub(/^ +/, '')
|
391
|
+
<ListSubscriptionsByTopicResponse xmlns="http://sns.amazonaws.com/ doc/2010-03-31/">
|
392
|
+
<ListSubscriptionsByTopicResult>
|
393
|
+
<Subscriptions>
|
394
|
+
<member>
|
395
|
+
<TopicArn>arn:aws:sns:us-east-1:123456789012:MyTopic</TopicArn>
|
396
|
+
<Protocol>email</Protocol>
|
397
|
+
<SubscriptionArn>arn:aws:sns:us-east-1:123456789012:MyTopic:80289ba6-0fd4-4079-afb4-ce8c8260f0ca</SubscriptionArn>
|
398
|
+
<Owner>123456789012</Owner>
|
399
|
+
<Endpoint>example@amazon.com</Endpoint>
|
400
|
+
</member>
|
401
|
+
</Subscriptions>
|
402
|
+
</ListSubscriptionsByTopicResult>
|
403
|
+
<ResponseMetadata>
|
404
|
+
<RequestId>b9275252-3774-11df-9540-99d0768312d3</RequestId>
|
405
|
+
</ResponseMetadata>
|
406
|
+
</ListSubscriptionsByTopicResponse>
|
407
|
+
RESPONSE
|
408
|
+
|
409
|
+
@regexp = %r{/?Action=ListSubscriptionsByTopic}
|
410
|
+
end
|
411
|
+
|
412
|
+
use_vcr_cassette "topic/subscriptions", {:record => :new_episodes, :match_requests_on => [:uri,:method,:body]}
|
413
|
+
|
414
|
+
it 'should list the subscriptions for this topic' do
|
415
|
+
@time_stub.should_receive(:iso8601).and_return(123)
|
416
|
+
Time.stub(:now).and_return(@time_stub)
|
417
|
+
|
418
|
+
stub_http_request(:get, @regexp).to_return(:body => @sub_data,
|
419
|
+
:status => 200,
|
420
|
+
:headers => {'Content-Type' => 'text/xml', 'Connection' => 'close'})
|
421
|
+
|
422
|
+
entry_hash = {
|
423
|
+
"Owner" => "123456789012",
|
424
|
+
"Endpoint" => "example@amazon.com",
|
425
|
+
"Protocol" => "email",
|
426
|
+
"TopicArn" => "arn:aws:sns:us-east-1:123456789012:MyTopic"
|
427
|
+
}
|
428
|
+
subkey = "arn:aws:sns:us-east-1:123456789012:MyTopic:80289ba6-0fd4-4079-afb4-ce8c8260f0ca"
|
429
|
+
@subscriptions = AmazeSNS["MyTopic"].subscriptions
|
430
|
+
@subscriptions[subkey].should == entry_hash
|
431
|
+
@subscriptions[subkey]["Owner"].should == "123456789012"
|
432
|
+
@subscriptions[subkey]["Endpoint"].should == "example@amazon.com"
|
433
|
+
@subscriptions[subkey]["Protocol"].should == "email"
|
434
|
+
@subscriptions[subkey]["TopicArn"].should == "arn:aws:sns:us-east-1:123456789012:MyTopic"
|
435
|
+
|
436
|
+
WebMock.should have_requested(:get, %r{http://sns.us-east-1.amazonaws.com:80}).once
|
437
|
+
WebMock.should have_requested(:get, @regexp).once
|
438
|
+
end
|
439
|
+
end
|
440
|
+
|
441
|
+
context 'unsubscribing from a topic' do
|
442
|
+
|
443
|
+
before :each do
|
444
|
+
@data = <<-RESPONSE.gsub(/^ +/, '')
|
445
|
+
<UnsubscribeResponse xmlns="http://sns.amazonaws.com/doc/2010-03-31/">
|
446
|
+
<ResponseMetadata>
|
447
|
+
<RequestId>18e0ac39-3776-11df-84c0-b93cc1666b84</RequestId>
|
448
|
+
</ResponseMetadata>
|
449
|
+
</UnsubscribeResponse>
|
450
|
+
RESPONSE
|
451
|
+
|
452
|
+
@regexp = %r{/?Action=Unsubscribe}
|
453
|
+
end
|
454
|
+
|
455
|
+
use_vcr_cassette "topic/unsubscribe", {:record => :new_episodes, :match_requests_on => [:uri,:method,:body]}
|
456
|
+
|
457
|
+
it 'should be able to remove the subscriber' do
|
458
|
+
@time_stub.should_receive(:iso8601).and_return(123)
|
459
|
+
Time.stub(:now).and_return(@time_stub)
|
460
|
+
|
461
|
+
stub_http_request(:get, @regexp).to_return(:body => @data,
|
462
|
+
:status => 200,
|
463
|
+
:headers => {'Content-Type' => 'text/xml', 'Connection' => 'close'})
|
464
|
+
|
465
|
+
|
466
|
+
AmazeSNS["MyTopic"].unsubscribe('arn:aws:sns:us-east-1:123456789012:MyTopic:80289ba6-0fd4-4079-afb4-ce8c8260f0ca')
|
467
|
+
|
468
|
+
WebMock.should have_requested(:get, %r{http://sns.us-east-1.amazonaws.com:80}).once
|
469
|
+
WebMock.should have_requested(:get, @regexp).once
|
470
|
+
end
|
471
|
+
|
472
|
+
end
|
473
|
+
|
474
|
+
context 'deleting a topic' do
|
475
|
+
before :each do
|
476
|
+
@delete_data = <<-RESPONSE.gsub(/^ +/, '')
|
477
|
+
<DeleteTopicResponse xmlns="http://sns.amazonaws.com/doc/2010-03-31/">
|
478
|
+
<ResponseMetadata>
|
479
|
+
<RequestId>f3aa9ac9-3c3d-11df-8235-9dab105e9c32</RequestId>
|
480
|
+
</ResponseMetadata>
|
481
|
+
</DeleteTopicResponse>
|
482
|
+
RESPONSE
|
483
|
+
|
484
|
+
@regexp = %r{/?Action=DeleteTopic}
|
485
|
+
end
|
486
|
+
|
487
|
+
use_vcr_cassette "topic/delete", {:record => :new_episodes, :match_requests_on => [:uri,:method,:body]}
|
488
|
+
|
489
|
+
it 'should send data to the API' do
|
490
|
+
@time_stub.should_receive(:iso8601).and_return(123)
|
491
|
+
Time.stub(:now).and_return(@time_stub)
|
492
|
+
|
493
|
+
stub_http_request(:get, @regexp).to_return(:body => @delete_data,
|
494
|
+
:status => 200,
|
495
|
+
:headers => {'Content-Type' => 'text/xml', 'Connection' => 'close'})
|
496
|
+
|
497
|
+
@request_id = AmazeSNS["MyTopic"].delete
|
498
|
+
@request_id["DeleteTopicResponse"]["ResponseMetadata"]["RequestId"].should == "f3aa9ac9-3c3d-11df-8235-9dab105e9c32"
|
499
|
+
|
500
|
+
WebMock.should have_requested(:get, @regexp).once
|
501
|
+
WebMock.should have_requested(:get, %r{http://sns.us-east-1.amazonaws.com:80}).once
|
502
|
+
end
|
503
|
+
|
504
|
+
it 'should remove entry from the topics hash' do
|
505
|
+
AmazeSNS.topics.has_key?("MyTopic").should_not be_true
|
506
|
+
end
|
507
|
+
|
508
|
+
end # end deleting a topic spec
|
19
509
|
|
20
|
-
|
510
|
+
|
21
511
|
end
|
22
512
|
|
23
513
|
end
|