fake_sns 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 +18 -0
- data/.rspec +2 -0
- data/.simplecov +4 -0
- data/.travis.yml +5 -0
- data/Gemfile +2 -0
- data/README.md +167 -0
- data/Rakefile +24 -0
- data/bin/fake_sns +79 -0
- data/config.ru +3 -0
- data/fake_sns.gemspec +34 -0
- data/lib/fake_sns/action.rb +24 -0
- data/lib/fake_sns/actions/create_topic.rb +41 -0
- data/lib/fake_sns/actions/delete_topic.rb +13 -0
- data/lib/fake_sns/actions/get_topic_attributes.rb +32 -0
- data/lib/fake_sns/actions/list_subscriptions.rb +24 -0
- data/lib/fake_sns/actions/list_subscriptions_by_topic.rb +23 -0
- data/lib/fake_sns/actions/list_topics.rb +13 -0
- data/lib/fake_sns/actions/publish.rb +37 -0
- data/lib/fake_sns/actions/set_topic_attributes.rb +19 -0
- data/lib/fake_sns/actions/subscribe.rb +43 -0
- data/lib/fake_sns/database.rb +76 -0
- data/lib/fake_sns/deliver_message.rb +100 -0
- data/lib/fake_sns/error.rb +34 -0
- data/lib/fake_sns/error_response.rb +46 -0
- data/lib/fake_sns/message.rb +28 -0
- data/lib/fake_sns/message_collection.rb +40 -0
- data/lib/fake_sns/response.rb +16 -0
- data/lib/fake_sns/server.rb +76 -0
- data/lib/fake_sns/show_output.rb +20 -0
- data/lib/fake_sns/storage.rb +75 -0
- data/lib/fake_sns/subscription.rb +17 -0
- data/lib/fake_sns/subscription_collection.rb +34 -0
- data/lib/fake_sns/test_integration.rb +110 -0
- data/lib/fake_sns/topic.rb +13 -0
- data/lib/fake_sns/topic_collection.rb +41 -0
- data/lib/fake_sns/version.rb +3 -0
- data/lib/fake_sns/views/create_topic.xml.erb +8 -0
- data/lib/fake_sns/views/delete_topic.xml.erb +5 -0
- data/lib/fake_sns/views/error.xml.erb +8 -0
- data/lib/fake_sns/views/get_topic_attributes.xml.erb +15 -0
- data/lib/fake_sns/views/list_subscriptions.xml.erb +18 -0
- data/lib/fake_sns/views/list_subscriptions_by_topic.xml.erb +18 -0
- data/lib/fake_sns/views/list_topics.xml.erb +14 -0
- data/lib/fake_sns/views/publish.xml.erb +8 -0
- data/lib/fake_sns/views/set_topic_attributes.xml.erb +5 -0
- data/lib/fake_sns/views/subscribe.xml.erb +8 -0
- data/lib/fake_sns.rb +51 -0
- data/spec/fake_sns/drain_spec.rb +91 -0
- data/spec/fake_sns/publish_spec.rb +28 -0
- data/spec/fake_sns/replace_spec.rb +14 -0
- data/spec/fake_sns/subscribing_spec.rb +42 -0
- data/spec/fake_sns/topics_spec.rb +44 -0
- data/spec/spec_helper.rb +54 -0
- metadata +271 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: eea380f4afe8a28a3fe8ef442ee68bc36ed44fc7
|
4
|
+
data.tar.gz: 27394ec000f0bb22a985f37e38058c9c32057b33
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 4a4c3f9cb1e0e99c47fc939ba45bf15ce944ab3bdc9ac70f3086daccfd1e0ba5c8b1e7a3ceed9a360653d3ae614ac5bf3f83bf8e519f373f3ec5e5c688ce0271
|
7
|
+
data.tar.gz: 65744967afec469a3224a608dd141d5c2549f482e28c1d42f2980388cccfe3e1d37d3ee6714d4ae497c2f337c534780a0bc4621d42cbf182c4cb7eaa7c9a827c
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.simplecov
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,167 @@
|
|
1
|
+
# Fake SNS
|
2
|
+
|
3
|
+
A small web app for local SNS development.
|
4
|
+
|
5
|
+
It contains a small store to inspect, and some methods to inspect and change the
|
6
|
+
contents, so you can create scenarios.
|
7
|
+
|
8
|
+
### Noteworthy differences:
|
9
|
+
|
10
|
+
* No checking of access keys.
|
11
|
+
* Returns all topics, not just 100, no support for `NextToken` parameter.
|
12
|
+
|
13
|
+
### Implemented:
|
14
|
+
|
15
|
+
* CreateTopic
|
16
|
+
* ListTopics
|
17
|
+
* DeleteTopic
|
18
|
+
* GetTopicAttributes
|
19
|
+
* SetTopicAttributes
|
20
|
+
* ListSubscriptions
|
21
|
+
* ListSubscriptionsByTopic
|
22
|
+
|
23
|
+
### Under Construction
|
24
|
+
|
25
|
+
* Subscribe
|
26
|
+
* Publish
|
27
|
+
|
28
|
+
### Actions to be implemented:
|
29
|
+
|
30
|
+
* AddPermission
|
31
|
+
* ConfirmSubscription
|
32
|
+
* CreatePlatformApplication
|
33
|
+
* CreatePlatformEndpoint
|
34
|
+
* DeleteEndpoint
|
35
|
+
* DeletePlatformApplication
|
36
|
+
* GetEndpointAttributes
|
37
|
+
* GetPlatformApplicationAttributes
|
38
|
+
* GetSubscriptionAttributes
|
39
|
+
* ListEndpointsByPlatformApplication
|
40
|
+
* ListPlatformApplications
|
41
|
+
* RemovePermission
|
42
|
+
* SetEndpointAttributes
|
43
|
+
* SetPlatformApplicationAttributes
|
44
|
+
* SetSubscriptionAttributes
|
45
|
+
* Unsubscribe
|
46
|
+
|
47
|
+
## Usage
|
48
|
+
|
49
|
+
There are 2 ways of running FakeSNS, as a gem, or as plain Rack app. The first
|
50
|
+
is easy, the latter is more flexible.
|
51
|
+
|
52
|
+
As a gem:
|
53
|
+
|
54
|
+
```
|
55
|
+
$ gem install fake_sns
|
56
|
+
$ fake_sns -p 9292
|
57
|
+
```
|
58
|
+
|
59
|
+
To configure AWS-SDK to send messages here:
|
60
|
+
|
61
|
+
``` ruby
|
62
|
+
AWS.config(
|
63
|
+
use_ssl: false,
|
64
|
+
sns_endpoint: "0.0.0.0",
|
65
|
+
sns_port: 9292,
|
66
|
+
)
|
67
|
+
```
|
68
|
+
|
69
|
+
### Command line options
|
70
|
+
|
71
|
+
Get help by running `fake_sns --help`. These options are basically the same as
|
72
|
+
Sinatra's options. Here are the SNS specific options:
|
73
|
+
|
74
|
+
* Store the database somewhere else: `--database FILENAME` or
|
75
|
+
specify an in memory database that will be lost: `--database :memory:`
|
76
|
+
|
77
|
+
### Extra endpoints
|
78
|
+
|
79
|
+
To get a YAML representation of all the data known to FakeSNS, do a GET request
|
80
|
+
to the root path:
|
81
|
+
|
82
|
+
```
|
83
|
+
curl -X GET http://localhost:9292/
|
84
|
+
```
|
85
|
+
|
86
|
+
To change the database, submit the contents you got from the previous step,
|
87
|
+
augment it and submit it as the body of a PUT request:
|
88
|
+
|
89
|
+
```
|
90
|
+
curl -X GET http://localhost:9292/ -o my-data.yml
|
91
|
+
vim my-data.yml
|
92
|
+
curl -X PUT --data @my-data.yml http://localhost:9292/
|
93
|
+
```
|
94
|
+
|
95
|
+
To reset the entire database, send a DELETE request:
|
96
|
+
|
97
|
+
```
|
98
|
+
curl -X DELETE http://localhost:9292/
|
99
|
+
```
|
100
|
+
|
101
|
+
To send ALL the messages stored in the queue, you can send a post request:
|
102
|
+
|
103
|
+
```
|
104
|
+
curl -X POST http://localhost:9292/drain
|
105
|
+
```
|
106
|
+
|
107
|
+
You can also just send a single message:
|
108
|
+
|
109
|
+
```
|
110
|
+
curl -X POST http://localhost:9292/drain/:message_id
|
111
|
+
```
|
112
|
+
|
113
|
+
Currently, only HTTP/HTTPS and SQS endpoints are working. You'll need
|
114
|
+
to pass AWS config (in JSON format) for the SQS integration to work. See
|
115
|
+
[FakeSNS] [fake_sns] for more information.
|
116
|
+
|
117
|
+
```
|
118
|
+
curl \
|
119
|
+
-X POST \
|
120
|
+
--data '{"aws_config": {"use_ssl": false, "sqs_endpoint": "localhost", "sqs_port": 4789, "secret_access_key": "xxx", "access_key_id": "yyy"}}' \
|
121
|
+
http://localhost:9292/drain
|
122
|
+
```
|
123
|
+
|
124
|
+
### Test Integration
|
125
|
+
|
126
|
+
When making integration tests for your app, you can easily include Fake SNS.
|
127
|
+
|
128
|
+
Here are the methods you need to run FakeSNS programmatically.
|
129
|
+
|
130
|
+
``` ruby
|
131
|
+
require "fake_sns/test_integration"
|
132
|
+
|
133
|
+
# globally, before the test suite starts:
|
134
|
+
AWS.config(
|
135
|
+
use_ssl: false,
|
136
|
+
sns_endpoint: "localhost",
|
137
|
+
sns_port: 4568,
|
138
|
+
access_key_id: "fake access key",
|
139
|
+
secret_access_key: "fake secret key",
|
140
|
+
)
|
141
|
+
fake_sns = FakeSNS::TestIntegration.new
|
142
|
+
|
143
|
+
# before each test that requires SNS:
|
144
|
+
fake_sns.start
|
145
|
+
|
146
|
+
# at the end of the suite:
|
147
|
+
at_exit {
|
148
|
+
fake_sns.stop
|
149
|
+
}
|
150
|
+
|
151
|
+
# for debugging, get everything FakeSNS knows:
|
152
|
+
puts fake_sns.data.inspect
|
153
|
+
|
154
|
+
# if you have SQS configured in the AWS config, you can also do:
|
155
|
+
fake_sns.drain
|
156
|
+
```
|
157
|
+
|
158
|
+
See `spec/spec_helper.rb` in this project for an example on how to load it in
|
159
|
+
your test suite.
|
160
|
+
|
161
|
+
## More information
|
162
|
+
|
163
|
+
* [API Reference](http://docs.aws.amazon.com/sns/latest/api/API_Operations.html)
|
164
|
+
* [AWS-SDK docs](http://rubydoc.info/gems/aws-sdk/frames)
|
165
|
+
* [Fake SQS] [fake_sqs]
|
166
|
+
|
167
|
+
[fake_sqs]: https://github.com/iain/fake_sqs
|
data/Rakefile
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
|
3
|
+
require "tempfile"
|
4
|
+
require "rspec/core/rake_task"
|
5
|
+
|
6
|
+
namespace :spec do
|
7
|
+
|
8
|
+
desc "Run specs with in-memory database"
|
9
|
+
RSpec::Core::RakeTask.new(:memory) do |t|
|
10
|
+
ENV["SNS_DATABASE"] = ":memory:"
|
11
|
+
end
|
12
|
+
|
13
|
+
desc "Run specs with file database"
|
14
|
+
RSpec::Core::RakeTask.new(:file) do |t|
|
15
|
+
file = Tempfile.new(["rspec-sns", ".yml"], encoding: "utf-8")
|
16
|
+
ENV["SNS_DATABASE"] = file.path
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
desc "Run spec suite with both in-memory and file"
|
22
|
+
task :spec => ["spec:memory", "spec:file"]
|
23
|
+
|
24
|
+
task :default => :spec
|
data/bin/fake_sns
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
lib = File.expand_path("../../lib", __FILE__)
|
4
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
+
|
6
|
+
require 'fake_sns'
|
7
|
+
require 'optparse'
|
8
|
+
|
9
|
+
options = {
|
10
|
+
:port => 9292,
|
11
|
+
:host => "0.0.0.0",
|
12
|
+
:verbose => false,
|
13
|
+
:daemonize => false,
|
14
|
+
:database => nil,
|
15
|
+
}
|
16
|
+
|
17
|
+
parser = OptionParser.new do |o|
|
18
|
+
|
19
|
+
o.on "--database FILENAME", "Place to store the database (defaults to ~/.fake_sns.yml)" do |filename|
|
20
|
+
options[:database] = filename
|
21
|
+
end
|
22
|
+
|
23
|
+
o.on "-p", "--port PORT", Integer, "Port to use (default: #{options[:port]})" do |port|
|
24
|
+
options[:port] = port
|
25
|
+
end
|
26
|
+
|
27
|
+
o.on "-o", "--bind HOST", "Host to bind to (default: 0.0.0.0)" do |host|
|
28
|
+
options[:host] = host
|
29
|
+
end
|
30
|
+
|
31
|
+
o.on "-s", "--server SERVER", ['thin', 'mongrel', 'webrick'], "Server to use: thin, mongrel or webrick (by default Sinatra chooses the best available)" do |server|
|
32
|
+
options[:server] = server
|
33
|
+
end
|
34
|
+
|
35
|
+
o.on "-P", "--pid PIDFILE", "Where to write the pid" do |pid|
|
36
|
+
options[:pid] = pid
|
37
|
+
end
|
38
|
+
|
39
|
+
o.on "-d", "--[no-]daemonize", "Detaches the process" do |daemonize|
|
40
|
+
options[:daemonize] = daemonize
|
41
|
+
end
|
42
|
+
|
43
|
+
o.on "-v", "--[no]-verbose", "Shows input parameters and output XML" do |verbose|
|
44
|
+
options[:verbose] = verbose
|
45
|
+
end
|
46
|
+
|
47
|
+
o.on_tail "--version", "Shows the version" do
|
48
|
+
puts "fake_sns version #{FakeSNS::VERSION}"
|
49
|
+
exit
|
50
|
+
end
|
51
|
+
|
52
|
+
o.on_tail "-h", "--help", "Shows this help page" do
|
53
|
+
puts o
|
54
|
+
exit
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
parser.parse!
|
60
|
+
|
61
|
+
if options[:daemonize]
|
62
|
+
Process.daemon(true, true)
|
63
|
+
end
|
64
|
+
|
65
|
+
if (pid = options[:pid])
|
66
|
+
if File.exist?(pid)
|
67
|
+
existing_pid = File.open(pid, 'r').read.chomp.to_i
|
68
|
+
running = Process.getpgid(existing_pid) rescue false
|
69
|
+
if running
|
70
|
+
warn "Error, Process #{existing_pid} already running"
|
71
|
+
exit 1
|
72
|
+
else
|
73
|
+
warn "Cleaning up stale pid at #{pid}"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
File.open(pid, 'w') { |f| f.write(Process.pid) }
|
77
|
+
end
|
78
|
+
|
79
|
+
FakeSNS.server(options).run!
|
data/config.ru
ADDED
data/fake_sns.gemspec
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'fake_sns/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "fake_sns"
|
8
|
+
spec.version = FakeSNS::VERSION
|
9
|
+
spec.authors = ["iain"]
|
10
|
+
spec.email = ["iain@iain.nl"]
|
11
|
+
spec.description = %q{Small Fake version of SNS}
|
12
|
+
spec.summary = %q{Small Fake version of SNS}
|
13
|
+
spec.homepage = "https://github.com/yourkarma/fake_sns"
|
14
|
+
|
15
|
+
spec.files = `git ls-files`.split($/)
|
16
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
17
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
18
|
+
spec.require_paths = ["lib"]
|
19
|
+
|
20
|
+
spec.add_dependency "sinatra", "~> 1.4"
|
21
|
+
spec.add_dependency "virtus", "~> 1.0"
|
22
|
+
spec.add_dependency "verbose_hash_fetch"
|
23
|
+
spec.add_dependency "faraday", "~> 0.8"
|
24
|
+
spec.add_dependency "aws-sdk", "~> 1.30"
|
25
|
+
|
26
|
+
spec.add_development_dependency "aws-sdk"
|
27
|
+
spec.add_development_dependency "bundler"
|
28
|
+
spec.add_development_dependency "rake"
|
29
|
+
spec.add_development_dependency "rspec"
|
30
|
+
spec.add_development_dependency "pry"
|
31
|
+
spec.add_development_dependency "fake_sqs", "~> 0.0.9"
|
32
|
+
spec.add_development_dependency "json_expressions"
|
33
|
+
|
34
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module FakeSNS
|
2
|
+
class Action
|
3
|
+
|
4
|
+
attr_reader :db, :params
|
5
|
+
|
6
|
+
def self.param(fields, &block)
|
7
|
+
fields.each do |field, key|
|
8
|
+
define_method field do
|
9
|
+
params.fetch(key, &block)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize(db, params)
|
15
|
+
@db = db
|
16
|
+
@params = params
|
17
|
+
end
|
18
|
+
|
19
|
+
def call
|
20
|
+
# override me, if needed
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module FakeSNS
|
2
|
+
module Actions
|
3
|
+
class CreateTopic < Action
|
4
|
+
|
5
|
+
param name: "Name"
|
6
|
+
|
7
|
+
def valid_name?
|
8
|
+
name =~ /\A[\w\-]+\z/
|
9
|
+
end
|
10
|
+
|
11
|
+
def call
|
12
|
+
raise InvalidParameterValue, "Topic Name: #{name.inspect}" unless valid_name?
|
13
|
+
@topic = (existing_topic || new_topic)
|
14
|
+
end
|
15
|
+
|
16
|
+
def arn
|
17
|
+
topic["arn"]
|
18
|
+
end
|
19
|
+
|
20
|
+
attr_reader :topic
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def new_topic
|
25
|
+
arn = generate_arn
|
26
|
+
topic_attributes = { "arn" => arn, "name" => name }
|
27
|
+
db.topics.create(topic_attributes)
|
28
|
+
topic_attributes
|
29
|
+
end
|
30
|
+
|
31
|
+
def generate_arn
|
32
|
+
"arn:aws:sns:us-east-1:#{SecureRandom.hex}:#{name}"
|
33
|
+
end
|
34
|
+
|
35
|
+
def existing_topic
|
36
|
+
db.topics.find { |t| t["name"] == name }
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module FakeSNS
|
2
|
+
module Actions
|
3
|
+
class GetTopicAttributes < Action
|
4
|
+
|
5
|
+
param arn: "TopicArn"
|
6
|
+
|
7
|
+
# TopicArn
|
8
|
+
# Owner
|
9
|
+
# Policy
|
10
|
+
# DisplayName
|
11
|
+
# SubscriptionsPending
|
12
|
+
# SubscriptionsConfirmed
|
13
|
+
# SubscriptionsDeleted
|
14
|
+
# DeliveryPolicy
|
15
|
+
# EffectiveDeliveryPolicy
|
16
|
+
|
17
|
+
attr_reader :topic
|
18
|
+
|
19
|
+
def call
|
20
|
+
@topic = db.topics.fetch(arn) { raise NotFound, arn }
|
21
|
+
end
|
22
|
+
|
23
|
+
def each_attribute
|
24
|
+
yield "TopicArn", arn
|
25
|
+
%w(DisplayName Policy DeliveryPolicy).each do |key|
|
26
|
+
yield key, topic[key] if topic.has_key?(key)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module FakeSNS
|
2
|
+
module Actions
|
3
|
+
class ListSubscriptions < Action
|
4
|
+
|
5
|
+
param next_token: "NextToken"
|
6
|
+
|
7
|
+
def call
|
8
|
+
end
|
9
|
+
|
10
|
+
def each_subscription
|
11
|
+
subscriptions.each do |subscription|
|
12
|
+
yield subscription
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def subscriptions
|
19
|
+
db.subscriptions
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module FakeSNS
|
2
|
+
module Actions
|
3
|
+
class ListSubscriptionsByTopic < ListSubscriptions
|
4
|
+
|
5
|
+
param topic_arn: "TopicArn"
|
6
|
+
param next_token: "NextToken"
|
7
|
+
|
8
|
+
def call
|
9
|
+
super
|
10
|
+
@topic = db.topics.fetch(topic_arn) do
|
11
|
+
raise InvalidParameterValue, "Unknown topic: #{topic_arn}"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def subscriptions
|
18
|
+
super.select { |s| s["topic_arn"] == topic_arn }
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module FakeSNS
|
2
|
+
module Actions
|
3
|
+
class Publish < Action
|
4
|
+
|
5
|
+
param message: "Message"
|
6
|
+
param message_structure: "MessageStructure"
|
7
|
+
param subject: "Subject" do nil end
|
8
|
+
param target_arn: "TargetArn" do nil end
|
9
|
+
param topic_arn: "TopicArn" do nil end
|
10
|
+
|
11
|
+
def call
|
12
|
+
if (bytes = message.bytesize) > 262144
|
13
|
+
raise InvalidParameterValue, "Too much bytes: #{bytes} > 262144."
|
14
|
+
end
|
15
|
+
@topic = db.topics.fetch(topic_arn) do
|
16
|
+
raise InvalidParameterValue, "Unknown topic: #{topic_arn}"
|
17
|
+
end
|
18
|
+
@message_id = SecureRandom.uuid
|
19
|
+
|
20
|
+
db.messages.create(
|
21
|
+
id: message_id,
|
22
|
+
subject: subject,
|
23
|
+
message: message,
|
24
|
+
topic_arn: topic_arn,
|
25
|
+
structure: message_structure,
|
26
|
+
target_arn: target_arn,
|
27
|
+
received_at: Time.now,
|
28
|
+
)
|
29
|
+
end
|
30
|
+
|
31
|
+
def message_id
|
32
|
+
@message_id || raise(InternalFailure, "no message id yet, this should not happen")
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module FakeSNS
|
2
|
+
module Actions
|
3
|
+
class SetTopicAttributes < Action
|
4
|
+
|
5
|
+
VALID_PARAMETER_NAMES = %w(Policy DisplayName DeliveryPolicy)
|
6
|
+
|
7
|
+
param key: "AttributeName"
|
8
|
+
param value: "AttributeValue"
|
9
|
+
param arn: "TopicArn"
|
10
|
+
|
11
|
+
def call
|
12
|
+
raise InvalidParameterValue, "AttributeName: #{key.inspect}" unless VALID_PARAMETER_NAMES.include?(key)
|
13
|
+
topic = db.topics.fetch(arn) { raise NotFound, arn }
|
14
|
+
topic[key] = value
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module FakeSNS
|
2
|
+
module Actions
|
3
|
+
class Subscribe < Action
|
4
|
+
|
5
|
+
param endpoint: "Endpoint"
|
6
|
+
param protocol: "Protocol"
|
7
|
+
param topic_arn: "TopicArn"
|
8
|
+
|
9
|
+
attr_reader :topic
|
10
|
+
|
11
|
+
def call
|
12
|
+
@topic = db.topics.fetch(topic_arn) do
|
13
|
+
raise InvalidParameterValue, "Unknown topic: #{topic_arn}"
|
14
|
+
end
|
15
|
+
@subscription = (existing_subscription || new_subscription)
|
16
|
+
end
|
17
|
+
|
18
|
+
def subscription_arn
|
19
|
+
@subscription["arn"]
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def existing_subscription
|
25
|
+
db.subscriptions.to_a.find { |s|
|
26
|
+
s.topic_arn == topic_arn && s.endpoint == endpoint
|
27
|
+
}
|
28
|
+
end
|
29
|
+
|
30
|
+
def new_subscription
|
31
|
+
attributes = {
|
32
|
+
"arn" => "#{topic_arn}:#{SecureRandom.uuid}",
|
33
|
+
"protocol" => protocol,
|
34
|
+
"endpoint" => endpoint,
|
35
|
+
"topic_arn" => topic_arn,
|
36
|
+
}
|
37
|
+
db.subscriptions.create(attributes)
|
38
|
+
attributes
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|