refinery 0.9.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.
Files changed (53) hide show
  1. data/.autotest +10 -0
  2. data/.gitignore +5 -0
  3. data/CHANGELOG +1 -0
  4. data/LICENSE +21 -0
  5. data/README.rdoc +50 -0
  6. data/README.textile +50 -0
  7. data/Rakefile +39 -0
  8. data/VERSION +1 -0
  9. data/bin/epub +53 -0
  10. data/bin/monitor +47 -0
  11. data/bin/pubnow +61 -0
  12. data/bin/refinery +53 -0
  13. data/config/config.example.yml +18 -0
  14. data/lib/refinery/config.rb +48 -0
  15. data/lib/refinery/configurable.rb +15 -0
  16. data/lib/refinery/daemon.rb +124 -0
  17. data/lib/refinery/event_publisher.rb +120 -0
  18. data/lib/refinery/heartbeat.rb +30 -0
  19. data/lib/refinery/loggable.rb +9 -0
  20. data/lib/refinery/monitor.rb +116 -0
  21. data/lib/refinery/publisher.rb +24 -0
  22. data/lib/refinery/queueable.rb +20 -0
  23. data/lib/refinery/server.rb +86 -0
  24. data/lib/refinery/statistics.rb +61 -0
  25. data/lib/refinery/stats_server.rb +134 -0
  26. data/lib/refinery/utilities.rb +33 -0
  27. data/lib/refinery/validations.rb +48 -0
  28. data/lib/refinery/worker.rb +65 -0
  29. data/lib/refinery.rb +74 -0
  30. data/logs/README +1 -0
  31. data/publishers/error.rb +8 -0
  32. data/publishers/sample.rb +8 -0
  33. data/publishers/sleep.rb +7 -0
  34. data/refinery.gemspec +105 -0
  35. data/test/config.yml +10 -0
  36. data/test/test_helper.rb +21 -0
  37. data/test/unit/config_test.rb +42 -0
  38. data/test/unit/configurable_test.rb +11 -0
  39. data/test/unit/daemon_test.rb +37 -0
  40. data/test/unit/event_publisher_test.rb +11 -0
  41. data/test/unit/heartbeat_test.rb +22 -0
  42. data/test/unit/loggable_test.rb +11 -0
  43. data/test/unit/publisher_test.rb +13 -0
  44. data/test/unit/queueable_test.rb +24 -0
  45. data/test/unit/server_test.rb +39 -0
  46. data/test/unit/statistics_test.rb +41 -0
  47. data/test/unit/utilities_test.rb +25 -0
  48. data/test/unit/validations_test.rb +37 -0
  49. data/test/unit/worker_test.rb +44 -0
  50. data/workers/error.rb +8 -0
  51. data/workers/sample.rb +8 -0
  52. data/workers/sleep.rb +7 -0
  53. metadata +122 -0
@@ -0,0 +1,65 @@
1
+ module Refinery #:nodoc:
2
+ # Base class for workers. Place subclasses of this in the workers
3
+ # directory.
4
+ #
5
+ # Workers may include validation logic to verify that the message
6
+ # has the correct keys and values before processing.
7
+ class Worker
8
+ include Refinery::Loggable
9
+ include Refinery::Configurable
10
+ include Refinery::Utilities
11
+ include Refinery::Validations
12
+ include Refinery::Queueable
13
+
14
+ # Initialize the worker with the given daemon.
15
+ def initialize(daemon)
16
+ @daemon = daemon
17
+ end
18
+
19
+ # Run the worker with the given message. The result from the worker's
20
+ # <code>execute</code> method is returned along with the run time.
21
+ #
22
+ # Validation will occur prior to calling execute.
23
+ def run(message)
24
+ result = false
25
+
26
+ validate(message)
27
+
28
+ logger.debug "Executing worker #{self.class.name}"
29
+ time = Benchmark.realtime do
30
+ begin
31
+ result = execute(message)
32
+ rescue Exception => e
33
+ logger.error "Error executing worker #{self.class.name}: #{e.message}"
34
+ raise e
35
+ end
36
+ end
37
+ logger.debug "Completed worker #{self.class.name} in #{time} seconds"
38
+ return result, time
39
+ end
40
+
41
+ # Get the data store for the worker.
42
+ #
43
+ # The data store is provided through the Moneta interface.
44
+ #
45
+ # If the configuration providers a data_store:class option then that class
46
+ # will be used (the class must be in the Moneta module), otherwise
47
+ # Moneta::S3 will be used.
48
+ def data_store(options)
49
+ class_name = processor_config['workers']['data_store']['class'] rescue 'S3'
50
+ ds_class = Moneta.const_get(camelize(class_name))
51
+ (@data_store ||= {})[options] ||= ds_class.new(
52
+ :access_key_id => config['aws']['credentials']['access_key_id'],
53
+ :secret_access_key => config['aws']['credentials']['secret_access_key'],
54
+ :bucket => options[:bucket],
55
+ :multi_thread => true
56
+ )
57
+ end
58
+
59
+ private
60
+ # Get's the config element starting at the processer
61
+ def processor_config
62
+ config['processors'][daemon.name]
63
+ end
64
+ end
65
+ end
data/lib/refinery.rb ADDED
@@ -0,0 +1,74 @@
1
+ $:.unshift(File.dirname(__FILE__))
2
+
3
+ require 'logger'
4
+ require 'socket'
5
+ require 'benchmark'
6
+
7
+ # The Refinery module contains all of the classes for the refinery system.
8
+ module Refinery
9
+
10
+ # Require the specified library.
11
+ #
12
+ # The short name is the require path and the display_name will be shown
13
+ # if the library cannot be loaded.
14
+ def self.require_library(short_name, display_name)
15
+ begin
16
+ require short_name
17
+ rescue LoadError
18
+ puts "#{display_name} is required, please install it"
19
+ exit
20
+ end
21
+ end
22
+
23
+ # Require all of the dependencies.
24
+ def self.require_libraries
25
+ require_library('rubygems', 'Rubygems')
26
+ require_library('right_aws', 'RightScale AWS gem')
27
+ require_library('json', 'JSON gem')
28
+ require_library('moneta', 'Moneta gem')
29
+ require_library('moneta/s3', 'Moneta S3 implementation')
30
+ end
31
+
32
+ def self.require_optional_library(short_name, display_name)
33
+ begin
34
+ require short_name
35
+ rescue LoadError
36
+ end
37
+ end
38
+
39
+ def self.require_optional_libraries
40
+ require_optional_library('sequel', 'Sequel gem')
41
+ require_optional_library('ramaze', 'Ramaze')
42
+ end
43
+
44
+ # Require internal code files
45
+ def self.require_internals
46
+ require 'refinery/loggable'
47
+ require 'refinery/configurable'
48
+ require 'refinery/queueable'
49
+
50
+ require 'refinery/utilities'
51
+
52
+ require 'refinery/validations'
53
+
54
+ require 'refinery/config'
55
+ require 'refinery/heartbeat'
56
+ require 'refinery/server'
57
+ require 'refinery/daemon'
58
+ require 'refinery/worker'
59
+ require 'refinery/event_publisher'
60
+ require 'refinery/publisher'
61
+ require 'refinery/monitor'
62
+ require 'refinery/statistics'
63
+ require 'refinery/stats_server'
64
+
65
+ end
66
+
67
+ # Raised if a source file cannot be loaded
68
+ class SourceFileNotFound < RuntimeError
69
+ end
70
+ end
71
+
72
+ Refinery::require_libraries
73
+ Refinery::require_optional_libraries
74
+ Refinery::require_internals
data/logs/README ADDED
@@ -0,0 +1 @@
1
+ Log files from Refinery will be written here. Do not remove this directory.
@@ -0,0 +1,8 @@
1
+ # An example publisher that posts a message to the queue that should raise an error.
2
+ class Error < Refinery::Publisher
3
+ def execute
4
+ if waiting_queue.size == 0
5
+ publish({'text' => 'fire an error, please'})
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ # A sample publisher that posts a message to the queue.
2
+ class Sample < Refinery::Publisher
3
+ def execute
4
+ if waiting_queue.size == 0
5
+ publish({'text' => 'hey there!'})
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,7 @@
1
+ class Sleep < Refinery::Publisher
2
+ def execute
3
+ if waiting_queue.size == 0
4
+ publish({'seconds' => rand(5) + 0.5})
5
+ end
6
+ end
7
+ end
data/refinery.gemspec ADDED
@@ -0,0 +1,105 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{refinery}
5
+ s.version = "0.9.0"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Anthony Eden"]
9
+ s.date = %q{2009-06-01}
10
+ s.description = %q{Process data in a distributed fashion.}
11
+ s.email = %q{anthonyeden@gmail.com}
12
+ s.executables = ["epub", "monitor", "pubnow", "refinery"]
13
+ s.extra_rdoc_files = [
14
+ "LICENSE",
15
+ "README.rdoc",
16
+ "README.textile"
17
+ ]
18
+ s.files = [
19
+ ".autotest",
20
+ ".gitignore",
21
+ "CHANGELOG",
22
+ "LICENSE",
23
+ "README.rdoc",
24
+ "README.textile",
25
+ "Rakefile",
26
+ "VERSION",
27
+ "bin/epub",
28
+ "bin/monitor",
29
+ "bin/pubnow",
30
+ "bin/refinery",
31
+ "config/config.example.yml",
32
+ "lib/refinery.rb",
33
+ "lib/refinery/config.rb",
34
+ "lib/refinery/configurable.rb",
35
+ "lib/refinery/daemon.rb",
36
+ "lib/refinery/event_publisher.rb",
37
+ "lib/refinery/heartbeat.rb",
38
+ "lib/refinery/loggable.rb",
39
+ "lib/refinery/monitor.rb",
40
+ "lib/refinery/publisher.rb",
41
+ "lib/refinery/queueable.rb",
42
+ "lib/refinery/server.rb",
43
+ "lib/refinery/statistics.rb",
44
+ "lib/refinery/stats_server.rb",
45
+ "lib/refinery/utilities.rb",
46
+ "lib/refinery/validations.rb",
47
+ "lib/refinery/worker.rb",
48
+ "logs/README",
49
+ "publishers/error.rb",
50
+ "publishers/sample.rb",
51
+ "publishers/sleep.rb",
52
+ "refinery.gemspec",
53
+ "test/config.yml",
54
+ "test/test_helper.rb",
55
+ "test/unit/config_test.rb",
56
+ "test/unit/configurable_test.rb",
57
+ "test/unit/daemon_test.rb",
58
+ "test/unit/event_publisher_test.rb",
59
+ "test/unit/heartbeat_test.rb",
60
+ "test/unit/loggable_test.rb",
61
+ "test/unit/publisher_test.rb",
62
+ "test/unit/queueable_test.rb",
63
+ "test/unit/server_test.rb",
64
+ "test/unit/statistics_test.rb",
65
+ "test/unit/utilities_test.rb",
66
+ "test/unit/validations_test.rb",
67
+ "test/unit/worker_test.rb",
68
+ "workers/error.rb",
69
+ "workers/sample.rb",
70
+ "workers/sleep.rb"
71
+ ]
72
+ s.has_rdoc = true
73
+ s.homepage = %q{http://github.com/aeden/refinery}
74
+ s.rdoc_options = ["--charset=UTF-8"]
75
+ s.require_paths = ["lib"]
76
+ s.rubyforge_project = %q{refinery}
77
+ s.rubygems_version = %q{1.3.1}
78
+ s.summary = %q{Refinery processes data in a distributed environment.}
79
+ s.test_files = [
80
+ "test/test_helper.rb",
81
+ "test/unit/config_test.rb",
82
+ "test/unit/configurable_test.rb",
83
+ "test/unit/daemon_test.rb",
84
+ "test/unit/event_publisher_test.rb",
85
+ "test/unit/heartbeat_test.rb",
86
+ "test/unit/loggable_test.rb",
87
+ "test/unit/publisher_test.rb",
88
+ "test/unit/queueable_test.rb",
89
+ "test/unit/server_test.rb",
90
+ "test/unit/statistics_test.rb",
91
+ "test/unit/utilities_test.rb",
92
+ "test/unit/validations_test.rb",
93
+ "test/unit/worker_test.rb"
94
+ ]
95
+
96
+ if s.respond_to? :specification_version then
97
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
98
+ s.specification_version = 2
99
+
100
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
101
+ else
102
+ end
103
+ else
104
+ end
105
+ end
data/test/config.yml ADDED
@@ -0,0 +1,10 @@
1
+ aws:
2
+ credentials:
3
+ access_key_id: "aaa"
4
+ secret_access_key: "bbb"
5
+ processors:
6
+ sample:
7
+ publishers:
8
+ delay: 10
9
+ workers:
10
+ initial: 3
@@ -0,0 +1,21 @@
1
+ require 'test/unit'
2
+ require 'rubygems'
3
+ require 'shoulda'
4
+ require 'mocha'
5
+ require File.dirname(__FILE__) + '/../lib/refinery'
6
+
7
+ class Test::Unit::TestCase
8
+ def setup_default_config
9
+ Refinery::Config.stubs(:default).returns(Refinery::Config.new(
10
+ {
11
+ 'aws' => {
12
+ 'credentials' => {
13
+ 'access_key_id' => 'aki',
14
+ 'secret_access_key' => 'sak'
15
+ }
16
+ },
17
+ 'processors' => []
18
+ }
19
+ ))
20
+ end
21
+ end
@@ -0,0 +1,42 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ class ConfigTest < Test::Unit::TestCase
4
+ context "the config class" do
5
+ should "provide a default configuration" do
6
+ assert_not_nil Refinery::Config.default
7
+ end
8
+
9
+ context "default configuration" do
10
+ setup do
11
+ @config = Refinery::Config.default
12
+ end
13
+ should "provide an empty aws credentials hash" do
14
+ assert_equal Hash.new, @config['aws']['credentials']
15
+ end
16
+ should "provide an empty processors hash" do
17
+ assert_equal Hash.new, @config['processors']
18
+ end
19
+ end
20
+
21
+ context "after loading configuration from a YAML file" do
22
+ setup do
23
+ @config_file = File.dirname(__FILE__) + '/../config.yml'
24
+ @config = Refinery::Config.new
25
+ @config.load_file(@config_file)
26
+ end
27
+ should "have aws credentials" do
28
+ assert_equal 'aaa', @config['aws']['credentials']['access_key_id']
29
+ assert_equal 'bbb', @config['aws']['credentials']['secret_access_key']
30
+ end
31
+ should "reload the file when changed" do
32
+ `touch #{@config_file}`
33
+ YAML.expects(:load_file).once
34
+ @config.refresh
35
+ end
36
+ should "not reload the file when not changed" do
37
+ YAML.expects(:load_file).never
38
+ @config.refresh
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,11 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+ class ConfigureMe
3
+ include Refinery::Configurable
4
+ end
5
+ class ConfigurableTest < Test::Unit::TestCase
6
+ context "a class with the configurable module" do
7
+ should "provide a config" do
8
+ assert_not_nil ConfigureMe.new.config
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,37 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+ class DaemonTest < Test::Unit::TestCase
3
+ context "a daemon" do
4
+ setup do
5
+ @server = stub('Server')
6
+ @waiting_queue = stub('Queue(waiting)')
7
+ @waiting_queue.stubs(:receive)
8
+ @error_queue = stub('Queue(error)')
9
+ @done_queue = stub('Queue(done)')
10
+ end
11
+ should "be startable" do
12
+ assert_nothing_raised do
13
+ daemon = Refinery::Daemon.new(@server, 'sample', @waiting_queue, @error_queue, @done_queue)
14
+ end
15
+ end
16
+ should "have logging" do
17
+ daemon = Refinery::Daemon.new(@server, 'sample', @waiting_queue, @error_queue, @done_queue)
18
+ assert_not_nil daemon.logger
19
+ end
20
+ context "that is started" do
21
+ setup do
22
+ @daemon = Refinery::Daemon.new(@server, 'sample', @waiting_queue, @error_queue, @done_queue)
23
+ end
24
+ should "have a state of running" do
25
+ assert @daemon.running?
26
+ end
27
+ context "after calling stop" do
28
+ setup do
29
+ @daemon.stop
30
+ end
31
+ should "not be running" do
32
+ assert !@daemon.running?
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,11 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+ class EventPublisherTest < Test::Unit::TestCase
3
+ context "an event publisher" do
4
+ should "raise an error if credentials are not set" do
5
+ publishing_settings = {'sample' => {'delay' => 10}}
6
+ Refinery::Config.any_instance.stubs(:publishing).returns(publishing_settings)
7
+ event_publisher = Refinery::EventPublisher.new
8
+ event_publisher.run
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,22 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+ class HeartbeatTest < Test::Unit::TestCase
3
+ context "a heartbeat" do
4
+ setup do
5
+ setup_default_config
6
+
7
+ @server = stub('server')
8
+ @server.stubs(:daemons).returns([])
9
+
10
+ heartbeat_queue = stub('heartbeat queue')
11
+ heartbeat_queue.stubs(:send_message)
12
+ queue_provider = stub('queue provider')
13
+ queue_provider.expects(:queue).with('heartbeat').returns(heartbeat_queue)
14
+ RightAws::SqsGen2.stubs(:new).with(
15
+ 'aki', 'sak', {:multi_thread => true}
16
+ ).returns(queue_provider)
17
+ end
18
+ should "be initializable" do
19
+ Refinery::Heartbeat.new(@server)
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,11 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+ class LogMe
3
+ include Refinery::Loggable
4
+ end
5
+ class LoggableTest < Test::Unit::TestCase
6
+ context "a class with Loggable mixed in" do
7
+ should "have a logger" do
8
+ assert_not_nil LogMe.new.logger
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,13 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ class SamplePublisher < Refinery::Publisher
4
+ end
5
+
6
+ class PublisherTest < Test::Unit::TestCase
7
+ context "a publisher" do
8
+ should "be instantiable" do
9
+ waiting_queue = stub('waiting queue')
10
+ SamplePublisher.new(waiting_queue)
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,24 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ class QueueMe
4
+ include Refinery::Configurable
5
+ include Refinery::Queueable
6
+ end
7
+
8
+ class QueueableTest < Test::Unit::TestCase
9
+ context "a class with the Queuable module" do
10
+ should "provide a queue" do
11
+ setup_default_config
12
+
13
+ queue = stub('queue')
14
+ queue_provider = stub('queue provider')
15
+ queue_provider.expects(:queue).with('a_queue').returns(queue)
16
+ RightAws::SqsGen2.expects(:new).with(
17
+ 'aki', 'sak', {:multi_thread => true}
18
+ ).returns(queue_provider)
19
+
20
+ queueable = QueueMe.new
21
+ assert_not_nil queueable.queue('a_queue')
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,39 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+ class ServerTest < Test::Unit::TestCase
3
+ context "the server class" do
4
+ should "provide a logger" do
5
+ assert_not_nil Refinery::Server.logger
6
+ end
7
+ context "logger" do
8
+ should "default to WARN level" do
9
+ assert_equal Logger::WARN, Refinery::Server.logger.level
10
+ end
11
+ end
12
+ end
13
+ context "a server instance" do
14
+ setup do
15
+ @server = Refinery::Server.new
16
+ end
17
+ should "have a config" do
18
+ assert_not_nil @server.config
19
+ end
20
+ should "be runnable" do
21
+ setup_default_config
22
+
23
+ heartbeat_queue = stub('heartbeat queue')
24
+ heartbeat_queue.stubs(:send_message)
25
+ queue_provider = stub('queue provider')
26
+ queue_provider.expects(:queue).with('heartbeat').returns(heartbeat_queue)
27
+ RightAws::SqsGen2.expects(:new).with(
28
+ 'aki', 'sak', {:multi_thread => true}
29
+ ).returns(queue_provider)
30
+
31
+ assert_nothing_raised do
32
+ thread = Thread.new do
33
+ @server.run
34
+ end
35
+ @server.stop
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,41 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ class StatisticsTest < Test::Unit::TestCase
4
+ context "a statistics instance" do
5
+ should "record a done message" do
6
+ dataset = stub('dataset')
7
+ dataset.expects(:<<) # TODO: improve this expectation
8
+
9
+ db = stub('db')
10
+ db.stubs(:table_exists?).returns(true)
11
+ db.stubs(:[]).with(:completed_jobs).returns(dataset)
12
+
13
+ Sequel.expects(:connect).with('sqlite://stats.db').returns(db)
14
+
15
+ message = {
16
+ 'host_info' => {'hostname' => 'test', 'pid' => 1},
17
+ 'run_time' => 1,
18
+ 'original' => ''
19
+ }
20
+ Refinery::Statistics.new.record_done(message)
21
+ end
22
+
23
+ should "record an error message" do
24
+ dataset = stub('dataset')
25
+ dataset.expects(:<<) # TODO: improve this expectation
26
+
27
+ db = stub('db')
28
+ db.stubs(:table_exists?).returns(true)
29
+ db.stubs(:[]).with(:errors).returns(dataset)
30
+
31
+ Sequel.expects(:connect).with('sqlite://stats.db').returns(db)
32
+
33
+ message = {
34
+ 'host_info' => {'hostname' => 'test', 'pid' => 1},
35
+ 'error' => {'class' => 'Error', 'message' => 'An error occurred.'},
36
+ 'original' => ''
37
+ }
38
+ Refinery::Statistics.new.record_error(message)
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,25 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ class UtilitiesIncluded
4
+ include Refinery::Utilities
5
+ end
6
+
7
+ class UtilitiesTest < Test::Unit::TestCase
8
+ context "a class with utilities included" do
9
+ setup do
10
+ @o = UtilitiesIncluded.new
11
+ end
12
+ should "camelize a word" do
13
+
14
+ assert_equal 'ClassName', @o.camelize('class_name')
15
+ end
16
+ should "encode and decode message" do
17
+ message = {'some' => 'message'}
18
+ assert_equal message, @o.decode_message(@o.encode_message(message))
19
+ end
20
+ should "provide host info" do
21
+ assert_not_nil @o.host_info['pid']
22
+ assert_not_nil @o.host_info['hostname']
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,37 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ class ValidatedWorker < Refinery::Worker
4
+ include Refinery::Validations
5
+ validate_with do |message|
6
+ raise Refinery::InvalidMessageError, "A message is required" unless message
7
+ end
8
+ validates_key_exists :test
9
+
10
+ def execute(message)
11
+ end
12
+ end
13
+ class ValidationsTest < Test::Unit::TestCase
14
+ context "a validated worker" do
15
+ setup do
16
+ daemon = stub('daemon')
17
+ @worker = ValidatedWorker.new(daemon)
18
+ end
19
+ should "raise a validation error if the key does not exist" do
20
+ message = {}
21
+ assert_raise Refinery::InvalidMessageError do
22
+ @worker.run(message)
23
+ end
24
+ end
25
+ should "not raise a validation error if the key does exist" do
26
+ message = {:test => 'ding!'}
27
+ assert_nothing_raised do
28
+ @worker.run(message)
29
+ end
30
+ end
31
+ should "raise a validation error if the message is nil" do
32
+ assert_raise Refinery::InvalidMessageError do
33
+ @worker.run(nil)
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,44 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ class SampleWorker < Refinery::Worker
4
+ attr_reader :message
5
+ def execute(message)
6
+ @message = message
7
+ end
8
+ end
9
+
10
+ class WorkerTest < Test::Unit::TestCase
11
+ context "a worker" do
12
+ setup do
13
+ daemon = stub('daemon')
14
+ @worker = SampleWorker.new(daemon)
15
+ @message = {'test' => 'value'}
16
+ end
17
+ should "run" do
18
+ @worker.run(@message)
19
+ assert_equal @message, @worker.message
20
+ end
21
+ should "provide a data store" do
22
+ options = {:bucket => 'bucket'}
23
+
24
+ data_store = stub('data store')
25
+
26
+ Moneta::S3.expects(:new).with(
27
+ :access_key_id => 'aki',
28
+ :secret_access_key => 'sak',
29
+ :bucket => options[:bucket],
30
+ :multi_thread => true
31
+ ).returns(data_store)
32
+
33
+ setup_default_config
34
+ assert_not_nil @worker.data_store(options)
35
+ end
36
+ should "provide a queue" do
37
+ queue = stub('queue')
38
+ queue_provider = stub('queue provider')
39
+ queue_provider.expects(:queue).with('a_queue').returns(queue)
40
+ @worker.expects(:queue_provider).returns(queue_provider)
41
+ assert_not_nil @worker.queue('a_queue')
42
+ end
43
+ end
44
+ end