fare 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,28 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ begin
4
+ require 'cucumber'
5
+ require 'cucumber/rake/task'
6
+
7
+ Cucumber::Rake::Task.new(:features)
8
+
9
+ rescue LoadError
10
+ task :features do
11
+ puts "Cucumber not installed."
12
+ exit 1
13
+ end
14
+ end
15
+
16
+ begin
17
+ require 'rspec/core/rake_task'
18
+ RSpec::Core::RakeTask.new(:spec) do |t|
19
+ t.pattern = "spec"
20
+ end
21
+ rescue LoadError
22
+ task :spec do
23
+ puts "RSpec not installed"
24
+ exit 1
25
+ end
26
+ end
27
+
28
+ task :default => [:spec, :features]
@@ -0,0 +1,48 @@
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 "fare"
7
+ require "optparse"
8
+
9
+ command = ARGV.shift
10
+
11
+ def show_help
12
+ puts <<-HELP.gsub(/^ +/, '')
13
+ Usage: fare COMMAND [OPTIONS]
14
+
15
+ Available commands:
16
+
17
+ fare update Parses your configuration file, creates topics, queus, subscriptions and caches it.
18
+ fare subscriber Controls the subscribers.
19
+
20
+ You can run any command with the --help option.
21
+
22
+ Example: fare subscriber --help
23
+ HELP
24
+ end
25
+
26
+ case command
27
+ when "update"
28
+ require "fare/update_cli"
29
+ Fare::UpdateCLI.new(ARGV).call
30
+ when "subscriber"
31
+ require "fare/subscriber_cli"
32
+ Fare::SubscriberCLI.new(ARGV).call
33
+ when "-v", "--version"
34
+ puts "Fare version #{Fare::VERSION}"
35
+ exit 0
36
+ when "help", "--help", "-h"
37
+ show_help
38
+ exit 0
39
+ when "", nil
40
+ show_help
41
+ exit 1
42
+ else
43
+ puts "Unkown command: #{command}"
44
+ puts
45
+ show_help
46
+ exit 1
47
+ end
48
+
@@ -0,0 +1,35 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'fare/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "fare"
8
+ spec.version = Fare::VERSION
9
+ spec.authors = ["iain"]
10
+ spec.email = ["iain@iain.nl"]
11
+ spec.description = %q{An event system built on Amazon SNS and SQS}
12
+ spec.summary = %q{An event system built on Amazon SNS and SQS}
13
+ spec.homepage = "https://github.com/yourkarma/fare"
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 "aws-sdk"
21
+ spec.add_dependency "daemonic", "~> 0.1.2"
22
+ spec.add_dependency "virtus"
23
+
24
+ spec.add_development_dependency "bundler"
25
+ spec.add_development_dependency "thin"
26
+ spec.add_development_dependency "rake"
27
+ spec.add_development_dependency "rspec"
28
+ spec.add_development_dependency "fake_sqs", "~> 0.0.10"
29
+ spec.add_development_dependency "fake_sns", "~> 0.0.2"
30
+
31
+ spec.add_development_dependency "cucumber"
32
+ spec.add_development_dependency "aruba"
33
+ spec.add_development_dependency "json_expressions"
34
+
35
+ end
@@ -0,0 +1,60 @@
1
+ Feature: Multiqueue
2
+
3
+ Scenario: Different subscribers for different queues
4
+
5
+ Given the Fare config:
6
+ """
7
+ app_name "my_app"
8
+
9
+ publishes subject: "user", action: "login", version: "0.1"
10
+ publishes subject: "user", action: "signup", version: "0.1"
11
+
12
+ subscriber do
13
+
14
+ setup do
15
+ require File.expand_path("../../middleware", __FILE__)
16
+ end
17
+
18
+ stack do
19
+ listen_to subject: "user", action: "login"
20
+ run do
21
+ use RegisterEvent, name: "default-queue"
22
+ end
23
+ end
24
+
25
+ end
26
+
27
+ subscriber :other_queue do
28
+
29
+ setup do
30
+ require File.expand_path("../../middleware", __FILE__)
31
+ end
32
+
33
+ stack do
34
+ listen_to subject: "user", action: "login"
35
+ run do
36
+ use RegisterEvent, name: "other-queue"
37
+ end
38
+ end
39
+
40
+ end
41
+ """
42
+
43
+ And a file named "middleware.rb" with:
44
+ """
45
+ class RegisterEvent
46
+ def initialize(app, options = {})
47
+ @app = app
48
+ @options = options
49
+ end
50
+ def call(env)
51
+ puts "Registered event by #{@options[:name]}"
52
+ exit
53
+ end
54
+ end
55
+ """
56
+
57
+ When I publish an event with the subject "user" and action "login"
58
+ And I run `fare subscriber start --name other_queue`
59
+ Then the output should contain "Registered event by other-queue"
60
+ But the output should not contain "Registered event by default-queue"
@@ -0,0 +1,65 @@
1
+ Feature: Multistack
2
+
3
+ Scenario: Different stacks for different messages
4
+
5
+ Given the Fare config:
6
+ """
7
+ app_name "my_app"
8
+
9
+ publishes subject: "user", action: "login", version: "0.1"
10
+ publishes subject: "user", action: "signup", version: "0.1"
11
+
12
+ subscriber do
13
+
14
+ setup do
15
+ require File.expand_path("../../middleware", __FILE__)
16
+ end
17
+
18
+ stack do
19
+ listen_to subject: "user", action: "login"
20
+ run do
21
+ use TestForLogin
22
+ end
23
+ end
24
+
25
+ stack do
26
+ listen_to subject: "user", action: "signup"
27
+ run do
28
+ use TestForSignup
29
+ end
30
+ end
31
+
32
+ end
33
+ """
34
+
35
+ And a file named "middleware.rb" with:
36
+ """
37
+ class TestForLogin
38
+ def initialize(app)
39
+ @app = app
40
+ end
41
+ def call(env)
42
+ puts "Received Login"
43
+ exit
44
+ end
45
+ end
46
+
47
+ class TestForSignup
48
+ def initialize(app)
49
+ @app = app
50
+ end
51
+ def call(env)
52
+ puts "Received Signup"
53
+ exit
54
+ end
55
+ end
56
+ """
57
+
58
+ When I publish an event with the subject "user" and action "login"
59
+ And I run `fare subscriber start`
60
+ Then the output should contain "Received Login"
61
+ But the output should not contain "Received Signup"
62
+
63
+ When I publish an event with the subject "user" and action "signup"
64
+ And I run `fare subscriber start`
65
+ Then the output should contain "Received Signup"
@@ -0,0 +1 @@
1
+ require "aruba/cucumber"
@@ -0,0 +1,40 @@
1
+ Given(/^the Fare config:$/) do |string|
2
+
3
+ extra = %Q|require File.expand_path("../../helper.rb", __FILE__)|
4
+
5
+ write_file "config/fare.rb", "#{extra}\n#{string}"
6
+
7
+ write_file "helper.rb", <<-HELPER
8
+
9
+ AWS.config(
10
+ use_ssl: false,
11
+ sqs_endpoint: "localhost",
12
+ sqs_port: 4568,
13
+ sns_endpoint: "localhost",
14
+ sns_port: 9293,
15
+ access_key_id: "fake access key",
16
+ secret_access_key: "fake secret key",
17
+ )
18
+
19
+ HELPER
20
+
21
+ run_simple("fare update")
22
+ end
23
+
24
+ When(/^I give SNS time to propagate the messages$/) do
25
+ $fake_sns.drain
26
+ end
27
+
28
+ When(/^I publish an event with the subject "(.*?)" and action "(.*?)"$/) do |subject, action|
29
+ write_file "publisher.rb", <<-PUBLISHER
30
+ require "bundler/setup"
31
+ Bundler.require(:default, :test)
32
+ Fare.publish(subject: #{subject.inspect}, action: #{action.inspect}, payload: "payload")
33
+ PUBLISHER
34
+
35
+ run_simple "ruby publisher.rb"
36
+
37
+ $fake_sns.drain
38
+ $fake_sns.reset
39
+ run_simple("fare update --force")
40
+ end
@@ -0,0 +1,95 @@
1
+ Feature: Subscriber
2
+
3
+ Scenario: Running in the foreground
4
+
5
+ Given the Fare config:
6
+ """
7
+ app_name "my_app"
8
+
9
+ publishes subject: "user", action: "login", version: "0.1"
10
+
11
+ subscriber do
12
+
13
+ stack do
14
+ listen_to subject: "user", action: "login"
15
+
16
+ run do
17
+ use Class.new {
18
+
19
+ def initialize(app, options = {})
20
+ @app = app
21
+ end
22
+
23
+ def call(env)
24
+ event = env.fetch(:event)
25
+ puts "Event received: #{event.subject} - #{event.action}"
26
+ exit
27
+ end
28
+
29
+ }
30
+ end
31
+ end
32
+
33
+ end
34
+ """
35
+
36
+ When I publish an event with the subject "user" and action "login"
37
+
38
+ And I run `fare subscriber start`
39
+
40
+ Then the output should contain "Event received: user - login"
41
+
42
+ Scenario: Multiple Middleware
43
+
44
+ Given the Fare config:
45
+ """
46
+ app_name "my_app"
47
+
48
+ publishes subject: "user", action: "login", version: "0.1"
49
+
50
+ subscriber do
51
+
52
+ setup do
53
+ require File.expand_path("../../middleware", __FILE__)
54
+ end
55
+
56
+ stack do
57
+ listen_to subject: "user", action: "login"
58
+
59
+ run do
60
+ use TestMiddlewareOne
61
+ use TestMiddlewareTwo
62
+ end
63
+ end
64
+
65
+ end
66
+ """
67
+
68
+ And a file named "middleware.rb" with:
69
+ """
70
+ class TestMiddlewareOne
71
+ def initialize(app)
72
+ @app = app
73
+ end
74
+ def call(env)
75
+ env[:one] = "Extra Data"
76
+ @app.call(env)
77
+ end
78
+ end
79
+
80
+ class TestMiddlewareTwo
81
+ def initialize(app)
82
+ @app = app
83
+ end
84
+ def call(env)
85
+ puts "Received data: #{env[:one]}"
86
+ exit
87
+ end
88
+ end
89
+ """
90
+
91
+ When I publish an event with the subject "user" and action "login"
92
+
93
+ And I run `fare subscriber start`
94
+
95
+ Then the output should contain "Received data: Extra Data"
@@ -0,0 +1,34 @@
1
+ ENV["RACK_ENV"] = "test"
2
+ require "bundler/setup"
3
+ Bundler.require(:default, :test)
4
+
5
+ require "fare"
6
+
7
+ require "fake_sns/test_integration"
8
+ require "fake_sqs/test_integration"
9
+
10
+ AWS.config(
11
+ use_ssl: false,
12
+ sqs_endpoint: "localhost",
13
+ sqs_port: 4568,
14
+ sns_endpoint: "localhost",
15
+ sns_port: 9293,
16
+ access_key_id: "fake access key",
17
+ secret_access_key: "fake secret key",
18
+ )
19
+
20
+ $fake_sns = FakeSNS::TestIntegration.new(database: ":memory:")
21
+ $fake_sqs = FakeSQS::TestIntegration.new(database: ":memory:")
22
+
23
+ $fake_sns.start
24
+ $fake_sqs.start
25
+
26
+ at_exit {
27
+ $fake_sns.stop
28
+ $fake_sqs.stop
29
+ }
30
+
31
+ Before do
32
+ $fake_sns.reset
33
+ $fake_sqs.reset
34
+ end
@@ -0,0 +1,96 @@
1
+ require "aws-sdk"
2
+ require "verbose_hash_fetch"
3
+ require "base64"
4
+ require "json"
5
+ require "yaml"
6
+ require "digest/md5"
7
+ require "virtus"
8
+ require "forwardable"
9
+
10
+ require "fare/version"
11
+
12
+ require "fare/load_configuration_file"
13
+ require "fare/configuration_dsl"
14
+ require "fare/configuration"
15
+ require "fare/subscriber_stack"
16
+ require "fare/generate_lock_file"
17
+ require "fare/topic"
18
+
19
+ require "fare/queue_adapter"
20
+ require "fare/topic_adapter"
21
+
22
+ require "fare/configuration_when_locked"
23
+ require "fare/publisher"
24
+
25
+ require "fare/subscriber"
26
+ require "fare/event"
27
+
28
+ require "fare/middleware/logging"
29
+ require "fare/middleware/raven"
30
+
31
+ module Fare
32
+ ConfigurationNotFoundError = Class.new(RuntimeError)
33
+ LockFileNotFoundError = Class.new(RuntimeError)
34
+ ChecksumNotMatchingError = Class.new(RuntimeError)
35
+ NoEnvironmentFoundError = Class.new(RuntimeError)
36
+
37
+ class << self
38
+ attr_accessor :queue_adapter, :topic_adapter
39
+ end
40
+ self.queue_adapter = QueueAdapter
41
+ self.topic_adapter = TopicAdapter
42
+
43
+ def self.test_mode!
44
+ require "fare/test_mode"
45
+ @message_list = TestMode::MessageList.new
46
+ self.queue_adapter = @message_list.queue_adapter
47
+ self.topic_adapter = @message_list.topic_adapter
48
+ update(force: true)
49
+ @configuration = nil
50
+ end
51
+
52
+ def self.stubbed_messages
53
+ if @message_list
54
+ @message_list
55
+ else
56
+ fail "Not in test mode. Enable it with: Fare.test_mode!"
57
+ end
58
+ end
59
+
60
+ def self.given_event(*args)
61
+ stubbed_messages.given_event(*args)
62
+ end
63
+
64
+ def self.run(*args)
65
+ stubbed_messages.run(*args)
66
+ end
67
+
68
+ def self.default_config_file
69
+ File.expand_path("config/fare.rb", Dir.pwd)
70
+ end
71
+
72
+ def self.default_environment
73
+ env = ENV["RACK_ENV"] || ENV["RAILS_ENV"]
74
+ if env.nil? && defined?(::Rails)
75
+ env = Rails.env
76
+ end
77
+ env
78
+ end
79
+
80
+ def self.update(options = {})
81
+ GenerateLockFile.new(options).call
82
+ end
83
+
84
+ def self.publish(options)
85
+ Publisher.new(configuration, options).call
86
+ end
87
+
88
+ def self.configuration
89
+ @configuration ||= config({})
90
+ end
91
+
92
+ def self.config(options)
93
+ @configuration = ConfigurationWhenLocked.new(options)
94
+ end
95
+
96
+ end