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
@@ -0,0 +1,76 @@
|
|
1
|
+
require "etc"
|
2
|
+
require "aws-sdk"
|
3
|
+
|
4
|
+
module FakeSNS
|
5
|
+
class Database
|
6
|
+
|
7
|
+
attr_reader :database_filename
|
8
|
+
|
9
|
+
def initialize(database_filename)
|
10
|
+
@database_filename = database_filename || File.join(Dir.home, ".fake_sns.yml")
|
11
|
+
end
|
12
|
+
|
13
|
+
def perform(action, params)
|
14
|
+
action_instance = action_provider(action).new(self, params)
|
15
|
+
action_instance.call
|
16
|
+
Response.new(action_instance)
|
17
|
+
end
|
18
|
+
|
19
|
+
def topics
|
20
|
+
@topics ||= TopicCollection.new(store)
|
21
|
+
end
|
22
|
+
|
23
|
+
def subscriptions
|
24
|
+
@subscriptions ||= SubscriptionCollection.new(store)
|
25
|
+
end
|
26
|
+
|
27
|
+
def messages
|
28
|
+
@messages ||= MessageCollection.new(store)
|
29
|
+
end
|
30
|
+
|
31
|
+
def reset
|
32
|
+
topics.reset
|
33
|
+
subscriptions.reset
|
34
|
+
messages.reset
|
35
|
+
end
|
36
|
+
|
37
|
+
def transaction
|
38
|
+
store.transaction do
|
39
|
+
yield
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def replace(data)
|
44
|
+
store.replace(data)
|
45
|
+
end
|
46
|
+
|
47
|
+
def to_yaml
|
48
|
+
store.to_yaml
|
49
|
+
end
|
50
|
+
|
51
|
+
def each_deliverable_message
|
52
|
+
topics.each do |topic|
|
53
|
+
subscriptions.each do |subscription|
|
54
|
+
messages.each do |message|
|
55
|
+
if message.topic_arn == topic.arn
|
56
|
+
yield subscription, message
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def store
|
66
|
+
@store ||= Storage.for(database_filename)
|
67
|
+
end
|
68
|
+
|
69
|
+
def action_provider(action)
|
70
|
+
Actions.const_get(action)
|
71
|
+
rescue NameError
|
72
|
+
raise InvalidAction, "not implemented: #{action}"
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
require "forwardable"
|
2
|
+
require "faraday"
|
3
|
+
|
4
|
+
module FakeSNS
|
5
|
+
class DeliverMessage
|
6
|
+
|
7
|
+
extend Forwardable
|
8
|
+
|
9
|
+
def self.call(options)
|
10
|
+
new(options).call
|
11
|
+
end
|
12
|
+
|
13
|
+
attr_reader :subscription, :message, :config, :request
|
14
|
+
|
15
|
+
def_delegators :subscription, :protocol, :endpoint, :arn
|
16
|
+
|
17
|
+
def initialize(options)
|
18
|
+
@subscription = options.fetch(:subscription)
|
19
|
+
@message = options.fetch(:message)
|
20
|
+
@request = options.fetch(:request)
|
21
|
+
@config = options.fetch(:config)
|
22
|
+
end
|
23
|
+
|
24
|
+
def call
|
25
|
+
method_name = protocol.gsub("-", "_")
|
26
|
+
if protected_methods.map(&:to_s).include?(method_name)
|
27
|
+
send(method_name)
|
28
|
+
else
|
29
|
+
raise InvalidParameterValue, "Protocol #{protocol} not supported"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
protected
|
34
|
+
|
35
|
+
def sqs
|
36
|
+
queue_name = endpoint.split(":").last
|
37
|
+
sqs = AWS::SQS.new(config["aws_config"] || {})
|
38
|
+
queue = sqs.queues.named(queue_name)
|
39
|
+
queue.send_message(message_contents)
|
40
|
+
end
|
41
|
+
|
42
|
+
def http
|
43
|
+
http_or_https
|
44
|
+
end
|
45
|
+
|
46
|
+
def https
|
47
|
+
http_or_https
|
48
|
+
end
|
49
|
+
|
50
|
+
def email
|
51
|
+
pending
|
52
|
+
end
|
53
|
+
|
54
|
+
def email_json
|
55
|
+
pending
|
56
|
+
end
|
57
|
+
|
58
|
+
def sms
|
59
|
+
pending
|
60
|
+
end
|
61
|
+
|
62
|
+
def application
|
63
|
+
pending
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
def message_contents
|
69
|
+
message.message_for_protocol protocol
|
70
|
+
end
|
71
|
+
|
72
|
+
def pending
|
73
|
+
puts "Not sending to subscription #{arn}, because protocol #{protocol} has no fake implementation. Message: #{message.id} - #{message_contents.inspect}"
|
74
|
+
end
|
75
|
+
|
76
|
+
def http_or_https
|
77
|
+
Faraday.new.post(endpoint) do |f|
|
78
|
+
f.body = {
|
79
|
+
"Type" => "Notification",
|
80
|
+
"MessageId" => message.id,
|
81
|
+
"TopicArn" => message.topic_arn,
|
82
|
+
"Subject" => message.subject,
|
83
|
+
"Message" => message_contents,
|
84
|
+
"Timestamp" => message.received_at.strftime("%Y-%m-%dT%H:%M:%SZ"),
|
85
|
+
"SignatureVersion" => "1",
|
86
|
+
"Signature" => "Fake",
|
87
|
+
"SigningCertURL" => "https://sns.us-east-1.amazonaws.com/SimpleNotificationService-f3ecfb7224c7233fe7bb5f59f96de52f.pem",
|
88
|
+
"UnsubscribeURL" => "", # TODO url to unsubscribe URL on this server
|
89
|
+
}.to_json
|
90
|
+
f.headers = {
|
91
|
+
"x-amz-sns-message-type" => "Notification",
|
92
|
+
"x-amz-sns-message-id" => message.id,
|
93
|
+
"x-amz-sns-topic-arn" => message.topic_arn,
|
94
|
+
"x-amz-sns-subscription-arn" => arn,
|
95
|
+
}
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module FakeSNS
|
2
|
+
|
3
|
+
class Error < StandardError
|
4
|
+
end
|
5
|
+
|
6
|
+
def self.error_type(status)
|
7
|
+
Class.new(Error) do
|
8
|
+
define_method :status do
|
9
|
+
status
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
# Common Errors, according to AWS docs
|
15
|
+
IncompleteSignature = error_type 400
|
16
|
+
InternalFailure = error_type 500
|
17
|
+
InvalidAction = error_type 400
|
18
|
+
InvalidClientTokenId = error_type 403
|
19
|
+
InvalidParameterCombination = error_type 400
|
20
|
+
InvalidParameterValue = error_type 400
|
21
|
+
InvalidQueryParameter = error_type 400
|
22
|
+
MalformedQueryString = error_type 400
|
23
|
+
MissingAction = error_type 400
|
24
|
+
MissingAuthenticationToken = error_type 403
|
25
|
+
MissingParameter = error_type 400
|
26
|
+
OptInRequired = error_type 403
|
27
|
+
RequestExpired = error_type 400
|
28
|
+
ServiceUnavailable = error_type 403
|
29
|
+
Throttling = error_type 400
|
30
|
+
|
31
|
+
# Other errors
|
32
|
+
NotFound = error_type 404
|
33
|
+
|
34
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module FakeSNS
|
2
|
+
class ErrorResponse
|
3
|
+
|
4
|
+
DEFAULT_CODE = "InternalFailure"
|
5
|
+
DEFAULT_STATUS = 500
|
6
|
+
|
7
|
+
attr_reader :error, :parameters
|
8
|
+
|
9
|
+
def initialize(error, parameters)
|
10
|
+
@error = error
|
11
|
+
@parameters = parameters
|
12
|
+
end
|
13
|
+
|
14
|
+
def status
|
15
|
+
if error.respond_to?(:status)
|
16
|
+
error.status
|
17
|
+
else
|
18
|
+
DEFAULT_STATUS
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# TODO figure out what this value does
|
23
|
+
def type
|
24
|
+
"Sender"
|
25
|
+
end
|
26
|
+
|
27
|
+
def code
|
28
|
+
if error.respond_to?(:code)
|
29
|
+
error.code
|
30
|
+
elsif error.is_a?(FakeSNS::Error)
|
31
|
+
error.class.to_s.split("::").last
|
32
|
+
else
|
33
|
+
DEFAULT_CODE
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def message
|
38
|
+
error.message
|
39
|
+
end
|
40
|
+
|
41
|
+
def request_id
|
42
|
+
@request_id ||= SecureRandom.uuid
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require "json"
|
2
|
+
|
3
|
+
module FakeSNS
|
4
|
+
class Message
|
5
|
+
|
6
|
+
include Virtus.model
|
7
|
+
|
8
|
+
json = Class.new(Virtus::Attribute) do
|
9
|
+
def coerce(value)
|
10
|
+
value.is_a?(::Hash) ? value : JSON.parse(value)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
attribute :id, String
|
15
|
+
attribute :subject, String
|
16
|
+
attribute :endpoint, String
|
17
|
+
attribute :topic_arn, String
|
18
|
+
attribute :structure, String
|
19
|
+
attribute :target_arn, String
|
20
|
+
attribute :received_at, DateTime
|
21
|
+
attribute :message, json
|
22
|
+
|
23
|
+
def message_for_protocol(type)
|
24
|
+
message.fetch(type.to_s) { message.fetch("default") }
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module FakeSNS
|
2
|
+
class MessageCollection
|
3
|
+
|
4
|
+
include Enumerable
|
5
|
+
|
6
|
+
def initialize(store)
|
7
|
+
@store = store
|
8
|
+
@store["messages"] ||= []
|
9
|
+
end
|
10
|
+
|
11
|
+
def collection
|
12
|
+
@store["messages"]
|
13
|
+
end
|
14
|
+
|
15
|
+
def reset
|
16
|
+
@store["messages"] = []
|
17
|
+
end
|
18
|
+
|
19
|
+
def each(*args, &block)
|
20
|
+
collection.map { |item| Message.new(item) }.each(*args, &block)
|
21
|
+
end
|
22
|
+
|
23
|
+
def fetch(arn, &default)
|
24
|
+
default ||= -> { raise InvalidParameterValue, "Unknown message #{arn}" }
|
25
|
+
found = collection.find do |message|
|
26
|
+
message["arn"] == arn
|
27
|
+
end
|
28
|
+
found || default.call
|
29
|
+
end
|
30
|
+
|
31
|
+
def create(attributes)
|
32
|
+
collection << attributes
|
33
|
+
end
|
34
|
+
|
35
|
+
def delete(arn)
|
36
|
+
collection.delete(fetch(arn))
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require "securerandom"
|
2
|
+
require "delegate"
|
3
|
+
|
4
|
+
module FakeSNS
|
5
|
+
class Response < SimpleDelegator
|
6
|
+
|
7
|
+
def request_id
|
8
|
+
@request_id ||= SecureRandom.uuid
|
9
|
+
end
|
10
|
+
|
11
|
+
def template
|
12
|
+
__getobj__.class.name.to_s.split("::").last.gsub(/[A-Z]/){|m| "_#{m[0].downcase}"}.sub(/_/, '')
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require "fake_sns"
|
2
|
+
require "sinatra/base"
|
3
|
+
|
4
|
+
module FakeSNS
|
5
|
+
class Server < Sinatra::Base
|
6
|
+
|
7
|
+
before do
|
8
|
+
content_type :xml
|
9
|
+
end
|
10
|
+
|
11
|
+
def database
|
12
|
+
$database ||= FakeSNS::Database.new(settings.database)
|
13
|
+
end
|
14
|
+
|
15
|
+
def action
|
16
|
+
params.fetch("Action") { raise MissingAction }
|
17
|
+
end
|
18
|
+
|
19
|
+
get "/" do
|
20
|
+
database.transaction do
|
21
|
+
database.to_yaml
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
post "/" do
|
26
|
+
database.transaction do
|
27
|
+
begin
|
28
|
+
response = database.perform(action, params)
|
29
|
+
status 200
|
30
|
+
erb :"#{response.template}.xml", scope: response
|
31
|
+
rescue Exception => error
|
32
|
+
p error
|
33
|
+
puts(*error.backtrace)
|
34
|
+
error_response = ErrorResponse.new(error, params)
|
35
|
+
status error_response.status
|
36
|
+
erb :"error.xml", scope: error_response
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
delete "/" do
|
42
|
+
database.transaction do
|
43
|
+
database.reset
|
44
|
+
200
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
put "/" do
|
49
|
+
database.replace(request.body.read)
|
50
|
+
200
|
51
|
+
end
|
52
|
+
|
53
|
+
post "/drain" do
|
54
|
+
database.transaction do
|
55
|
+
config = JSON.parse(request.body.read)
|
56
|
+
database.each_deliverable_message do |subscription, message|
|
57
|
+
DeliverMessage.call(subscription: subscription, message: message, request: request, config: config)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
200
|
61
|
+
end
|
62
|
+
|
63
|
+
post "/drain/:message_id" do |message_id|
|
64
|
+
config = JSON.parse(request.body.read)
|
65
|
+
database.transaction do
|
66
|
+
database.each_deliverable_message do |subscription, message|
|
67
|
+
if message.id == message_id
|
68
|
+
DeliverMessage.call(subscription: subscription, message: message, request: request, config: config)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
200
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'rack/request'
|
2
|
+
|
3
|
+
module FakeSNS
|
4
|
+
class ShowOutput
|
5
|
+
|
6
|
+
def initialize(app)
|
7
|
+
@app = app
|
8
|
+
end
|
9
|
+
|
10
|
+
def call(env)
|
11
|
+
request = Rack::Request.new(env)
|
12
|
+
puts request.params.to_yaml
|
13
|
+
result = @app.call(env)
|
14
|
+
puts
|
15
|
+
puts(*result.last)
|
16
|
+
result
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require "yaml/store"
|
2
|
+
|
3
|
+
module FakeSNS
|
4
|
+
|
5
|
+
class Storage
|
6
|
+
|
7
|
+
def self.for(database_filename)
|
8
|
+
if database_filename == ":memory:"
|
9
|
+
MemoryStorage.new(database_filename)
|
10
|
+
else
|
11
|
+
FileStorage.new(database_filename)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(database_filename)
|
16
|
+
@database_filename = database_filename
|
17
|
+
end
|
18
|
+
|
19
|
+
def [](key)
|
20
|
+
storage[key]
|
21
|
+
end
|
22
|
+
|
23
|
+
def []=(key, value)
|
24
|
+
storage[key] = value
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
class MemoryStorage < Storage
|
30
|
+
|
31
|
+
def to_yaml
|
32
|
+
storage.to_yaml
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
def storage
|
37
|
+
@storage ||= {}
|
38
|
+
end
|
39
|
+
|
40
|
+
def transaction
|
41
|
+
yield
|
42
|
+
end
|
43
|
+
|
44
|
+
def replace(data)
|
45
|
+
@storage = YAML.load(data)
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
class FileStorage < Storage
|
51
|
+
|
52
|
+
def to_yaml
|
53
|
+
storage["x"]
|
54
|
+
storage.instance_variable_get(:@table).to_yaml
|
55
|
+
end
|
56
|
+
|
57
|
+
def storage
|
58
|
+
@storage ||= YAML::Store.new(@database_filename)
|
59
|
+
end
|
60
|
+
|
61
|
+
def transaction
|
62
|
+
storage.transaction do
|
63
|
+
yield
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def replace(data)
|
68
|
+
File.open(@database_filename, "w:utf-8") do |f|
|
69
|
+
f.write(data)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module FakeSNS
|
2
|
+
class Subscription
|
3
|
+
|
4
|
+
include Virtus.model
|
5
|
+
|
6
|
+
attribute :arn, String
|
7
|
+
attribute :protocol, String
|
8
|
+
attribute :endpoint, String
|
9
|
+
attribute :topic_arn, String
|
10
|
+
attribute :owner, String
|
11
|
+
|
12
|
+
def sqs?
|
13
|
+
protocol == "sqs"
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module FakeSNS
|
2
|
+
class SubscriptionCollection
|
3
|
+
|
4
|
+
include Enumerable
|
5
|
+
|
6
|
+
attr_reader :collection
|
7
|
+
|
8
|
+
def initialize(store)
|
9
|
+
@store = store
|
10
|
+
@store["subscriptions"] ||= []
|
11
|
+
end
|
12
|
+
|
13
|
+
def collection
|
14
|
+
@store["subscriptions"]
|
15
|
+
end
|
16
|
+
|
17
|
+
def reset
|
18
|
+
@store["subscriptions"] = []
|
19
|
+
end
|
20
|
+
|
21
|
+
def each(*args, &block)
|
22
|
+
collection.map { |item| Subscription.new(item) }.each(*args, &block)
|
23
|
+
end
|
24
|
+
|
25
|
+
def create(attributes)
|
26
|
+
collection << attributes
|
27
|
+
end
|
28
|
+
|
29
|
+
def delete(arn)
|
30
|
+
collection.delete(fetch(arn))
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
require "faraday"
|
2
|
+
|
3
|
+
module FakeSNS
|
4
|
+
class TestIntegration
|
5
|
+
|
6
|
+
attr_reader :options
|
7
|
+
|
8
|
+
def initialize(options = {})
|
9
|
+
@options = options
|
10
|
+
end
|
11
|
+
|
12
|
+
def host
|
13
|
+
option :sns_endpoint
|
14
|
+
end
|
15
|
+
|
16
|
+
def port
|
17
|
+
option :sns_port
|
18
|
+
end
|
19
|
+
|
20
|
+
def start
|
21
|
+
start! unless up?
|
22
|
+
reset
|
23
|
+
end
|
24
|
+
|
25
|
+
def start!
|
26
|
+
@pid = Process.spawn(binfile, "-p", port.to_s, "--database", database, :out => out, :err => out)
|
27
|
+
wait_until_up
|
28
|
+
end
|
29
|
+
|
30
|
+
def stop
|
31
|
+
if @pid
|
32
|
+
Process.kill("INT", @pid)
|
33
|
+
Process.waitpid(@pid)
|
34
|
+
@pid = nil
|
35
|
+
else
|
36
|
+
$stderr.puts "FakeSNS is not running"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def reset
|
41
|
+
connection.delete("/")
|
42
|
+
end
|
43
|
+
|
44
|
+
def url
|
45
|
+
"http://#{host}:#{port}"
|
46
|
+
end
|
47
|
+
|
48
|
+
def up?
|
49
|
+
@pid && connection.get("/").success?
|
50
|
+
rescue Errno::ECONNREFUSED, Faraday::Error::ConnectionFailed
|
51
|
+
false
|
52
|
+
end
|
53
|
+
|
54
|
+
def data
|
55
|
+
YAML.load(connection.get("/").body)
|
56
|
+
end
|
57
|
+
|
58
|
+
def drain(message_id = nil, options = {})
|
59
|
+
path = message_id ? "/drain/#{message_id}" : "/drain"
|
60
|
+
default = { aws_config: AWS.config.send(:supplied) }
|
61
|
+
body = default.merge(options).to_json
|
62
|
+
result = connection.post(path, body)
|
63
|
+
if result.success?
|
64
|
+
true
|
65
|
+
else
|
66
|
+
raise "Unable to drain messages: #{result.body}"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def connection
|
71
|
+
@connection ||= Faraday.new(url)
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
def database
|
77
|
+
options.fetch(:database) { ":memory:" }
|
78
|
+
end
|
79
|
+
|
80
|
+
def option(key)
|
81
|
+
options.fetch(key) { AWS.config.public_send(key) }
|
82
|
+
end
|
83
|
+
|
84
|
+
|
85
|
+
def wait_until_up(deadline = Time.now + 2)
|
86
|
+
fail "FakeSNS didn't start in time" if Time.now > deadline
|
87
|
+
unless up?
|
88
|
+
sleep 0.1
|
89
|
+
wait_until_up(deadline)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def binfile
|
94
|
+
File.expand_path("../../../bin/fake_sns", __FILE__)
|
95
|
+
end
|
96
|
+
|
97
|
+
def out
|
98
|
+
if debug?
|
99
|
+
:out
|
100
|
+
else
|
101
|
+
"/dev/null"
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def debug?
|
106
|
+
ENV["DEBUG"].to_s == "true"
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
110
|
+
end
|