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.
@@ -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
- describe 'Request#process' do
47
- module EventMachine
48
- module HttpEncoding
49
- def encode_query(path, query, uri_query)
50
- encoded_query = if query.kind_of?(Hash)
51
- query.sort{|a, b| a.to_s <=> b.to_s}.
52
- map { |k, v| encode_param(k, v) }.
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
- before :each do
67
- EM::HttpRequest = EM::MockHttpRequest
68
- EM::HttpRequest.reset_registry!
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
- @params = {
73
- 'Action' => 'ListTopics',
74
- 'SignatureMethod' => 'HmacSHA256',
75
- 'SignatureVersion' => 2,
76
- 'Timestamp' => Time.now.iso8601,
77
- 'AWSAccessKeyId' => AmazeSNS.akey
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
- @query_string = canonical_querystring(@params)
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
- string_to_sign = "GET
83
- #{AmazeSNS.host}
84
- /
85
- #{@query_string}"
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
- hmac = HMAC::SHA256.new(AmazeSNS.skey)
88
- hmac.update( string_to_sign )
89
- signature = Base64.encode64(hmac.digest).chomp
121
+ 403 UNAUTHORIZED: Some error
122
+ RESPONSE
90
123
 
91
- @params['Signature'] = signature
92
- @querystring2 = @params.collect { |key, value| [url_encode(key), url_encode(value)].join("=") }.join('&')
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 "should return a deferrable which succeeds in success case" do
97
- #Time.stub(:now).and_return(123)
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
- url = "http://#{AmazeSNS.host}/?#{@querystring2}"
146
+ #rspec expectations matchers
147
+ AmazeSNS.should respond_to(:method_missing)
148
+ AmazeSNS.should respond_to(:process_query).with(1).argument
110
149
 
111
- EM::HttpRequest.register(url, :get, data)
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
- EM.run {
114
- d = AmazeSNS.list_topics
115
- d.callback{
116
- @raw_resp = Crack::XML.parse(resp.response)
117
- AmazeSNS.process_response(@raw_resp)
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
- $LOAD_PATH.unshift(File.dirname(__FILE__))
2
- require 'spec'
3
- require 'spec/autorun'
4
- require 'request'
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 'em-http/mock'
6
+ require 'webmock'
7
+ require 'webmock/rspec'
8
+ require 'vcr'
9
9
 
10
- Spec::Runner.configure do |config|
11
- # EventMachine.instance_eval do
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
- def fake_response
36
- <<-HEREDOC
37
- <ListTopicsResponse xmlns=\"http://sns.amazonaws.com/doc/2010-03-31/\">\n<ListTopicsResult>\n<Topics>\n<member>\n<TopicArn>arn:aws:sns:us-east-1:365155214602:cars</TopicArn>\n</member>\n<member>\n<TopicArn>arn:aws:sns:us-east-1:365155214602:luckypooz</TopicArn>\n</member>\n<member>\n<TopicArn>arn:aws:sns:us-east-1:365155214602:29steps_products</TopicArn>\n</member>\n</Topics>\n</ListTopicsResult>\n <ResponseMetadata>\n<RequestId>d4a2ff9b-56dc-11df-b6e7-a7864eff589e</RequestId>\n</ResponseMetadata>\n</ListTopicsResponse>
38
- HEREDOC
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>{ &quot;Version&quot;:&quot;2008-10-17&quot;,&quot;Id&quot;:&quot;us-east-1/365155214602/MyTopic__default_policy_ID&quot;,&quot;Statement&quot;:[{&quot;Sid&quot;:&quot;us-east-1/365155214602/MyTopic__default_statement_ID&quot;,&quot;Effect&quot;:&quot;Allow&quot;,&quot;Principal&quot;:{&quot;AWS&quot;:&quot;*&quot;},&quot;Action&quot;:[&quot;SNS:Publish&quot;,&quot;SNS:RemovePermission&quot;,&quot;SNS:SetTopicAttributes&quot;,&quot;SNS:DeleteTopic&quot;,&quot;SNS:ListSubscriptionsByTopic&quot;,&quot;SNS:GetTopicAttributes&quot;,&quot;SNS:Receive&quot;,&quot;SNS:AddPermission&quot;,&quot;SNS:Subscribe&quot;],&quot;Resource&quot;:&quot;arn:aws:sns:us-east-1:365155214602:MyTopic&quot;,&quot;Condition&quot;:{&quot;StringLike&quot;:{&quot;AWS:SourceArn&quot;:&quot;arn:aws:*:*:365155214602:*&quot;}}}]}</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
- describe 'when creating a topic' do
510
+
21
511
  end
22
512
 
23
513
  end