surety 0.1.7
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.
- data/Gemfile +3 -0
 - data/Gemfile.lock +56 -0
 - data/LICENSE +20 -0
 - data/README.md +57 -0
 - data/Rakefile +15 -0
 - data/lib/generators/install_generator.rb +12 -0
 - data/lib/generators/templates/20120104151700_create_messages.rb +21 -0
 - data/lib/surety/configuration.rb +12 -0
 - data/lib/surety/generator.rb +14 -0
 - data/lib/surety/message.rb +78 -0
 - data/lib/surety/processor.rb +29 -0
 - data/lib/surety.rb +8 -0
 - data/surety.gemspec +26 -0
 - data/test/configuration_test.rb +13 -0
 - data/test/database.yml +13 -0
 - data/test/fixtures/test_delegate.rb +18 -0
 - data/test/fixtures/test_generator.rb +7 -0
 - data/test/generator_test.rb +26 -0
 - data/test/message_test.rb +284 -0
 - data/test/message_timezone_test.rb +57 -0
 - data/test/processor_test.rb +126 -0
 - data/test/redis-test.conf +132 -0
 - data/test/schema.rb +15 -0
 - data/test/test_helper.rb +70 -0
 - metadata +191 -0
 
    
        data/Gemfile
    ADDED
    
    
    
        data/Gemfile.lock
    ADDED
    
    | 
         @@ -0,0 +1,56 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            PATH
         
     | 
| 
      
 2 
     | 
    
         
            +
              remote: .
         
     | 
| 
      
 3 
     | 
    
         
            +
              specs:
         
     | 
| 
      
 4 
     | 
    
         
            +
                surety (0.1.0)
         
     | 
| 
      
 5 
     | 
    
         
            +
                  activerecord (>= 3.0)
         
     | 
| 
      
 6 
     | 
    
         
            +
                  activesupport (>= 3.0)
         
     | 
| 
      
 7 
     | 
    
         
            +
                  resque (>= 1.19.0)
         
     | 
| 
      
 8 
     | 
    
         
            +
                  state_machine (>= 1.0.0)
         
     | 
| 
      
 9 
     | 
    
         
            +
                  yajl-ruby (~> 0.8.2)
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
            GEM
         
     | 
| 
      
 12 
     | 
    
         
            +
              remote: http://rubygems.org/
         
     | 
| 
      
 13 
     | 
    
         
            +
              specs:
         
     | 
| 
      
 14 
     | 
    
         
            +
                activemodel (3.0.11)
         
     | 
| 
      
 15 
     | 
    
         
            +
                  activesupport (= 3.0.11)
         
     | 
| 
      
 16 
     | 
    
         
            +
                  builder (~> 2.1.2)
         
     | 
| 
      
 17 
     | 
    
         
            +
                  i18n (~> 0.5.0)
         
     | 
| 
      
 18 
     | 
    
         
            +
                activerecord (3.0.11)
         
     | 
| 
      
 19 
     | 
    
         
            +
                  activemodel (= 3.0.11)
         
     | 
| 
      
 20 
     | 
    
         
            +
                  activesupport (= 3.0.11)
         
     | 
| 
      
 21 
     | 
    
         
            +
                  arel (~> 2.0.10)
         
     | 
| 
      
 22 
     | 
    
         
            +
                  tzinfo (~> 0.3.23)
         
     | 
| 
      
 23 
     | 
    
         
            +
                activesupport (3.0.11)
         
     | 
| 
      
 24 
     | 
    
         
            +
                arel (2.0.10)
         
     | 
| 
      
 25 
     | 
    
         
            +
                builder (2.1.2)
         
     | 
| 
      
 26 
     | 
    
         
            +
                i18n (0.5.0)
         
     | 
| 
      
 27 
     | 
    
         
            +
                multi_json (1.0.4)
         
     | 
| 
      
 28 
     | 
    
         
            +
                mysql2 (0.2.7)
         
     | 
| 
      
 29 
     | 
    
         
            +
                rack (1.4.0)
         
     | 
| 
      
 30 
     | 
    
         
            +
                rack-protection (1.2.0)
         
     | 
| 
      
 31 
     | 
    
         
            +
                  rack
         
     | 
| 
      
 32 
     | 
    
         
            +
                redis (2.2.2)
         
     | 
| 
      
 33 
     | 
    
         
            +
                redis-namespace (1.0.3)
         
     | 
| 
      
 34 
     | 
    
         
            +
                  redis (< 3.0.0)
         
     | 
| 
      
 35 
     | 
    
         
            +
                resque (1.19.0)
         
     | 
| 
      
 36 
     | 
    
         
            +
                  multi_json (~> 1.0)
         
     | 
| 
      
 37 
     | 
    
         
            +
                  redis-namespace (~> 1.0.2)
         
     | 
| 
      
 38 
     | 
    
         
            +
                  sinatra (>= 0.9.2)
         
     | 
| 
      
 39 
     | 
    
         
            +
                  vegas (~> 0.1.2)
         
     | 
| 
      
 40 
     | 
    
         
            +
                sinatra (1.3.2)
         
     | 
| 
      
 41 
     | 
    
         
            +
                  rack (~> 1.3, >= 1.3.6)
         
     | 
| 
      
 42 
     | 
    
         
            +
                  rack-protection (~> 1.2)
         
     | 
| 
      
 43 
     | 
    
         
            +
                  tilt (~> 1.3, >= 1.3.3)
         
     | 
| 
      
 44 
     | 
    
         
            +
                state_machine (1.1.1)
         
     | 
| 
      
 45 
     | 
    
         
            +
                tilt (1.3.3)
         
     | 
| 
      
 46 
     | 
    
         
            +
                tzinfo (0.3.31)
         
     | 
| 
      
 47 
     | 
    
         
            +
                vegas (0.1.8)
         
     | 
| 
      
 48 
     | 
    
         
            +
                  rack (>= 1.0.0)
         
     | 
| 
      
 49 
     | 
    
         
            +
                yajl-ruby (0.8.3)
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
            PLATFORMS
         
     | 
| 
      
 52 
     | 
    
         
            +
              ruby
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
            DEPENDENCIES
         
     | 
| 
      
 55 
     | 
    
         
            +
              mysql2 (= 0.2.7)
         
     | 
| 
      
 56 
     | 
    
         
            +
              surety!
         
     | 
    
        data/LICENSE
    ADDED
    
    | 
         @@ -0,0 +1,20 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            Copyright (c) 2012 Monica McArthur
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            Permission is hereby granted, free of charge, to any person obtaining
         
     | 
| 
      
 4 
     | 
    
         
            +
            a copy of this software and associated documentation files (the
         
     | 
| 
      
 5 
     | 
    
         
            +
            "Software"), to deal in the Software without restriction, including
         
     | 
| 
      
 6 
     | 
    
         
            +
            without limitation the rights to use, copy, modify, merge, publish,
         
     | 
| 
      
 7 
     | 
    
         
            +
            distribute, sublicense, and/or sell copies of the Software, and to
         
     | 
| 
      
 8 
     | 
    
         
            +
            permit persons to whom the Software is furnished to do so, subject to
         
     | 
| 
      
 9 
     | 
    
         
            +
            the following conditions:
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
            The above copyright notice and this permission notice shall be
         
     | 
| 
      
 12 
     | 
    
         
            +
            included in all copies or substantial portions of the Software.
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
            THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
         
     | 
| 
      
 15 
     | 
    
         
            +
            EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
         
     | 
| 
      
 16 
     | 
    
         
            +
            MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
         
     | 
| 
      
 17 
     | 
    
         
            +
            NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
         
     | 
| 
      
 18 
     | 
    
         
            +
            LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
         
     | 
| 
      
 19 
     | 
    
         
            +
            OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
         
     | 
| 
      
 20 
     | 
    
         
            +
            WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
         
     | 
    
        data/README.md
    ADDED
    
    | 
         @@ -0,0 +1,57 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            Surety
         
     | 
| 
      
 2 
     | 
    
         
            +
            ============
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            A lightweight guaranteed-delivery messaging system.
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            Dependency Notes
         
     | 
| 
      
 8 
     | 
    
         
            +
            ================
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
            * Surety uses ActiveRecord to persist the message requests in order to provide transactional, guaranteed-delivery requests. Requires ActiveRecord 3.0.0 or higher.
         
     | 
| 
      
 11 
     | 
    
         
            +
            * Surety uses Resque to underpin the message processing/retry loop. Requires Resque 1.19.0 or higher.
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
            Usage / Examples
         
     | 
| 
      
 15 
     | 
    
         
            +
            ================
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
            A simple class that can send a message for guaranteed delivery:
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                class TestGenerator
         
     | 
| 
      
 20 
     | 
    
         
            +
                  include Surety::Generator
         
     | 
| 
      
 21 
     | 
    
         
            +
                
         
     | 
| 
      
 22 
     | 
    
         
            +
                  def some_method
         
     | 
| 
      
 23 
     | 
    
         
            +
                    self.send_message(message_content)
         
     | 
| 
      
 24 
     | 
    
         
            +
                  end
         
     | 
| 
      
 25 
     | 
    
         
            +
                end
         
     | 
| 
      
 26 
     | 
    
         
            +
                
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
            On the server side, to start up the loop to process messages:
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
              Surety::Processor.request_next
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                
         
     | 
| 
      
 33 
     | 
    
         
            +
            Configuration
         
     | 
| 
      
 34 
     | 
    
         
            +
            =============
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
            Both the prefix for the ActiveRecord database connection name (as specified in database.yml) and the class to which Surety delegates messages for processing after pulling them off the queue are configurable.
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
            Example configuration (from a sample config/initializers/surety.rb file)
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
            Surety::Configuration.database_prefix = 'surety_'
         
     | 
| 
      
 41 
     | 
    
         
            +
            Surety::Configuration.message_processing_delegate = MessageDistributor
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
            Install
         
     | 
| 
      
 45 
     | 
    
         
            +
            =======
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
            ### As a gem
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
                $ gem install surety
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
            Acknowledgements
         
     | 
| 
      
 53 
     | 
    
         
            +
            ================
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
            Copyright (c) 2012 Monica McArthur, released under the MIT license.
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
            Thanks to Ryan and Steve for arguing that this gem was necessary... it is.
         
     | 
    
        data/Rakefile
    ADDED
    
    | 
         @@ -0,0 +1,15 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'rake'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'rake/testtask'
         
     | 
| 
      
 3 
     | 
    
         
            +
            require 'bundler'
         
     | 
| 
      
 4 
     | 
    
         
            +
            Bundler::GemHelper.install_tasks
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            desc 'Default: run unit tests.'
         
     | 
| 
      
 7 
     | 
    
         
            +
            task :default => :test
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            desc 'Test the surety gem.'
         
     | 
| 
      
 10 
     | 
    
         
            +
            Rake::TestTask.new(:test) do |t|
         
     | 
| 
      
 11 
     | 
    
         
            +
              t.libs << 'lib'
         
     | 
| 
      
 12 
     | 
    
         
            +
              t.libs << 'test'
         
     | 
| 
      
 13 
     | 
    
         
            +
              t.pattern = 'test/**/*_test.rb'
         
     | 
| 
      
 14 
     | 
    
         
            +
              t.verbose = true
         
     | 
| 
      
 15 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,12 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'rails/generators'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Surety
         
     | 
| 
      
 4 
     | 
    
         
            +
              class InstallGenerator < Rails::Generators::Base
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
                source_root File.join(File.dirname(__FILE__), 'templates')
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                def manifest
         
     | 
| 
      
 9 
     | 
    
         
            +
                  copy_file "20120104151700_create_messages.rb", "db/migrate/20120104151700_create_messages.rb"
         
     | 
| 
      
 10 
     | 
    
         
            +
                end
         
     | 
| 
      
 11 
     | 
    
         
            +
              end
         
     | 
| 
      
 12 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,21 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            class CreateMessages < ActiveRecord::Migration
         
     | 
| 
      
 2 
     | 
    
         
            +
              def self.up
         
     | 
| 
      
 3 
     | 
    
         
            +
                create_table :messages do |t|
         
     | 
| 
      
 4 
     | 
    
         
            +
                  t.string :message_content
         
     | 
| 
      
 5 
     | 
    
         
            +
                  t.string :state
         
     | 
| 
      
 6 
     | 
    
         
            +
                  t.integer :processing_attempt_count, :default => 0
         
     | 
| 
      
 7 
     | 
    
         
            +
                  t.datetime :processing_started_at
         
     | 
| 
      
 8 
     | 
    
         
            +
                  t.datetime :completed_at
         
     | 
| 
      
 9 
     | 
    
         
            +
                  t.integer :failure_count, :default => 0
         
     | 
| 
      
 10 
     | 
    
         
            +
                  t.datetime :failed_at
         
     | 
| 
      
 11 
     | 
    
         
            +
                  t.text :last_exception
         
     | 
| 
      
 12 
     | 
    
         
            +
                  t.timestamps
         
     | 
| 
      
 13 
     | 
    
         
            +
                end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                add_index :messages, [:state, :failed_at]
         
     | 
| 
      
 16 
     | 
    
         
            +
              end
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
              def self.down
         
     | 
| 
      
 19 
     | 
    
         
            +
                drop_table :messages
         
     | 
| 
      
 20 
     | 
    
         
            +
              end
         
     | 
| 
      
 21 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,78 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Surety
         
     | 
| 
      
 2 
     | 
    
         
            +
              class Message < ActiveRecord::Base
         
     | 
| 
      
 3 
     | 
    
         
            +
                require 'state_machine'
         
     | 
| 
      
 4 
     | 
    
         
            +
                establish_connection Surety::Configuration.database
         
     | 
| 
      
 5 
     | 
    
         
            +
                
         
     | 
| 
      
 6 
     | 
    
         
            +
                scope :needs_processing, lambda {
         
     | 
| 
      
 7 
     | 
    
         
            +
                  puts ActiveRecord::Base.default_timezone
         
     | 
| 
      
 8 
     | 
    
         
            +
                  puts ActiveRecord::Base.default_timezone.to_s=='utc'
         
     | 
| 
      
 9 
     | 
    
         
            +
                  db_time = Time.now.send(ActiveRecord::Base.default_timezone.to_s=='utc' ? :utc : :localtime)
         
     | 
| 
      
 10 
     | 
    
         
            +
                  puts db_time
         
     | 
| 
      
 11 
     | 
    
         
            +
                  {:conditions=>"(messages.state='unprocessed') or (messages.state='failed' and messages.failed_at<'#{(db_time-10.minutes).strftime('%Y-%m-%d %H:%M:%S')}')",
         
     | 
| 
      
 12 
     | 
    
         
            +
                  :order => :created_at, :limit=>1}
         
     | 
| 
      
 13 
     | 
    
         
            +
                }
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                def self.generate_message(message_content)
         
     | 
| 
      
 16 
     | 
    
         
            +
                  self.create(:message_content=>message_content)
         
     | 
| 
      
 17 
     | 
    
         
            +
                end
         
     | 
| 
      
 18 
     | 
    
         
            +
                
         
     | 
| 
      
 19 
     | 
    
         
            +
                def self.get_next_for_processing
         
     | 
| 
      
 20 
     | 
    
         
            +
                  next_message = nil
         
     | 
| 
      
 21 
     | 
    
         
            +
                  ActiveRecord::Base.transaction do
         
     | 
| 
      
 22 
     | 
    
         
            +
                    next_message = self.needs_processing.first
         
     | 
| 
      
 23 
     | 
    
         
            +
                    next_message.begin_processing! if next_message
         
     | 
| 
      
 24 
     | 
    
         
            +
                  end
         
     | 
| 
      
 25 
     | 
    
         
            +
                  next_message
         
     | 
| 
      
 26 
     | 
    
         
            +
                end
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                state_machine :state, :initial => :unprocessed do
         
     | 
| 
      
 29 
     | 
    
         
            +
                  state :unprocessed
         
     | 
| 
      
 30 
     | 
    
         
            +
                  state :processing
         
     | 
| 
      
 31 
     | 
    
         
            +
                  state :completed
         
     | 
| 
      
 32 
     | 
    
         
            +
                  state :failed
         
     | 
| 
      
 33 
     | 
    
         
            +
                  
         
     | 
| 
      
 34 
     | 
    
         
            +
                  event :begin_processing do
         
     | 
| 
      
 35 
     | 
    
         
            +
                    transition [:unprocessed, :failed] => :processing
         
     | 
| 
      
 36 
     | 
    
         
            +
                  end
         
     | 
| 
      
 37 
     | 
    
         
            +
                  
         
     | 
| 
      
 38 
     | 
    
         
            +
                  event :complete_processing do
         
     | 
| 
      
 39 
     | 
    
         
            +
                    transition :processing => :completed
         
     | 
| 
      
 40 
     | 
    
         
            +
                  end
         
     | 
| 
      
 41 
     | 
    
         
            +
                  
         
     | 
| 
      
 42 
     | 
    
         
            +
                  event :fail_processing do
         
     | 
| 
      
 43 
     | 
    
         
            +
                    transition :processing => :failed
         
     | 
| 
      
 44 
     | 
    
         
            +
                  end
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
                  before_transition :on => :begin_processing, :do => :reserve
         
     | 
| 
      
 47 
     | 
    
         
            +
                  before_transition :on => :complete_processing, :do => :record_completion
         
     | 
| 
      
 48 
     | 
    
         
            +
                  before_transition :on => :fail_processing, :do => :record_failure
         
     | 
| 
      
 49 
     | 
    
         
            +
                end
         
     | 
| 
      
 50 
     | 
    
         
            +
                
         
     | 
| 
      
 51 
     | 
    
         
            +
                def reserve
         
     | 
| 
      
 52 
     | 
    
         
            +
                  self.processing_started_at = Time.now
         
     | 
| 
      
 53 
     | 
    
         
            +
                  self.processing_attempt_count = self.processing_attempt_count+1
         
     | 
| 
      
 54 
     | 
    
         
            +
                end
         
     | 
| 
      
 55 
     | 
    
         
            +
                
         
     | 
| 
      
 56 
     | 
    
         
            +
                def process
         
     | 
| 
      
 57 
     | 
    
         
            +
                  begin
         
     | 
| 
      
 58 
     | 
    
         
            +
                    Surety::Configuration.message_processing_delegate.process(self)
         
     | 
| 
      
 59 
     | 
    
         
            +
                    self.complete_processing!
         
     | 
| 
      
 60 
     | 
    
         
            +
                  rescue Exception => ex
         
     | 
| 
      
 61 
     | 
    
         
            +
                    self.last_exception = ex
         
     | 
| 
      
 62 
     | 
    
         
            +
                    self.fail_processing!
         
     | 
| 
      
 63 
     | 
    
         
            +
                    raise ex
         
     | 
| 
      
 64 
     | 
    
         
            +
                  end
         
     | 
| 
      
 65 
     | 
    
         
            +
                end
         
     | 
| 
      
 66 
     | 
    
         
            +
                
         
     | 
| 
      
 67 
     | 
    
         
            +
                def record_completion
         
     | 
| 
      
 68 
     | 
    
         
            +
                  self.completed_at = Time.now
         
     | 
| 
      
 69 
     | 
    
         
            +
                  self.last_exception = nil
         
     | 
| 
      
 70 
     | 
    
         
            +
                end
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
                def record_failure
         
     | 
| 
      
 73 
     | 
    
         
            +
                  self.failed_at = Time.now
         
     | 
| 
      
 74 
     | 
    
         
            +
                  self.failure_count = self.failure_count+1
         
     | 
| 
      
 75 
     | 
    
         
            +
                end
         
     | 
| 
      
 76 
     | 
    
         
            +
             
     | 
| 
      
 77 
     | 
    
         
            +
              end
         
     | 
| 
      
 78 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,29 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Surety
         
     | 
| 
      
 2 
     | 
    
         
            +
              class Processor
         
     | 
| 
      
 3 
     | 
    
         
            +
                
         
     | 
| 
      
 4 
     | 
    
         
            +
                @queue = :surety_messages
         
     | 
| 
      
 5 
     | 
    
         
            +
                
         
     | 
| 
      
 6 
     | 
    
         
            +
                def self.perform
         
     | 
| 
      
 7 
     | 
    
         
            +
                  message = nil
         
     | 
| 
      
 8 
     | 
    
         
            +
                  puts "[Surety::Processor]: Handling surety message"
         
     | 
| 
      
 9 
     | 
    
         
            +
                  begin
         
     | 
| 
      
 10 
     | 
    
         
            +
                    message = Surety::Message.get_next_for_processing
         
     | 
| 
      
 11 
     | 
    
         
            +
                    puts "[Surety::Processor]: Found message #{message.inspect}"
         
     | 
| 
      
 12 
     | 
    
         
            +
                    message.process if message
         
     | 
| 
      
 13 
     | 
    
         
            +
                  rescue Exception => ex
         
     | 
| 
      
 14 
     | 
    
         
            +
                    puts "[Surety::Processor]: error #{ex.to_s}"
         
     | 
| 
      
 15 
     | 
    
         
            +
                    puts "[Surety::Processor]: #{ex.backtrace.join("\n")}"
         
     | 
| 
      
 16 
     | 
    
         
            +
                    raise ex
         
     | 
| 
      
 17 
     | 
    
         
            +
                  ensure
         
     | 
| 
      
 18 
     | 
    
         
            +
                    sleep 5 if message.nil?
         
     | 
| 
      
 19 
     | 
    
         
            +
                    request_next
         
     | 
| 
      
 20 
     | 
    
         
            +
                  end
         
     | 
| 
      
 21 
     | 
    
         
            +
                    
         
     | 
| 
      
 22 
     | 
    
         
            +
                end
         
     | 
| 
      
 23 
     | 
    
         
            +
                
         
     | 
| 
      
 24 
     | 
    
         
            +
                def self.request_next
         
     | 
| 
      
 25 
     | 
    
         
            +
                  Resque.enqueue(self)
         
     | 
| 
      
 26 
     | 
    
         
            +
                end
         
     | 
| 
      
 27 
     | 
    
         
            +
                
         
     | 
| 
      
 28 
     | 
    
         
            +
              end
         
     | 
| 
      
 29 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/surety.rb
    ADDED
    
    
    
        data/surety.gemspec
    ADDED
    
    | 
         @@ -0,0 +1,26 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            Gem::Specification.new do |s|
         
     | 
| 
      
 2 
     | 
    
         
            +
              s.name              = 'surety'
         
     | 
| 
      
 3 
     | 
    
         
            +
              s.version           = '0.1.7'
         
     | 
| 
      
 4 
     | 
    
         
            +
              s.date              = Time.now.strftime('%Y-%m-%d')
         
     | 
| 
      
 5 
     | 
    
         
            +
              s.summary           = 'A lightweight guaranteed-delivery messaging system.'
         
     | 
| 
      
 6 
     | 
    
         
            +
              s.homepage          = ''
         
     | 
| 
      
 7 
     | 
    
         
            +
              s.email             = 'monica@revolutionprep.com'
         
     | 
| 
      
 8 
     | 
    
         
            +
              s.authors           = ['Monica McArthur']
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
              s.executables   = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
         
     | 
| 
      
 11 
     | 
    
         
            +
              s.files         = `git ls-files`.split("\n")
         
     | 
| 
      
 12 
     | 
    
         
            +
              s.test_files    = `git ls-files -- {test,spec,features}/*`.split("\n")
         
     | 
| 
      
 13 
     | 
    
         
            +
              s.require_paths = ['lib']
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
              s.add_dependency('yajl-ruby', '~> 0.8.2')
         
     | 
| 
      
 16 
     | 
    
         
            +
              s.add_dependency('resque', '>= 1.19.0')
         
     | 
| 
      
 17 
     | 
    
         
            +
              s.add_dependency('activesupport', '>= 3.0')
         
     | 
| 
      
 18 
     | 
    
         
            +
              s.add_dependency('activerecord', '>= 3.0')
         
     | 
| 
      
 19 
     | 
    
         
            +
              s.add_dependency('state_machine', '>=1.0.0')
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
              s.add_development_dependency('mysql2', '0.2.7')
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
              s.description       = <<-DESC
         
     | 
| 
      
 24 
     | 
    
         
            +
                A lightweight guaranteed-delivery messaging system.
         
     | 
| 
      
 25 
     | 
    
         
            +
              DESC
         
     | 
| 
      
 26 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,13 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require File.expand_path('test_helper.rb', File.dirname(__FILE__))
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            class ConfigurationTest < Test::Unit::TestCase
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
              def setup
         
     | 
| 
      
 6 
     | 
    
         
            +
                Surety::Configuration.database_prefix = 'surety_'
         
     | 
| 
      
 7 
     | 
    
         
            +
              end
         
     | 
| 
      
 8 
     | 
    
         
            +
              
         
     | 
| 
      
 9 
     | 
    
         
            +
              def test_database_configuration
         
     | 
| 
      
 10 
     | 
    
         
            +
                assert Surety::Configuration.database=='surety_test'
         
     | 
| 
      
 11 
     | 
    
         
            +
              end
         
     | 
| 
      
 12 
     | 
    
         
            +
              
         
     | 
| 
      
 13 
     | 
    
         
            +
            end
         
     | 
    
        data/test/database.yml
    ADDED
    
    
| 
         @@ -0,0 +1,18 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            class TestDelegate
         
     | 
| 
      
 2 
     | 
    
         
            +
              def self.process(message)
         
     | 
| 
      
 3 
     | 
    
         
            +
                #puts "processing #{message.inspect}"
         
     | 
| 
      
 4 
     | 
    
         
            +
                if message.message_content.match('Good')
         
     | 
| 
      
 5 
     | 
    
         
            +
                  @@processing_result = "Success processing #{message.message_content}"
         
     | 
| 
      
 6 
     | 
    
         
            +
                elsif message.message_content.match('Bad')
         
     | 
| 
      
 7 
     | 
    
         
            +
                  @@processing_result = "Failure processing #{message.message_content}"
         
     | 
| 
      
 8 
     | 
    
         
            +
                  raise Exception.new('opps')
         
     | 
| 
      
 9 
     | 
    
         
            +
                else
         
     | 
| 
      
 10 
     | 
    
         
            +
                  @@processing_result = 'What?'
         
     | 
| 
      
 11 
     | 
    
         
            +
                end
         
     | 
| 
      
 12 
     | 
    
         
            +
                #puts "result is #{@@processing_result}"
         
     | 
| 
      
 13 
     | 
    
         
            +
              end
         
     | 
| 
      
 14 
     | 
    
         
            +
              
         
     | 
| 
      
 15 
     | 
    
         
            +
              def self.processing_result
         
     | 
| 
      
 16 
     | 
    
         
            +
                @@processing_result
         
     | 
| 
      
 17 
     | 
    
         
            +
              end
         
     | 
| 
      
 18 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,26 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require File.expand_path('test_helper.rb', File.dirname(__FILE__))
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            class GeneratorTest < Test::Unit::TestCase
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
              def setup
         
     | 
| 
      
 6 
     | 
    
         
            +
                Surety::Configuration.database_prefix = 'surety_'
         
     | 
| 
      
 7 
     | 
    
         
            +
              end
         
     | 
| 
      
 8 
     | 
    
         
            +
              
         
     | 
| 
      
 9 
     | 
    
         
            +
              def test_message_generation
         
     | 
| 
      
 10 
     | 
    
         
            +
                TestGenerator.new.generate_test_message
         
     | 
| 
      
 11 
     | 
    
         
            +
                message = Surety::Message.first
         
     | 
| 
      
 12 
     | 
    
         
            +
                assert message.present?
         
     | 
| 
      
 13 
     | 
    
         
            +
                assert_message_matches(message, 
         
     | 
| 
      
 14 
     | 
    
         
            +
                  {
         
     | 
| 
      
 15 
     | 
    
         
            +
                    :message_content=>'This is a test',
         
     | 
| 
      
 16 
     | 
    
         
            +
                    :state => 'unprocessed',
         
     | 
| 
      
 17 
     | 
    
         
            +
                    :processing_attempt_count => 0,
         
     | 
| 
      
 18 
     | 
    
         
            +
                    :failure_count => 0,
         
     | 
| 
      
 19 
     | 
    
         
            +
                    :processing_started_at => nil,
         
     | 
| 
      
 20 
     | 
    
         
            +
                    :completed_at => nil,
         
     | 
| 
      
 21 
     | 
    
         
            +
                    :failed_at => nil,
         
     | 
| 
      
 22 
     | 
    
         
            +
                    :last_exception => nil
         
     | 
| 
      
 23 
     | 
    
         
            +
                  })
         
     | 
| 
      
 24 
     | 
    
         
            +
              end
         
     | 
| 
      
 25 
     | 
    
         
            +
              
         
     | 
| 
      
 26 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,284 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require File.expand_path('test_helper.rb', File.dirname(__FILE__))
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            class MessageTest < Test::Unit::TestCase
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
              def setup
         
     | 
| 
      
 6 
     | 
    
         
            +
                Surety::Configuration.database_prefix = 'surety_'
         
     | 
| 
      
 7 
     | 
    
         
            +
                @message = Surety::Message.generate_message('Testing message')
         
     | 
| 
      
 8 
     | 
    
         
            +
              end
         
     | 
| 
      
 9 
     | 
    
         
            +
              
         
     | 
| 
      
 10 
     | 
    
         
            +
              def test_database_name
         
     | 
| 
      
 11 
     | 
    
         
            +
                assert Surety::Message.new.connection.current_database=='surety_test'
         
     | 
| 
      
 12 
     | 
    
         
            +
              end
         
     | 
| 
      
 13 
     | 
    
         
            +
              
         
     | 
| 
      
 14 
     | 
    
         
            +
              def test_message_creation
         
     | 
| 
      
 15 
     | 
    
         
            +
                assert_message_matches(@message, 
         
     | 
| 
      
 16 
     | 
    
         
            +
                  {
         
     | 
| 
      
 17 
     | 
    
         
            +
                    :message_content=>'Testing message',
         
     | 
| 
      
 18 
     | 
    
         
            +
                    :state => 'unprocessed',
         
     | 
| 
      
 19 
     | 
    
         
            +
                    :processing_attempt_count => 0,
         
     | 
| 
      
 20 
     | 
    
         
            +
                    :failure_count => 0,
         
     | 
| 
      
 21 
     | 
    
         
            +
                    :processing_started_at => nil,
         
     | 
| 
      
 22 
     | 
    
         
            +
                    :completed_at => nil,
         
     | 
| 
      
 23 
     | 
    
         
            +
                    :failed_at => nil,
         
     | 
| 
      
 24 
     | 
    
         
            +
                    :last_exception => nil
         
     | 
| 
      
 25 
     | 
    
         
            +
                  })
         
     | 
| 
      
 26 
     | 
    
         
            +
              end
         
     | 
| 
      
 27 
     | 
    
         
            +
              
         
     | 
| 
      
 28 
     | 
    
         
            +
              def test_message_processing
         
     | 
| 
      
 29 
     | 
    
         
            +
                @message.begin_processing!
         
     | 
| 
      
 30 
     | 
    
         
            +
                assert_message_matches(@message, 
         
     | 
| 
      
 31 
     | 
    
         
            +
                  {
         
     | 
| 
      
 32 
     | 
    
         
            +
                    :message_content=>'Testing message',
         
     | 
| 
      
 33 
     | 
    
         
            +
                    :state => 'processing',
         
     | 
| 
      
 34 
     | 
    
         
            +
                    :processing_attempt_count => 1,
         
     | 
| 
      
 35 
     | 
    
         
            +
                    :failure_count => 0,
         
     | 
| 
      
 36 
     | 
    
         
            +
                    :completed_at => nil,
         
     | 
| 
      
 37 
     | 
    
         
            +
                    :failed_at => nil,
         
     | 
| 
      
 38 
     | 
    
         
            +
                    :last_exception => nil
         
     | 
| 
      
 39 
     | 
    
         
            +
                  })
         
     | 
| 
      
 40 
     | 
    
         
            +
                  assert_in_delta(@message.processing_started_at, Time.now, 5)
         
     | 
| 
      
 41 
     | 
    
         
            +
              end
         
     | 
| 
      
 42 
     | 
    
         
            +
                
         
     | 
| 
      
 43 
     | 
    
         
            +
              def test_message_completion
         
     | 
| 
      
 44 
     | 
    
         
            +
                @message.begin_processing!
         
     | 
| 
      
 45 
     | 
    
         
            +
                @message.complete_processing!
         
     | 
| 
      
 46 
     | 
    
         
            +
                assert_message_matches(@message, 
         
     | 
| 
      
 47 
     | 
    
         
            +
                  {
         
     | 
| 
      
 48 
     | 
    
         
            +
                    :message_content=>'Testing message',
         
     | 
| 
      
 49 
     | 
    
         
            +
                    :state => 'completed',
         
     | 
| 
      
 50 
     | 
    
         
            +
                    :processing_attempt_count => 1,
         
     | 
| 
      
 51 
     | 
    
         
            +
                    :failure_count => 0,
         
     | 
| 
      
 52 
     | 
    
         
            +
                    :failed_at => nil,
         
     | 
| 
      
 53 
     | 
    
         
            +
                    :last_exception => nil
         
     | 
| 
      
 54 
     | 
    
         
            +
                  })
         
     | 
| 
      
 55 
     | 
    
         
            +
                  assert_in_delta(@message.processing_started_at, Time.now, 5)
         
     | 
| 
      
 56 
     | 
    
         
            +
                  assert_in_delta(@message.completed_at, Time.now, 5)
         
     | 
| 
      
 57 
     | 
    
         
            +
              end
         
     | 
| 
      
 58 
     | 
    
         
            +
              
         
     | 
| 
      
 59 
     | 
    
         
            +
              def test_message_failure
         
     | 
| 
      
 60 
     | 
    
         
            +
                @message.begin_processing!
         
     | 
| 
      
 61 
     | 
    
         
            +
                @message.fail_processing!
         
     | 
| 
      
 62 
     | 
    
         
            +
                assert_message_matches(@message, 
         
     | 
| 
      
 63 
     | 
    
         
            +
                  {
         
     | 
| 
      
 64 
     | 
    
         
            +
                    :message_content=>'Testing message',
         
     | 
| 
      
 65 
     | 
    
         
            +
                    :state => 'failed',
         
     | 
| 
      
 66 
     | 
    
         
            +
                    :processing_attempt_count => 1,
         
     | 
| 
      
 67 
     | 
    
         
            +
                    :failure_count => 1,
         
     | 
| 
      
 68 
     | 
    
         
            +
                    :completed_at => nil,
         
     | 
| 
      
 69 
     | 
    
         
            +
                    :last_exception => nil
         
     | 
| 
      
 70 
     | 
    
         
            +
                  })
         
     | 
| 
      
 71 
     | 
    
         
            +
                  assert_in_delta(@message.processing_started_at, Time.now, 5)
         
     | 
| 
      
 72 
     | 
    
         
            +
                  assert_in_delta(@message.failed_at, Time.now, 5)
         
     | 
| 
      
 73 
     | 
    
         
            +
              end
         
     | 
| 
      
 74 
     | 
    
         
            +
              
         
     | 
| 
      
 75 
     | 
    
         
            +
              def test_message_retry
         
     | 
| 
      
 76 
     | 
    
         
            +
                @message.begin_processing!
         
     | 
| 
      
 77 
     | 
    
         
            +
                @message.fail_processing!
         
     | 
| 
      
 78 
     | 
    
         
            +
                message_first_fail = Time.now
         
     | 
| 
      
 79 
     | 
    
         
            +
                sleep(10)
         
     | 
| 
      
 80 
     | 
    
         
            +
                @message.begin_processing!
         
     | 
| 
      
 81 
     | 
    
         
            +
                @message.complete_processing!
         
     | 
| 
      
 82 
     | 
    
         
            +
                assert_message_matches(@message, 
         
     | 
| 
      
 83 
     | 
    
         
            +
                  {
         
     | 
| 
      
 84 
     | 
    
         
            +
                    :message_content=>'Testing message',
         
     | 
| 
      
 85 
     | 
    
         
            +
                    :state => 'completed',
         
     | 
| 
      
 86 
     | 
    
         
            +
                    :processing_attempt_count => 2,
         
     | 
| 
      
 87 
     | 
    
         
            +
                    :failure_count => 1,
         
     | 
| 
      
 88 
     | 
    
         
            +
                    :last_exception => nil
         
     | 
| 
      
 89 
     | 
    
         
            +
                  })
         
     | 
| 
      
 90 
     | 
    
         
            +
                  assert_in_delta(@message.processing_started_at, Time.now, 5)
         
     | 
| 
      
 91 
     | 
    
         
            +
                  assert_in_delta(@message.completed_at, Time.now, 5)
         
     | 
| 
      
 92 
     | 
    
         
            +
                  assert_in_delta(@message.failed_at, message_first_fail, 5)
         
     | 
| 
      
 93 
     | 
    
         
            +
              end
         
     | 
| 
      
 94 
     | 
    
         
            +
              
         
     | 
| 
      
 95 
     | 
    
         
            +
              def test_bad_transitions
         
     | 
| 
      
 96 
     | 
    
         
            +
                assert_raise(StateMachine::InvalidTransition) {
         
     | 
| 
      
 97 
     | 
    
         
            +
                  @message.fail_processing!
         
     | 
| 
      
 98 
     | 
    
         
            +
                }
         
     | 
| 
      
 99 
     | 
    
         
            +
                assert_raise(StateMachine::InvalidTransition) {
         
     | 
| 
      
 100 
     | 
    
         
            +
                  @message.complete_processing!
         
     | 
| 
      
 101 
     | 
    
         
            +
                }
         
     | 
| 
      
 102 
     | 
    
         
            +
                @message.begin_processing!
         
     | 
| 
      
 103 
     | 
    
         
            +
                @message.fail_processing!
         
     | 
| 
      
 104 
     | 
    
         
            +
                assert_raise(StateMachine::InvalidTransition) {
         
     | 
| 
      
 105 
     | 
    
         
            +
                  @message.complete_processing!
         
     | 
| 
      
 106 
     | 
    
         
            +
                }
         
     | 
| 
      
 107 
     | 
    
         
            +
                @message.begin_processing!
         
     | 
| 
      
 108 
     | 
    
         
            +
                @message.complete_processing!
         
     | 
| 
      
 109 
     | 
    
         
            +
                assert_raise(StateMachine::InvalidTransition) {
         
     | 
| 
      
 110 
     | 
    
         
            +
                  @message.fail_processing!
         
     | 
| 
      
 111 
     | 
    
         
            +
                }
         
     | 
| 
      
 112 
     | 
    
         
            +
                assert_raise(StateMachine::InvalidTransition) {
         
     | 
| 
      
 113 
     | 
    
         
            +
                  @message.complete_processing!
         
     | 
| 
      
 114 
     | 
    
         
            +
                }
         
     | 
| 
      
 115 
     | 
    
         
            +
                assert_raise(StateMachine::InvalidTransition) {
         
     | 
| 
      
 116 
     | 
    
         
            +
                  @message.begin_processing!
         
     | 
| 
      
 117 
     | 
    
         
            +
                }
         
     | 
| 
      
 118 
     | 
    
         
            +
              end
         
     | 
| 
      
 119 
     | 
    
         
            +
              
         
     | 
| 
      
 120 
     | 
    
         
            +
              def test_needs_processing
         
     | 
| 
      
 121 
     | 
    
         
            +
                Surety::Message.new.connection.execute("truncate table messages")
         
     | 
| 
      
 122 
     | 
    
         
            +
                @message1 = Surety::Message.generate_message('Message 1')
         
     | 
| 
      
 123 
     | 
    
         
            +
                @message2 = Surety::Message.generate_message('Message 2')
         
     | 
| 
      
 124 
     | 
    
         
            +
                @message3 = Surety::Message.generate_message('Message 3')
         
     | 
| 
      
 125 
     | 
    
         
            +
                @message4 = Surety::Message.generate_message('Message 4')
         
     | 
| 
      
 126 
     | 
    
         
            +
                @message5 = Surety::Message.generate_message('Message 5')
         
     | 
| 
      
 127 
     | 
    
         
            +
                @message6 = Surety::Message.generate_message('Message 6')
         
     | 
| 
      
 128 
     | 
    
         
            +
                message = Surety::Message.needs_processing.first
         
     | 
| 
      
 129 
     | 
    
         
            +
                message.begin_processing!
         
     | 
| 
      
 130 
     | 
    
         
            +
                assert message.present?
         
     | 
| 
      
 131 
     | 
    
         
            +
                assert_message_matches(message, {
         
     | 
| 
      
 132 
     | 
    
         
            +
                  :message_content=>'Message 1',
         
     | 
| 
      
 133 
     | 
    
         
            +
                  :state => 'processing',
         
     | 
| 
      
 134 
     | 
    
         
            +
                  :processing_attempt_count => 1,
         
     | 
| 
      
 135 
     | 
    
         
            +
                  :failure_count => 0,
         
     | 
| 
      
 136 
     | 
    
         
            +
                  :completed_at => nil,
         
     | 
| 
      
 137 
     | 
    
         
            +
                  :failed_at => nil,
         
     | 
| 
      
 138 
     | 
    
         
            +
                  :last_exception => nil
         
     | 
| 
      
 139 
     | 
    
         
            +
                })
         
     | 
| 
      
 140 
     | 
    
         
            +
                assert_in_delta(message.processing_started_at, Time.now, 5)
         
     | 
| 
      
 141 
     | 
    
         
            +
                message = Surety::Message.needs_processing.first
         
     | 
| 
      
 142 
     | 
    
         
            +
                message.begin_processing!
         
     | 
| 
      
 143 
     | 
    
         
            +
                assert message.present?
         
     | 
| 
      
 144 
     | 
    
         
            +
                assert_message_matches(message, {
         
     | 
| 
      
 145 
     | 
    
         
            +
                  :message_content=>'Message 2',
         
     | 
| 
      
 146 
     | 
    
         
            +
                  :state => 'processing',
         
     | 
| 
      
 147 
     | 
    
         
            +
                  :processing_attempt_count => 1,
         
     | 
| 
      
 148 
     | 
    
         
            +
                  :failure_count => 0,
         
     | 
| 
      
 149 
     | 
    
         
            +
                  :completed_at => nil,
         
     | 
| 
      
 150 
     | 
    
         
            +
                  :failed_at => nil,
         
     | 
| 
      
 151 
     | 
    
         
            +
                  :last_exception => nil
         
     | 
| 
      
 152 
     | 
    
         
            +
                })
         
     | 
| 
      
 153 
     | 
    
         
            +
                assert_in_delta(message.processing_started_at, Time.now, 5)
         
     | 
| 
      
 154 
     | 
    
         
            +
                @message3.begin_processing!
         
     | 
| 
      
 155 
     | 
    
         
            +
                @message3.complete_processing!
         
     | 
| 
      
 156 
     | 
    
         
            +
                message = Surety::Message.needs_processing.first
         
     | 
| 
      
 157 
     | 
    
         
            +
                message.begin_processing!
         
     | 
| 
      
 158 
     | 
    
         
            +
                assert message.present?
         
     | 
| 
      
 159 
     | 
    
         
            +
                assert_message_matches(message, {
         
     | 
| 
      
 160 
     | 
    
         
            +
                  :message_content=>'Message 4',
         
     | 
| 
      
 161 
     | 
    
         
            +
                  :state => 'processing',
         
     | 
| 
      
 162 
     | 
    
         
            +
                  :processing_attempt_count => 1,
         
     | 
| 
      
 163 
     | 
    
         
            +
                  :failure_count => 0,
         
     | 
| 
      
 164 
     | 
    
         
            +
                  :completed_at => nil,
         
     | 
| 
      
 165 
     | 
    
         
            +
                  :failed_at => nil,
         
     | 
| 
      
 166 
     | 
    
         
            +
                  :last_exception => nil
         
     | 
| 
      
 167 
     | 
    
         
            +
                })
         
     | 
| 
      
 168 
     | 
    
         
            +
                assert_in_delta(message.processing_started_at, Time.now, 5)
         
     | 
| 
      
 169 
     | 
    
         
            +
                @message1.reload
         
     | 
| 
      
 170 
     | 
    
         
            +
                @message1.fail_processing!
         
     | 
| 
      
 171 
     | 
    
         
            +
                message = Surety::Message.needs_processing.first
         
     | 
| 
      
 172 
     | 
    
         
            +
                message.begin_processing!
         
     | 
| 
      
 173 
     | 
    
         
            +
                assert message.present?
         
     | 
| 
      
 174 
     | 
    
         
            +
                assert_message_matches(message, {
         
     | 
| 
      
 175 
     | 
    
         
            +
                  :message_content=>'Message 5',
         
     | 
| 
      
 176 
     | 
    
         
            +
                  :state => 'processing',
         
     | 
| 
      
 177 
     | 
    
         
            +
                  :processing_attempt_count => 1,
         
     | 
| 
      
 178 
     | 
    
         
            +
                  :failure_count => 0,
         
     | 
| 
      
 179 
     | 
    
         
            +
                  :completed_at => nil,
         
     | 
| 
      
 180 
     | 
    
         
            +
                  :failed_at => nil,
         
     | 
| 
      
 181 
     | 
    
         
            +
                  :last_exception => nil
         
     | 
| 
      
 182 
     | 
    
         
            +
                })
         
     | 
| 
      
 183 
     | 
    
         
            +
                assert_in_delta(message.processing_started_at, Time.now, 5)
         
     | 
| 
      
 184 
     | 
    
         
            +
                @message1.failed_at = Time.now-40.minutes
         
     | 
| 
      
 185 
     | 
    
         
            +
                @message1.save
         
     | 
| 
      
 186 
     | 
    
         
            +
                message = Surety::Message.needs_processing.first
         
     | 
| 
      
 187 
     | 
    
         
            +
                message.begin_processing!
         
     | 
| 
      
 188 
     | 
    
         
            +
                assert message.present?
         
     | 
| 
      
 189 
     | 
    
         
            +
                assert_message_matches(message, {
         
     | 
| 
      
 190 
     | 
    
         
            +
                  :message_content=>'Message 1',
         
     | 
| 
      
 191 
     | 
    
         
            +
                  :state => 'processing',
         
     | 
| 
      
 192 
     | 
    
         
            +
                  :processing_attempt_count => 2,
         
     | 
| 
      
 193 
     | 
    
         
            +
                  :failure_count => 1,
         
     | 
| 
      
 194 
     | 
    
         
            +
                  :completed_at => nil,
         
     | 
| 
      
 195 
     | 
    
         
            +
                  :last_exception => nil
         
     | 
| 
      
 196 
     | 
    
         
            +
                })
         
     | 
| 
      
 197 
     | 
    
         
            +
                assert_in_delta(message.processing_started_at, Time.now, 5)
         
     | 
| 
      
 198 
     | 
    
         
            +
              end
         
     | 
| 
      
 199 
     | 
    
         
            +
              
         
     | 
| 
      
 200 
     | 
    
         
            +
              def test_gets_next_for_processing
         
     | 
| 
      
 201 
     | 
    
         
            +
                Surety::Message.new.connection.execute("truncate table messages")
         
     | 
| 
      
 202 
     | 
    
         
            +
                @message1 = Surety::Message.generate_message('Message 1')
         
     | 
| 
      
 203 
     | 
    
         
            +
                @message2 = Surety::Message.generate_message('Message 2')
         
     | 
| 
      
 204 
     | 
    
         
            +
                @message3 = Surety::Message.generate_message('Message 3')
         
     | 
| 
      
 205 
     | 
    
         
            +
                @message4 = Surety::Message.generate_message('Message 4')
         
     | 
| 
      
 206 
     | 
    
         
            +
                @message5 = Surety::Message.generate_message('Message 5')
         
     | 
| 
      
 207 
     | 
    
         
            +
                @message6 = Surety::Message.generate_message('Message 6')
         
     | 
| 
      
 208 
     | 
    
         
            +
                message = Surety::Message.get_next_for_processing
         
     | 
| 
      
 209 
     | 
    
         
            +
                assert message.present?
         
     | 
| 
      
 210 
     | 
    
         
            +
                assert_message_matches(message, {
         
     | 
| 
      
 211 
     | 
    
         
            +
                  :message_content=>'Message 1',
         
     | 
| 
      
 212 
     | 
    
         
            +
                  :state => 'processing',
         
     | 
| 
      
 213 
     | 
    
         
            +
                  :processing_attempt_count => 1,
         
     | 
| 
      
 214 
     | 
    
         
            +
                  :failure_count => 0,
         
     | 
| 
      
 215 
     | 
    
         
            +
                  :completed_at => nil,
         
     | 
| 
      
 216 
     | 
    
         
            +
                  :failed_at => nil,
         
     | 
| 
      
 217 
     | 
    
         
            +
                  :last_exception => nil
         
     | 
| 
      
 218 
     | 
    
         
            +
                })
         
     | 
| 
      
 219 
     | 
    
         
            +
                assert_in_delta(message.processing_started_at, Time.now, 5)
         
     | 
| 
      
 220 
     | 
    
         
            +
                message = Surety::Message.get_next_for_processing
         
     | 
| 
      
 221 
     | 
    
         
            +
                assert message.present?
         
     | 
| 
      
 222 
     | 
    
         
            +
                assert_message_matches(message, {
         
     | 
| 
      
 223 
     | 
    
         
            +
                  :message_content=>'Message 2',
         
     | 
| 
      
 224 
     | 
    
         
            +
                  :state => 'processing',
         
     | 
| 
      
 225 
     | 
    
         
            +
                  :processing_attempt_count => 1,
         
     | 
| 
      
 226 
     | 
    
         
            +
                  :failure_count => 0,
         
     | 
| 
      
 227 
     | 
    
         
            +
                  :completed_at => nil,
         
     | 
| 
      
 228 
     | 
    
         
            +
                  :failed_at => nil,
         
     | 
| 
      
 229 
     | 
    
         
            +
                  :last_exception => nil
         
     | 
| 
      
 230 
     | 
    
         
            +
                })
         
     | 
| 
      
 231 
     | 
    
         
            +
                assert_in_delta(message.processing_started_at, Time.now, 5)
         
     | 
| 
      
 232 
     | 
    
         
            +
                @message3.begin_processing!
         
     | 
| 
      
 233 
     | 
    
         
            +
                @message3.complete_processing!
         
     | 
| 
      
 234 
     | 
    
         
            +
                message = Surety::Message.get_next_for_processing
         
     | 
| 
      
 235 
     | 
    
         
            +
                assert message.present?
         
     | 
| 
      
 236 
     | 
    
         
            +
                assert_message_matches(message, {
         
     | 
| 
      
 237 
     | 
    
         
            +
                  :message_content=>'Message 4',
         
     | 
| 
      
 238 
     | 
    
         
            +
                  :state => 'processing',
         
     | 
| 
      
 239 
     | 
    
         
            +
                  :processing_attempt_count => 1,
         
     | 
| 
      
 240 
     | 
    
         
            +
                  :failure_count => 0,
         
     | 
| 
      
 241 
     | 
    
         
            +
                  :completed_at => nil,
         
     | 
| 
      
 242 
     | 
    
         
            +
                  :failed_at => nil,
         
     | 
| 
      
 243 
     | 
    
         
            +
                  :last_exception => nil
         
     | 
| 
      
 244 
     | 
    
         
            +
                })
         
     | 
| 
      
 245 
     | 
    
         
            +
                assert_in_delta(message.processing_started_at, Time.now, 5)
         
     | 
| 
      
 246 
     | 
    
         
            +
                @message1.reload
         
     | 
| 
      
 247 
     | 
    
         
            +
                @message1.fail_processing!
         
     | 
| 
      
 248 
     | 
    
         
            +
                message = Surety::Message.get_next_for_processing
         
     | 
| 
      
 249 
     | 
    
         
            +
                assert message.present?
         
     | 
| 
      
 250 
     | 
    
         
            +
                assert_message_matches(message, {
         
     | 
| 
      
 251 
     | 
    
         
            +
                  :message_content=>'Message 5',
         
     | 
| 
      
 252 
     | 
    
         
            +
                  :state => 'processing',
         
     | 
| 
      
 253 
     | 
    
         
            +
                  :processing_attempt_count => 1,
         
     | 
| 
      
 254 
     | 
    
         
            +
                  :failure_count => 0,
         
     | 
| 
      
 255 
     | 
    
         
            +
                  :completed_at => nil,
         
     | 
| 
      
 256 
     | 
    
         
            +
                  :failed_at => nil,
         
     | 
| 
      
 257 
     | 
    
         
            +
                  :last_exception => nil
         
     | 
| 
      
 258 
     | 
    
         
            +
                })
         
     | 
| 
      
 259 
     | 
    
         
            +
                assert_in_delta(message.processing_started_at, Time.now, 5)
         
     | 
| 
      
 260 
     | 
    
         
            +
                @message1.failed_at = Time.now-40.minutes
         
     | 
| 
      
 261 
     | 
    
         
            +
                @message1.save
         
     | 
| 
      
 262 
     | 
    
         
            +
                message = Surety::Message.get_next_for_processing
         
     | 
| 
      
 263 
     | 
    
         
            +
                assert message.present?
         
     | 
| 
      
 264 
     | 
    
         
            +
                assert_message_matches(message, {
         
     | 
| 
      
 265 
     | 
    
         
            +
                  :message_content=>'Message 1',
         
     | 
| 
      
 266 
     | 
    
         
            +
                  :state => 'processing',
         
     | 
| 
      
 267 
     | 
    
         
            +
                  :processing_attempt_count => 2,
         
     | 
| 
      
 268 
     | 
    
         
            +
                  :failure_count => 1,
         
     | 
| 
      
 269 
     | 
    
         
            +
                  :completed_at => nil,
         
     | 
| 
      
 270 
     | 
    
         
            +
                  :last_exception => nil
         
     | 
| 
      
 271 
     | 
    
         
            +
                })
         
     | 
| 
      
 272 
     | 
    
         
            +
                assert_in_delta(message.processing_started_at, Time.now, 5)
         
     | 
| 
      
 273 
     | 
    
         
            +
              end
         
     | 
| 
      
 274 
     | 
    
         
            +
              
         
     | 
| 
      
 275 
     | 
    
         
            +
              def test_no_next_message
         
     | 
| 
      
 276 
     | 
    
         
            +
                Surety::Message.new.connection.execute("truncate table messages")
         
     | 
| 
      
 277 
     | 
    
         
            +
                @message1 = Surety::Message.generate_message('Message 1')
         
     | 
| 
      
 278 
     | 
    
         
            +
                @message1.begin_processing!
         
     | 
| 
      
 279 
     | 
    
         
            +
                @message1.complete_processing!
         
     | 
| 
      
 280 
     | 
    
         
            +
                message = Surety::Message.get_next_for_processing
         
     | 
| 
      
 281 
     | 
    
         
            +
                assert message.nil?
         
     | 
| 
      
 282 
     | 
    
         
            +
              end
         
     | 
| 
      
 283 
     | 
    
         
            +
              
         
     | 
| 
      
 284 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,57 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require File.expand_path('test_helper.rb', File.dirname(__FILE__))
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            class MessageTimezoneTest < Test::Unit::TestCase
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
              def setup
         
     | 
| 
      
 6 
     | 
    
         
            +
                Surety::Configuration.database_prefix = 'surety_'
         
     | 
| 
      
 7 
     | 
    
         
            +
                ActiveRecord::Base.default_timezone = :utc
         
     | 
| 
      
 8 
     | 
    
         
            +
                @message = Surety::Message.generate_message('Testing message')
         
     | 
| 
      
 9 
     | 
    
         
            +
              end
         
     | 
| 
      
 10 
     | 
    
         
            +
              
         
     | 
| 
      
 11 
     | 
    
         
            +
              def test_needs_processing_failure_timeout_when_active_record_using_utc
         
     | 
| 
      
 12 
     | 
    
         
            +
                Surety::Message.new.connection.execute("truncate table messages")
         
     | 
| 
      
 13 
     | 
    
         
            +
                @message1 = Surety::Message.generate_message('Message 1')
         
     | 
| 
      
 14 
     | 
    
         
            +
                @message2 = Surety::Message.generate_message('Message 2')
         
     | 
| 
      
 15 
     | 
    
         
            +
                message = Surety::Message.needs_processing.first
         
     | 
| 
      
 16 
     | 
    
         
            +
                message.begin_processing!
         
     | 
| 
      
 17 
     | 
    
         
            +
                assert message.present?
         
     | 
| 
      
 18 
     | 
    
         
            +
                assert_message_matches(message, {
         
     | 
| 
      
 19 
     | 
    
         
            +
                  :message_content=>'Message 1',
         
     | 
| 
      
 20 
     | 
    
         
            +
                  :state => 'processing',
         
     | 
| 
      
 21 
     | 
    
         
            +
                  :processing_attempt_count => 1,
         
     | 
| 
      
 22 
     | 
    
         
            +
                  :failure_count => 0,
         
     | 
| 
      
 23 
     | 
    
         
            +
                  :completed_at => nil,
         
     | 
| 
      
 24 
     | 
    
         
            +
                  :failed_at => nil,
         
     | 
| 
      
 25 
     | 
    
         
            +
                  :last_exception => nil
         
     | 
| 
      
 26 
     | 
    
         
            +
                })
         
     | 
| 
      
 27 
     | 
    
         
            +
                assert_in_delta(message.processing_started_at, Time.now, 5)
         
     | 
| 
      
 28 
     | 
    
         
            +
                @message1.reload
         
     | 
| 
      
 29 
     | 
    
         
            +
                @message1.fail_processing!
         
     | 
| 
      
 30 
     | 
    
         
            +
                message = Surety::Message.get_next_for_processing
         
     | 
| 
      
 31 
     | 
    
         
            +
                assert message.present?
         
     | 
| 
      
 32 
     | 
    
         
            +
                assert_message_matches(message, {
         
     | 
| 
      
 33 
     | 
    
         
            +
                  :message_content=>'Message 2',
         
     | 
| 
      
 34 
     | 
    
         
            +
                  :state => 'processing',
         
     | 
| 
      
 35 
     | 
    
         
            +
                  :processing_attempt_count => 1,
         
     | 
| 
      
 36 
     | 
    
         
            +
                  :failure_count => 0,
         
     | 
| 
      
 37 
     | 
    
         
            +
                  :completed_at => nil,
         
     | 
| 
      
 38 
     | 
    
         
            +
                  :failed_at => nil,
         
     | 
| 
      
 39 
     | 
    
         
            +
                  :last_exception => nil
         
     | 
| 
      
 40 
     | 
    
         
            +
                })
         
     | 
| 
      
 41 
     | 
    
         
            +
                assert_in_delta(message.processing_started_at, Time.now, 5)
         
     | 
| 
      
 42 
     | 
    
         
            +
                @message1.failed_at = Time.now-40.minutes
         
     | 
| 
      
 43 
     | 
    
         
            +
                @message1.save
         
     | 
| 
      
 44 
     | 
    
         
            +
                message = Surety::Message.get_next_for_processing
         
     | 
| 
      
 45 
     | 
    
         
            +
                assert message.present?
         
     | 
| 
      
 46 
     | 
    
         
            +
                assert_message_matches(message, {
         
     | 
| 
      
 47 
     | 
    
         
            +
                  :message_content=>'Message 1',
         
     | 
| 
      
 48 
     | 
    
         
            +
                  :state => 'processing',
         
     | 
| 
      
 49 
     | 
    
         
            +
                  :processing_attempt_count => 2,
         
     | 
| 
      
 50 
     | 
    
         
            +
                  :failure_count => 1,
         
     | 
| 
      
 51 
     | 
    
         
            +
                  :completed_at => nil,
         
     | 
| 
      
 52 
     | 
    
         
            +
                  :last_exception => nil
         
     | 
| 
      
 53 
     | 
    
         
            +
                })
         
     | 
| 
      
 54 
     | 
    
         
            +
                assert_in_delta(message.processing_started_at, Time.now, 5)
         
     | 
| 
      
 55 
     | 
    
         
            +
              end
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,126 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require File.expand_path('test_helper.rb', File.dirname(__FILE__))
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            class ProcessorTest < Test::Unit::TestCase
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
              def setup
         
     | 
| 
      
 6 
     | 
    
         
            +
                $success = $lock_failed = $lock_expired = 0
         
     | 
| 
      
 7 
     | 
    
         
            +
                Resque.redis.namespace = nil
         
     | 
| 
      
 8 
     | 
    
         
            +
                Resque.redis.flushall
         
     | 
| 
      
 9 
     | 
    
         
            +
                Resque.redis.namespace = 'test_surety'
         
     | 
| 
      
 10 
     | 
    
         
            +
                Surety::Configuration.database_prefix = 'surety_'
         
     | 
| 
      
 11 
     | 
    
         
            +
                Surety::Configuration.message_processing_delegate = TestDelegate
         
     | 
| 
      
 12 
     | 
    
         
            +
              end
         
     | 
| 
      
 13 
     | 
    
         
            +
              
         
     | 
| 
      
 14 
     | 
    
         
            +
              def test_request_next
         
     | 
| 
      
 15 
     | 
    
         
            +
                Surety::Processor.request_next
         
     | 
| 
      
 16 
     | 
    
         
            +
                assert Resque.redis.llen('queue:surety_messages')==1
         
     | 
| 
      
 17 
     | 
    
         
            +
              end
         
     | 
| 
      
 18 
     | 
    
         
            +
              
         
     | 
| 
      
 19 
     | 
    
         
            +
              def test_perform_successful
         
     | 
| 
      
 20 
     | 
    
         
            +
                Surety::Message.new.connection.execute("truncate table messages")
         
     | 
| 
      
 21 
     | 
    
         
            +
                @message1 = Surety::Message.generate_message('Good Message 1')
         
     | 
| 
      
 22 
     | 
    
         
            +
                @message2 = Surety::Message.generate_message('Message 2')
         
     | 
| 
      
 23 
     | 
    
         
            +
                Surety::Processor.request_next
         
     | 
| 
      
 24 
     | 
    
         
            +
                Resque::Worker.new(:surety_messages).process
         
     | 
| 
      
 25 
     | 
    
         
            +
                @message1.reload
         
     | 
| 
      
 26 
     | 
    
         
            +
                assert_message_matches(@message1, 
         
     | 
| 
      
 27 
     | 
    
         
            +
                  {
         
     | 
| 
      
 28 
     | 
    
         
            +
                    :message_content=>'Good Message 1',
         
     | 
| 
      
 29 
     | 
    
         
            +
                    :state => 'completed',
         
     | 
| 
      
 30 
     | 
    
         
            +
                    :processing_attempt_count => 1,
         
     | 
| 
      
 31 
     | 
    
         
            +
                    :failure_count => 0,
         
     | 
| 
      
 32 
     | 
    
         
            +
                    :failed_at => nil,
         
     | 
| 
      
 33 
     | 
    
         
            +
                    :last_exception => nil
         
     | 
| 
      
 34 
     | 
    
         
            +
                  })
         
     | 
| 
      
 35 
     | 
    
         
            +
                assert_in_delta(@message1.processing_started_at, Time.now, 5)
         
     | 
| 
      
 36 
     | 
    
         
            +
                assert_in_delta(@message1.completed_at, Time.now, 5)
         
     | 
| 
      
 37 
     | 
    
         
            +
                assert TestDelegate.processing_result=='Success processing Good Message 1'
         
     | 
| 
      
 38 
     | 
    
         
            +
                assert Resque.redis.llen('queue:surety_messages')==1
         
     | 
| 
      
 39 
     | 
    
         
            +
              end
         
     | 
| 
      
 40 
     | 
    
         
            +
              
         
     | 
| 
      
 41 
     | 
    
         
            +
              def test_perform_fail
         
     | 
| 
      
 42 
     | 
    
         
            +
                Surety::Message.new.connection.execute("truncate table messages")
         
     | 
| 
      
 43 
     | 
    
         
            +
                @message1 = Surety::Message.generate_message('Bad Message 1')
         
     | 
| 
      
 44 
     | 
    
         
            +
                @message2 = Surety::Message.generate_message('Message 2')
         
     | 
| 
      
 45 
     | 
    
         
            +
                Surety::Processor.request_next
         
     | 
| 
      
 46 
     | 
    
         
            +
                Resque::Worker.new(:surety_messages).process
         
     | 
| 
      
 47 
     | 
    
         
            +
                @message1.reload
         
     | 
| 
      
 48 
     | 
    
         
            +
                assert_message_matches(@message1, 
         
     | 
| 
      
 49 
     | 
    
         
            +
                  {
         
     | 
| 
      
 50 
     | 
    
         
            +
                    :message_content=>'Bad Message 1',
         
     | 
| 
      
 51 
     | 
    
         
            +
                    :state => 'failed',
         
     | 
| 
      
 52 
     | 
    
         
            +
                    :processing_attempt_count => 1,
         
     | 
| 
      
 53 
     | 
    
         
            +
                    :failure_count => 1,
         
     | 
| 
      
 54 
     | 
    
         
            +
                    :completed_at => nil,
         
     | 
| 
      
 55 
     | 
    
         
            +
                  })
         
     | 
| 
      
 56 
     | 
    
         
            +
                assert_in_delta(@message1.processing_started_at, Time.now, 5)
         
     | 
| 
      
 57 
     | 
    
         
            +
                assert_in_delta(@message1.failed_at, Time.now, 5)
         
     | 
| 
      
 58 
     | 
    
         
            +
                assert @message1.last_exception.present?
         
     | 
| 
      
 59 
     | 
    
         
            +
                assert TestDelegate.processing_result=='Failure processing Bad Message 1'
         
     | 
| 
      
 60 
     | 
    
         
            +
                assert Resque.redis.llen('queue:surety_messages')==1
         
     | 
| 
      
 61 
     | 
    
         
            +
              end
         
     | 
| 
      
 62 
     | 
    
         
            +
              
         
     | 
| 
      
 63 
     | 
    
         
            +
              def test_perform_multiple
         
     | 
| 
      
 64 
     | 
    
         
            +
                Surety::Message.new.connection.execute("truncate table messages")
         
     | 
| 
      
 65 
     | 
    
         
            +
                @message1 = Surety::Message.generate_message('Good Message 1')
         
     | 
| 
      
 66 
     | 
    
         
            +
                @message2 = Surety::Message.generate_message('Bad Message 2')
         
     | 
| 
      
 67 
     | 
    
         
            +
                @message3 = Surety::Message.generate_message('Good Message 3')
         
     | 
| 
      
 68 
     | 
    
         
            +
                @message4 = Surety::Message.generate_message('Left Alone Message 4')
         
     | 
| 
      
 69 
     | 
    
         
            +
                Surety::Processor.request_next
         
     | 
| 
      
 70 
     | 
    
         
            +
                Resque::Worker.new(:surety_messages).process
         
     | 
| 
      
 71 
     | 
    
         
            +
                assert TestDelegate.processing_result=='Success processing Good Message 1'
         
     | 
| 
      
 72 
     | 
    
         
            +
                Resque::Worker.new(:surety_messages).process
         
     | 
| 
      
 73 
     | 
    
         
            +
                assert TestDelegate.processing_result=='Failure processing Bad Message 2'
         
     | 
| 
      
 74 
     | 
    
         
            +
                Resque::Worker.new(:surety_messages).process
         
     | 
| 
      
 75 
     | 
    
         
            +
                assert TestDelegate.processing_result=='Success processing Good Message 3'
         
     | 
| 
      
 76 
     | 
    
         
            +
                assert Resque.redis.llen('queue:surety_messages')==1
         
     | 
| 
      
 77 
     | 
    
         
            +
                @message1.reload
         
     | 
| 
      
 78 
     | 
    
         
            +
                assert_message_matches(@message1, 
         
     | 
| 
      
 79 
     | 
    
         
            +
                  {
         
     | 
| 
      
 80 
     | 
    
         
            +
                    :message_content=>'Good Message 1',
         
     | 
| 
      
 81 
     | 
    
         
            +
                    :state => 'completed',
         
     | 
| 
      
 82 
     | 
    
         
            +
                    :processing_attempt_count => 1,
         
     | 
| 
      
 83 
     | 
    
         
            +
                    :failure_count => 0,
         
     | 
| 
      
 84 
     | 
    
         
            +
                    :failed_at => nil,
         
     | 
| 
      
 85 
     | 
    
         
            +
                    :last_exception => nil
         
     | 
| 
      
 86 
     | 
    
         
            +
                  })
         
     | 
| 
      
 87 
     | 
    
         
            +
                assert_in_delta(@message1.processing_started_at, Time.now, 5)
         
     | 
| 
      
 88 
     | 
    
         
            +
                assert_in_delta(@message1.completed_at, Time.now, 5)
         
     | 
| 
      
 89 
     | 
    
         
            +
                @message2.reload
         
     | 
| 
      
 90 
     | 
    
         
            +
                assert_message_matches(@message2, 
         
     | 
| 
      
 91 
     | 
    
         
            +
                  {
         
     | 
| 
      
 92 
     | 
    
         
            +
                    :message_content=>'Bad Message 2',
         
     | 
| 
      
 93 
     | 
    
         
            +
                    :state => 'failed',
         
     | 
| 
      
 94 
     | 
    
         
            +
                    :processing_attempt_count => 1,
         
     | 
| 
      
 95 
     | 
    
         
            +
                    :failure_count => 1,
         
     | 
| 
      
 96 
     | 
    
         
            +
                    :completed_at => nil,
         
     | 
| 
      
 97 
     | 
    
         
            +
                  })
         
     | 
| 
      
 98 
     | 
    
         
            +
                assert_in_delta(@message2.processing_started_at, Time.now, 5)
         
     | 
| 
      
 99 
     | 
    
         
            +
                assert_in_delta(@message2.failed_at, Time.now, 5)
         
     | 
| 
      
 100 
     | 
    
         
            +
                assert @message2.last_exception.present?
         
     | 
| 
      
 101 
     | 
    
         
            +
                assert Resque.redis.llen('queue:surety_messages')==1
         
     | 
| 
      
 102 
     | 
    
         
            +
                @message3.reload
         
     | 
| 
      
 103 
     | 
    
         
            +
                assert_message_matches(@message3, 
         
     | 
| 
      
 104 
     | 
    
         
            +
                  {
         
     | 
| 
      
 105 
     | 
    
         
            +
                    :message_content=>'Good Message 3',
         
     | 
| 
      
 106 
     | 
    
         
            +
                    :state => 'completed',
         
     | 
| 
      
 107 
     | 
    
         
            +
                    :processing_attempt_count => 1,
         
     | 
| 
      
 108 
     | 
    
         
            +
                    :failure_count => 0,
         
     | 
| 
      
 109 
     | 
    
         
            +
                    :failed_at => nil,
         
     | 
| 
      
 110 
     | 
    
         
            +
                    :last_exception => nil
         
     | 
| 
      
 111 
     | 
    
         
            +
                  })
         
     | 
| 
      
 112 
     | 
    
         
            +
                assert_in_delta(@message3.processing_started_at, Time.now, 5)
         
     | 
| 
      
 113 
     | 
    
         
            +
                assert_in_delta(@message3.completed_at, Time.now, 5)
         
     | 
| 
      
 114 
     | 
    
         
            +
              end
         
     | 
| 
      
 115 
     | 
    
         
            +
              
         
     | 
| 
      
 116 
     | 
    
         
            +
              def test_perform_nothin_in_queue
         
     | 
| 
      
 117 
     | 
    
         
            +
                Surety::Message.new.connection.execute("truncate table messages")
         
     | 
| 
      
 118 
     | 
    
         
            +
                @message1 = Surety::Message.generate_message('Message 1')
         
     | 
| 
      
 119 
     | 
    
         
            +
                @message1.begin_processing!
         
     | 
| 
      
 120 
     | 
    
         
            +
                @message1.complete_processing!
         
     | 
| 
      
 121 
     | 
    
         
            +
                Surety::Processor.request_next
         
     | 
| 
      
 122 
     | 
    
         
            +
                Resque::Worker.new(:surety_messages).process
         
     | 
| 
      
 123 
     | 
    
         
            +
                assert Resque.redis.llen('queue:surety_messages')==1
         
     | 
| 
      
 124 
     | 
    
         
            +
              end
         
     | 
| 
      
 125 
     | 
    
         
            +
              
         
     | 
| 
      
 126 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,132 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # Redis configuration file example
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            # By default Redis does not run as a daemon. Use 'yes' if you need it.
         
     | 
| 
      
 4 
     | 
    
         
            +
            # Note that Redis will write a pid file in /var/run/redis.pid when daemonized.
         
     | 
| 
      
 5 
     | 
    
         
            +
            daemonize yes
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            # When run as a daemon, Redis write a pid file in /var/run/redis.pid by default.
         
     | 
| 
      
 8 
     | 
    
         
            +
            # You can specify a custom pid file location here.
         
     | 
| 
      
 9 
     | 
    
         
            +
            pidfile ./test/redis-test.pid
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
            # Accept connections on the specified port, default is 6379
         
     | 
| 
      
 12 
     | 
    
         
            +
            port 9736
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
            # If you want you can bind a single interface, if the bind option is not
         
     | 
| 
      
 15 
     | 
    
         
            +
            # specified all the interfaces will listen for connections.
         
     | 
| 
      
 16 
     | 
    
         
            +
            #
         
     | 
| 
      
 17 
     | 
    
         
            +
            # bind 127.0.0.1
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
            # Close the connection after a client is idle for N seconds (0 to disable)
         
     | 
| 
      
 20 
     | 
    
         
            +
            timeout 300
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
            # Save the DB on disk:
         
     | 
| 
      
 23 
     | 
    
         
            +
            #
         
     | 
| 
      
 24 
     | 
    
         
            +
            #   save <seconds> <changes>
         
     | 
| 
      
 25 
     | 
    
         
            +
            #
         
     | 
| 
      
 26 
     | 
    
         
            +
            #   Will save the DB if both the given number of seconds and the given
         
     | 
| 
      
 27 
     | 
    
         
            +
            #   number of write operations against the DB occurred.
         
     | 
| 
      
 28 
     | 
    
         
            +
            #
         
     | 
| 
      
 29 
     | 
    
         
            +
            #   In the example below the behaviour will be to save:
         
     | 
| 
      
 30 
     | 
    
         
            +
            #   after 900 sec (15 min) if at least 1 key changed
         
     | 
| 
      
 31 
     | 
    
         
            +
            #   after 300 sec (5 min) if at least 10 keys changed
         
     | 
| 
      
 32 
     | 
    
         
            +
            #   after 60 sec if at least 10000 keys changed
         
     | 
| 
      
 33 
     | 
    
         
            +
            save 900 1
         
     | 
| 
      
 34 
     | 
    
         
            +
            save 300 10
         
     | 
| 
      
 35 
     | 
    
         
            +
            save 60 10000
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
            # The filename where to dump the DB
         
     | 
| 
      
 38 
     | 
    
         
            +
            dbfilename dump.rdb
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
            # For default save/load DB in/from the working directory
         
     | 
| 
      
 41 
     | 
    
         
            +
            # Note that you must specify a directory not a file name.
         
     | 
| 
      
 42 
     | 
    
         
            +
            dir ./test/
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
            # Set server verbosity to 'debug'
         
     | 
| 
      
 45 
     | 
    
         
            +
            # it can be one of:
         
     | 
| 
      
 46 
     | 
    
         
            +
            # debug (a lot of information, useful for development/testing)
         
     | 
| 
      
 47 
     | 
    
         
            +
            # notice (moderately verbose, what you want in production probably)
         
     | 
| 
      
 48 
     | 
    
         
            +
            # warning (only very important / critical messages are logged)
         
     | 
| 
      
 49 
     | 
    
         
            +
            loglevel debug
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
            # Specify the log file name. Also 'stdout' can be used to force
         
     | 
| 
      
 52 
     | 
    
         
            +
            # the demon to log on the standard output. Note that if you use standard
         
     | 
| 
      
 53 
     | 
    
         
            +
            # output for logging but daemonize, logs will be sent to /dev/null
         
     | 
| 
      
 54 
     | 
    
         
            +
            logfile stdout
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
            # Set the number of databases. The default database is DB 0, you can select
         
     | 
| 
      
 57 
     | 
    
         
            +
            # a different one on a per-connection basis using SELECT <dbid> where
         
     | 
| 
      
 58 
     | 
    
         
            +
            # dbid is a number between 0 and 'databases'-1
         
     | 
| 
      
 59 
     | 
    
         
            +
            databases 16
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
            ################################# REPLICATION #################################
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
      
 63 
     | 
    
         
            +
            # Master-Slave replication. Use slaveof to make a Redis instance a copy of
         
     | 
| 
      
 64 
     | 
    
         
            +
            # another Redis server. Note that the configuration is local to the slave
         
     | 
| 
      
 65 
     | 
    
         
            +
            # so for example it is possible to configure the slave to save the DB with a
         
     | 
| 
      
 66 
     | 
    
         
            +
            # different interval, or to listen to another port, and so on.
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
            # slaveof <masterip> <masterport>
         
     | 
| 
      
 69 
     | 
    
         
            +
             
     | 
| 
      
 70 
     | 
    
         
            +
            ################################## SECURITY ###################################
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
            # Require clients to issue AUTH <PASSWORD> before processing any other
         
     | 
| 
      
 73 
     | 
    
         
            +
            # commands.  This might be useful in environments in which you do not trust
         
     | 
| 
      
 74 
     | 
    
         
            +
            # others with access to the host running redis-server.
         
     | 
| 
      
 75 
     | 
    
         
            +
            #
         
     | 
| 
      
 76 
     | 
    
         
            +
            # This should stay commented out for backward compatibility and because most
         
     | 
| 
      
 77 
     | 
    
         
            +
            # people do not need auth (e.g. they run their own servers).
         
     | 
| 
      
 78 
     | 
    
         
            +
             
     | 
| 
      
 79 
     | 
    
         
            +
            # requirepass foobared
         
     | 
| 
      
 80 
     | 
    
         
            +
             
     | 
| 
      
 81 
     | 
    
         
            +
            ################################### LIMITS ####################################
         
     | 
| 
      
 82 
     | 
    
         
            +
             
     | 
| 
      
 83 
     | 
    
         
            +
            # Set the max number of connected clients at the same time. By default there
         
     | 
| 
      
 84 
     | 
    
         
            +
            # is no limit, and it's up to the number of file descriptors the Redis process
         
     | 
| 
      
 85 
     | 
    
         
            +
            # is able to open. The special value '0' means no limts.
         
     | 
| 
      
 86 
     | 
    
         
            +
            # Once the limit is reached Redis will close all the new connections sending
         
     | 
| 
      
 87 
     | 
    
         
            +
            # an error 'max number of clients reached'.
         
     | 
| 
      
 88 
     | 
    
         
            +
             
     | 
| 
      
 89 
     | 
    
         
            +
            # maxclients 128
         
     | 
| 
      
 90 
     | 
    
         
            +
             
     | 
| 
      
 91 
     | 
    
         
            +
            # Don't use more memory than the specified amount of bytes.
         
     | 
| 
      
 92 
     | 
    
         
            +
            # When the memory limit is reached Redis will try to remove keys with an
         
     | 
| 
      
 93 
     | 
    
         
            +
            # EXPIRE set. It will try to start freeing keys that are going to expire
         
     | 
| 
      
 94 
     | 
    
         
            +
            # in little time and preserve keys with a longer time to live.
         
     | 
| 
      
 95 
     | 
    
         
            +
            # Redis will also try to remove objects from free lists if possible.
         
     | 
| 
      
 96 
     | 
    
         
            +
            #
         
     | 
| 
      
 97 
     | 
    
         
            +
            # If all this fails, Redis will start to reply with errors to commands
         
     | 
| 
      
 98 
     | 
    
         
            +
            # that will use more memory, like SET, LPUSH, and so on, and will continue
         
     | 
| 
      
 99 
     | 
    
         
            +
            # to reply to most read-only commands like GET.
         
     | 
| 
      
 100 
     | 
    
         
            +
            #
         
     | 
| 
      
 101 
     | 
    
         
            +
            # WARNING: maxmemory can be a good idea mainly if you want to use Redis as a
         
     | 
| 
      
 102 
     | 
    
         
            +
            # 'state' server or cache, not as a real DB. When Redis is used as a real
         
     | 
| 
      
 103 
     | 
    
         
            +
            # database the memory usage will grow over the weeks, it will be obvious if
         
     | 
| 
      
 104 
     | 
    
         
            +
            # it is going to use too much memory in the long run, and you'll have the time
         
     | 
| 
      
 105 
     | 
    
         
            +
            # to upgrade. With maxmemory after the limit is reached you'll start to get
         
     | 
| 
      
 106 
     | 
    
         
            +
            # errors for write operations, and this may even lead to DB inconsistency.
         
     | 
| 
      
 107 
     | 
    
         
            +
             
     | 
| 
      
 108 
     | 
    
         
            +
            # maxmemory <bytes>
         
     | 
| 
      
 109 
     | 
    
         
            +
             
     | 
| 
      
 110 
     | 
    
         
            +
            ############################### ADVANCED CONFIG ###############################
         
     | 
| 
      
 111 
     | 
    
         
            +
             
     | 
| 
      
 112 
     | 
    
         
            +
            # Glue small output buffers together in order to send small replies in a
         
     | 
| 
      
 113 
     | 
    
         
            +
            # single TCP packet. Uses a bit more CPU but most of the times it is a win
         
     | 
| 
      
 114 
     | 
    
         
            +
            # in terms of number of queries per second. Use 'yes' if unsure.
         
     | 
| 
      
 115 
     | 
    
         
            +
            glueoutputbuf yes
         
     | 
| 
      
 116 
     | 
    
         
            +
             
     | 
| 
      
 117 
     | 
    
         
            +
            # Use object sharing. Can save a lot of memory if you have many common
         
     | 
| 
      
 118 
     | 
    
         
            +
            # string in your dataset, but performs lookups against the shared objects
         
     | 
| 
      
 119 
     | 
    
         
            +
            # pool so it uses more CPU and can be a bit slower. Usually it's a good
         
     | 
| 
      
 120 
     | 
    
         
            +
            # idea.
         
     | 
| 
      
 121 
     | 
    
         
            +
            #
         
     | 
| 
      
 122 
     | 
    
         
            +
            # When object sharing is enabled (shareobjects yes) you can use
         
     | 
| 
      
 123 
     | 
    
         
            +
            # shareobjectspoolsize to control the size of the pool used in order to try
         
     | 
| 
      
 124 
     | 
    
         
            +
            # object sharing. A bigger pool size will lead to better sharing capabilities.
         
     | 
| 
      
 125 
     | 
    
         
            +
            # In general you want this value to be at least the double of the number of
         
     | 
| 
      
 126 
     | 
    
         
            +
            # very common strings you have in your dataset.
         
     | 
| 
      
 127 
     | 
    
         
            +
            #
         
     | 
| 
      
 128 
     | 
    
         
            +
            # WARNING: object sharing is experimental, don't enable this feature
         
     | 
| 
      
 129 
     | 
    
         
            +
            # in production before of Redis 1.0-stable. Still please try this feature in
         
     | 
| 
      
 130 
     | 
    
         
            +
            # your development environment so that we can test it better.
         
     | 
| 
      
 131 
     | 
    
         
            +
            #shareobjects no
         
     | 
| 
      
 132 
     | 
    
         
            +
            #shareobjectspoolsize 1024
         
     | 
    
        data/test/schema.rb
    ADDED
    
    | 
         @@ -0,0 +1,15 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            ActiveRecord::Schema.define(:version => 1) do
         
     | 
| 
      
 2 
     | 
    
         
            +
              create_table :messages, :force => true do |t|
         
     | 
| 
      
 3 
     | 
    
         
            +
                t.column :message_content, :string
         
     | 
| 
      
 4 
     | 
    
         
            +
                t.column :state, :string
         
     | 
| 
      
 5 
     | 
    
         
            +
                t.column :processing_attempt_count, :integer, :default => 0
         
     | 
| 
      
 6 
     | 
    
         
            +
                t.column :processing_started_at, :datetime
         
     | 
| 
      
 7 
     | 
    
         
            +
                t.column :completed_at, :datetime
         
     | 
| 
      
 8 
     | 
    
         
            +
                t.column :failure_count, :integer, :default => 0
         
     | 
| 
      
 9 
     | 
    
         
            +
                t.column :failed_at, :datetime
         
     | 
| 
      
 10 
     | 
    
         
            +
                t.column :last_exception, :text
         
     | 
| 
      
 11 
     | 
    
         
            +
                t.column :created_at, :datetime
         
     | 
| 
      
 12 
     | 
    
         
            +
                t.column :updated_at, :datetime
         
     | 
| 
      
 13 
     | 
    
         
            +
              end
         
     | 
| 
      
 14 
     | 
    
         
            +
              
         
     | 
| 
      
 15 
     | 
    
         
            +
            end
         
     | 
    
        data/test/test_helper.rb
    ADDED
    
    | 
         @@ -0,0 +1,70 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            dir = File.dirname(File.expand_path(__FILE__))
         
     | 
| 
      
 2 
     | 
    
         
            +
            $LOAD_PATH.unshift dir + '/../lib'
         
     | 
| 
      
 3 
     | 
    
         
            +
            $TESTING = true
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            ENV['RAILS_ENV'] = 'test'
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            require 'rubygems'
         
     | 
| 
      
 8 
     | 
    
         
            +
            require 'test/unit'
         
     | 
| 
      
 9 
     | 
    
         
            +
            require 'active_support'
         
     | 
| 
      
 10 
     | 
    
         
            +
            require 'active_support/test_case'
         
     | 
| 
      
 11 
     | 
    
         
            +
            require 'resque'
         
     | 
| 
      
 12 
     | 
    
         
            +
            require 'state_machine'
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
            require 'surety'
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
            config = YAML::load(IO.read(File.dirname(__FILE__) + '/database.yml'))
         
     | 
| 
      
 18 
     | 
    
         
            +
            ActiveRecord::Base.configurations = config
         
     | 
| 
      
 19 
     | 
    
         
            +
            require 'mysql2'
         
     | 
| 
      
 20 
     | 
    
         
            +
            ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations['test'])
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
            load(File.dirname(__FILE__) + "/schema.rb")
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
            class ActiveSupport::TestCase
         
     | 
| 
      
 25 
     | 
    
         
            +
              include ActiveRecord::TestFixtures
         
     | 
| 
      
 26 
     | 
    
         
            +
              self.fixture_path = File.dirname(__FILE__) + "/fixtures"
         
     | 
| 
      
 27 
     | 
    
         
            +
              self.use_transactional_fixtures = false
         
     | 
| 
      
 28 
     | 
    
         
            +
              self.use_instantiated_fixtures = false
         
     | 
| 
      
 29 
     | 
    
         
            +
              fixtures :all
         
     | 
| 
      
 30 
     | 
    
         
            +
            end
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
            # make sure we can run redis
         
     | 
| 
      
 34 
     | 
    
         
            +
            if !system('which redis-server')
         
     | 
| 
      
 35 
     | 
    
         
            +
              puts '', "** can't find `redis-server` in your path"
         
     | 
| 
      
 36 
     | 
    
         
            +
              puts "** try running `sudo rake install`"
         
     | 
| 
      
 37 
     | 
    
         
            +
              abort ''
         
     | 
| 
      
 38 
     | 
    
         
            +
            end
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
            # start our own redis when the tests start,
         
     | 
| 
      
 41 
     | 
    
         
            +
            # kill it when they end
         
     | 
| 
      
 42 
     | 
    
         
            +
            at_exit do
         
     | 
| 
      
 43 
     | 
    
         
            +
              next if $!
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
              if defined?(MiniTest)
         
     | 
| 
      
 46 
     | 
    
         
            +
                exit_code = MiniTest::Unit.new.run(ARGV)
         
     | 
| 
      
 47 
     | 
    
         
            +
              else
         
     | 
| 
      
 48 
     | 
    
         
            +
                exit_code = Test::Unit::AutoRunner.run
         
     | 
| 
      
 49 
     | 
    
         
            +
              end
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
              pid = `ps -e -o pid,command | grep [r]edis-test`.split(" ")[0]
         
     | 
| 
      
 52 
     | 
    
         
            +
              puts 'Killing test redis server...'
         
     | 
| 
      
 53 
     | 
    
         
            +
              `rm -f #{dir}/dump.rdb`
         
     | 
| 
      
 54 
     | 
    
         
            +
              Process.kill('KILL', pid.to_i)
         
     | 
| 
      
 55 
     | 
    
         
            +
              exit exit_code
         
     | 
| 
      
 56 
     | 
    
         
            +
            end
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
            puts 'Starting redis for testing at localhost:9736...'
         
     | 
| 
      
 59 
     | 
    
         
            +
            `redis-server #{dir}/redis-test.conf`
         
     | 
| 
      
 60 
     | 
    
         
            +
            Resque.redis = '127.0.0.1:9736'
         
     | 
| 
      
 61 
     | 
    
         
            +
            Resque.redis.namespace = 'test_surety'
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
      
 63 
     | 
    
         
            +
            Dir.glob(File.expand_path(dir + '/fixtures/*')).each { |filename| require filename }
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
            def assert_message_matches(message, attrs)
         
     | 
| 
      
 66 
     | 
    
         
            +
              attrs.each_key {|key|
         
     | 
| 
      
 67 
     | 
    
         
            +
                #puts "checking message key: #{key} #{message.send(key.to_sym)} #{attrs[key]}"
         
     | 
| 
      
 68 
     | 
    
         
            +
                assert message.send(key.to_sym)==attrs[key]
         
     | 
| 
      
 69 
     | 
    
         
            +
              }
         
     | 
| 
      
 70 
     | 
    
         
            +
            end
         
     | 
    
        metadata
    ADDED
    
    | 
         @@ -0,0 +1,191 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            --- !ruby/object:Gem::Specification 
         
     | 
| 
      
 2 
     | 
    
         
            +
            name: surety
         
     | 
| 
      
 3 
     | 
    
         
            +
            version: !ruby/object:Gem::Version 
         
     | 
| 
      
 4 
     | 
    
         
            +
              hash: 21
         
     | 
| 
      
 5 
     | 
    
         
            +
              prerelease: 
         
     | 
| 
      
 6 
     | 
    
         
            +
              segments: 
         
     | 
| 
      
 7 
     | 
    
         
            +
              - 0
         
     | 
| 
      
 8 
     | 
    
         
            +
              - 1
         
     | 
| 
      
 9 
     | 
    
         
            +
              - 7
         
     | 
| 
      
 10 
     | 
    
         
            +
              version: 0.1.7
         
     | 
| 
      
 11 
     | 
    
         
            +
            platform: ruby
         
     | 
| 
      
 12 
     | 
    
         
            +
            authors: 
         
     | 
| 
      
 13 
     | 
    
         
            +
            - Monica McArthur
         
     | 
| 
      
 14 
     | 
    
         
            +
            autorequire: 
         
     | 
| 
      
 15 
     | 
    
         
            +
            bindir: bin
         
     | 
| 
      
 16 
     | 
    
         
            +
            cert_chain: []
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
            date: 2012-01-10 00:00:00 Z
         
     | 
| 
      
 19 
     | 
    
         
            +
            dependencies: 
         
     | 
| 
      
 20 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency 
         
     | 
| 
      
 21 
     | 
    
         
            +
              name: yajl-ruby
         
     | 
| 
      
 22 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 23 
     | 
    
         
            +
              requirement: &id001 !ruby/object:Gem::Requirement 
         
     | 
| 
      
 24 
     | 
    
         
            +
                none: false
         
     | 
| 
      
 25 
     | 
    
         
            +
                requirements: 
         
     | 
| 
      
 26 
     | 
    
         
            +
                - - ~>
         
     | 
| 
      
 27 
     | 
    
         
            +
                  - !ruby/object:Gem::Version 
         
     | 
| 
      
 28 
     | 
    
         
            +
                    hash: 59
         
     | 
| 
      
 29 
     | 
    
         
            +
                    segments: 
         
     | 
| 
      
 30 
     | 
    
         
            +
                    - 0
         
     | 
| 
      
 31 
     | 
    
         
            +
                    - 8
         
     | 
| 
      
 32 
     | 
    
         
            +
                    - 2
         
     | 
| 
      
 33 
     | 
    
         
            +
                    version: 0.8.2
         
     | 
| 
      
 34 
     | 
    
         
            +
              type: :runtime
         
     | 
| 
      
 35 
     | 
    
         
            +
              version_requirements: *id001
         
     | 
| 
      
 36 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency 
         
     | 
| 
      
 37 
     | 
    
         
            +
              name: resque
         
     | 
| 
      
 38 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 39 
     | 
    
         
            +
              requirement: &id002 !ruby/object:Gem::Requirement 
         
     | 
| 
      
 40 
     | 
    
         
            +
                none: false
         
     | 
| 
      
 41 
     | 
    
         
            +
                requirements: 
         
     | 
| 
      
 42 
     | 
    
         
            +
                - - ">="
         
     | 
| 
      
 43 
     | 
    
         
            +
                  - !ruby/object:Gem::Version 
         
     | 
| 
      
 44 
     | 
    
         
            +
                    hash: 91
         
     | 
| 
      
 45 
     | 
    
         
            +
                    segments: 
         
     | 
| 
      
 46 
     | 
    
         
            +
                    - 1
         
     | 
| 
      
 47 
     | 
    
         
            +
                    - 19
         
     | 
| 
      
 48 
     | 
    
         
            +
                    - 0
         
     | 
| 
      
 49 
     | 
    
         
            +
                    version: 1.19.0
         
     | 
| 
      
 50 
     | 
    
         
            +
              type: :runtime
         
     | 
| 
      
 51 
     | 
    
         
            +
              version_requirements: *id002
         
     | 
| 
      
 52 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency 
         
     | 
| 
      
 53 
     | 
    
         
            +
              name: activesupport
         
     | 
| 
      
 54 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 55 
     | 
    
         
            +
              requirement: &id003 !ruby/object:Gem::Requirement 
         
     | 
| 
      
 56 
     | 
    
         
            +
                none: false
         
     | 
| 
      
 57 
     | 
    
         
            +
                requirements: 
         
     | 
| 
      
 58 
     | 
    
         
            +
                - - ">="
         
     | 
| 
      
 59 
     | 
    
         
            +
                  - !ruby/object:Gem::Version 
         
     | 
| 
      
 60 
     | 
    
         
            +
                    hash: 7
         
     | 
| 
      
 61 
     | 
    
         
            +
                    segments: 
         
     | 
| 
      
 62 
     | 
    
         
            +
                    - 3
         
     | 
| 
      
 63 
     | 
    
         
            +
                    - 0
         
     | 
| 
      
 64 
     | 
    
         
            +
                    version: "3.0"
         
     | 
| 
      
 65 
     | 
    
         
            +
              type: :runtime
         
     | 
| 
      
 66 
     | 
    
         
            +
              version_requirements: *id003
         
     | 
| 
      
 67 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency 
         
     | 
| 
      
 68 
     | 
    
         
            +
              name: activerecord
         
     | 
| 
      
 69 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 70 
     | 
    
         
            +
              requirement: &id004 !ruby/object:Gem::Requirement 
         
     | 
| 
      
 71 
     | 
    
         
            +
                none: false
         
     | 
| 
      
 72 
     | 
    
         
            +
                requirements: 
         
     | 
| 
      
 73 
     | 
    
         
            +
                - - ">="
         
     | 
| 
      
 74 
     | 
    
         
            +
                  - !ruby/object:Gem::Version 
         
     | 
| 
      
 75 
     | 
    
         
            +
                    hash: 7
         
     | 
| 
      
 76 
     | 
    
         
            +
                    segments: 
         
     | 
| 
      
 77 
     | 
    
         
            +
                    - 3
         
     | 
| 
      
 78 
     | 
    
         
            +
                    - 0
         
     | 
| 
      
 79 
     | 
    
         
            +
                    version: "3.0"
         
     | 
| 
      
 80 
     | 
    
         
            +
              type: :runtime
         
     | 
| 
      
 81 
     | 
    
         
            +
              version_requirements: *id004
         
     | 
| 
      
 82 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency 
         
     | 
| 
      
 83 
     | 
    
         
            +
              name: state_machine
         
     | 
| 
      
 84 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 85 
     | 
    
         
            +
              requirement: &id005 !ruby/object:Gem::Requirement 
         
     | 
| 
      
 86 
     | 
    
         
            +
                none: false
         
     | 
| 
      
 87 
     | 
    
         
            +
                requirements: 
         
     | 
| 
      
 88 
     | 
    
         
            +
                - - ">="
         
     | 
| 
      
 89 
     | 
    
         
            +
                  - !ruby/object:Gem::Version 
         
     | 
| 
      
 90 
     | 
    
         
            +
                    hash: 23
         
     | 
| 
      
 91 
     | 
    
         
            +
                    segments: 
         
     | 
| 
      
 92 
     | 
    
         
            +
                    - 1
         
     | 
| 
      
 93 
     | 
    
         
            +
                    - 0
         
     | 
| 
      
 94 
     | 
    
         
            +
                    - 0
         
     | 
| 
      
 95 
     | 
    
         
            +
                    version: 1.0.0
         
     | 
| 
      
 96 
     | 
    
         
            +
              type: :runtime
         
     | 
| 
      
 97 
     | 
    
         
            +
              version_requirements: *id005
         
     | 
| 
      
 98 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency 
         
     | 
| 
      
 99 
     | 
    
         
            +
              name: mysql2
         
     | 
| 
      
 100 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 101 
     | 
    
         
            +
              requirement: &id006 !ruby/object:Gem::Requirement 
         
     | 
| 
      
 102 
     | 
    
         
            +
                none: false
         
     | 
| 
      
 103 
     | 
    
         
            +
                requirements: 
         
     | 
| 
      
 104 
     | 
    
         
            +
                - - "="
         
     | 
| 
      
 105 
     | 
    
         
            +
                  - !ruby/object:Gem::Version 
         
     | 
| 
      
 106 
     | 
    
         
            +
                    hash: 25
         
     | 
| 
      
 107 
     | 
    
         
            +
                    segments: 
         
     | 
| 
      
 108 
     | 
    
         
            +
                    - 0
         
     | 
| 
      
 109 
     | 
    
         
            +
                    - 2
         
     | 
| 
      
 110 
     | 
    
         
            +
                    - 7
         
     | 
| 
      
 111 
     | 
    
         
            +
                    version: 0.2.7
         
     | 
| 
      
 112 
     | 
    
         
            +
              type: :development
         
     | 
| 
      
 113 
     | 
    
         
            +
              version_requirements: *id006
         
     | 
| 
      
 114 
     | 
    
         
            +
            description: "    A lightweight guaranteed-delivery messaging system.\n"
         
     | 
| 
      
 115 
     | 
    
         
            +
            email: monica@revolutionprep.com
         
     | 
| 
      
 116 
     | 
    
         
            +
            executables: []
         
     | 
| 
      
 117 
     | 
    
         
            +
             
     | 
| 
      
 118 
     | 
    
         
            +
            extensions: []
         
     | 
| 
      
 119 
     | 
    
         
            +
             
     | 
| 
      
 120 
     | 
    
         
            +
            extra_rdoc_files: []
         
     | 
| 
      
 121 
     | 
    
         
            +
             
     | 
| 
      
 122 
     | 
    
         
            +
            files: 
         
     | 
| 
      
 123 
     | 
    
         
            +
            - Gemfile
         
     | 
| 
      
 124 
     | 
    
         
            +
            - Gemfile.lock
         
     | 
| 
      
 125 
     | 
    
         
            +
            - LICENSE
         
     | 
| 
      
 126 
     | 
    
         
            +
            - README.md
         
     | 
| 
      
 127 
     | 
    
         
            +
            - Rakefile
         
     | 
| 
      
 128 
     | 
    
         
            +
            - lib/generators/install_generator.rb
         
     | 
| 
      
 129 
     | 
    
         
            +
            - lib/generators/templates/20120104151700_create_messages.rb
         
     | 
| 
      
 130 
     | 
    
         
            +
            - lib/surety.rb
         
     | 
| 
      
 131 
     | 
    
         
            +
            - lib/surety/configuration.rb
         
     | 
| 
      
 132 
     | 
    
         
            +
            - lib/surety/generator.rb
         
     | 
| 
      
 133 
     | 
    
         
            +
            - lib/surety/message.rb
         
     | 
| 
      
 134 
     | 
    
         
            +
            - lib/surety/processor.rb
         
     | 
| 
      
 135 
     | 
    
         
            +
            - surety.gemspec
         
     | 
| 
      
 136 
     | 
    
         
            +
            - test/configuration_test.rb
         
     | 
| 
      
 137 
     | 
    
         
            +
            - test/database.yml
         
     | 
| 
      
 138 
     | 
    
         
            +
            - test/fixtures/test_delegate.rb
         
     | 
| 
      
 139 
     | 
    
         
            +
            - test/fixtures/test_generator.rb
         
     | 
| 
      
 140 
     | 
    
         
            +
            - test/generator_test.rb
         
     | 
| 
      
 141 
     | 
    
         
            +
            - test/message_test.rb
         
     | 
| 
      
 142 
     | 
    
         
            +
            - test/message_timezone_test.rb
         
     | 
| 
      
 143 
     | 
    
         
            +
            - test/processor_test.rb
         
     | 
| 
      
 144 
     | 
    
         
            +
            - test/redis-test.conf
         
     | 
| 
      
 145 
     | 
    
         
            +
            - test/schema.rb
         
     | 
| 
      
 146 
     | 
    
         
            +
            - test/test_helper.rb
         
     | 
| 
      
 147 
     | 
    
         
            +
            homepage: ""
         
     | 
| 
      
 148 
     | 
    
         
            +
            licenses: []
         
     | 
| 
      
 149 
     | 
    
         
            +
             
     | 
| 
      
 150 
     | 
    
         
            +
            post_install_message: 
         
     | 
| 
      
 151 
     | 
    
         
            +
            rdoc_options: []
         
     | 
| 
      
 152 
     | 
    
         
            +
             
     | 
| 
      
 153 
     | 
    
         
            +
            require_paths: 
         
     | 
| 
      
 154 
     | 
    
         
            +
            - lib
         
     | 
| 
      
 155 
     | 
    
         
            +
            required_ruby_version: !ruby/object:Gem::Requirement 
         
     | 
| 
      
 156 
     | 
    
         
            +
              none: false
         
     | 
| 
      
 157 
     | 
    
         
            +
              requirements: 
         
     | 
| 
      
 158 
     | 
    
         
            +
              - - ">="
         
     | 
| 
      
 159 
     | 
    
         
            +
                - !ruby/object:Gem::Version 
         
     | 
| 
      
 160 
     | 
    
         
            +
                  hash: 3
         
     | 
| 
      
 161 
     | 
    
         
            +
                  segments: 
         
     | 
| 
      
 162 
     | 
    
         
            +
                  - 0
         
     | 
| 
      
 163 
     | 
    
         
            +
                  version: "0"
         
     | 
| 
      
 164 
     | 
    
         
            +
            required_rubygems_version: !ruby/object:Gem::Requirement 
         
     | 
| 
      
 165 
     | 
    
         
            +
              none: false
         
     | 
| 
      
 166 
     | 
    
         
            +
              requirements: 
         
     | 
| 
      
 167 
     | 
    
         
            +
              - - ">="
         
     | 
| 
      
 168 
     | 
    
         
            +
                - !ruby/object:Gem::Version 
         
     | 
| 
      
 169 
     | 
    
         
            +
                  hash: 3
         
     | 
| 
      
 170 
     | 
    
         
            +
                  segments: 
         
     | 
| 
      
 171 
     | 
    
         
            +
                  - 0
         
     | 
| 
      
 172 
     | 
    
         
            +
                  version: "0"
         
     | 
| 
      
 173 
     | 
    
         
            +
            requirements: []
         
     | 
| 
      
 174 
     | 
    
         
            +
             
     | 
| 
      
 175 
     | 
    
         
            +
            rubyforge_project: 
         
     | 
| 
      
 176 
     | 
    
         
            +
            rubygems_version: 1.8.10
         
     | 
| 
      
 177 
     | 
    
         
            +
            signing_key: 
         
     | 
| 
      
 178 
     | 
    
         
            +
            specification_version: 3
         
     | 
| 
      
 179 
     | 
    
         
            +
            summary: A lightweight guaranteed-delivery messaging system.
         
     | 
| 
      
 180 
     | 
    
         
            +
            test_files: 
         
     | 
| 
      
 181 
     | 
    
         
            +
            - test/configuration_test.rb
         
     | 
| 
      
 182 
     | 
    
         
            +
            - test/database.yml
         
     | 
| 
      
 183 
     | 
    
         
            +
            - test/fixtures/test_delegate.rb
         
     | 
| 
      
 184 
     | 
    
         
            +
            - test/fixtures/test_generator.rb
         
     | 
| 
      
 185 
     | 
    
         
            +
            - test/generator_test.rb
         
     | 
| 
      
 186 
     | 
    
         
            +
            - test/message_test.rb
         
     | 
| 
      
 187 
     | 
    
         
            +
            - test/message_timezone_test.rb
         
     | 
| 
      
 188 
     | 
    
         
            +
            - test/processor_test.rb
         
     | 
| 
      
 189 
     | 
    
         
            +
            - test/redis-test.conf
         
     | 
| 
      
 190 
     | 
    
         
            +
            - test/schema.rb
         
     | 
| 
      
 191 
     | 
    
         
            +
            - test/test_helper.rb
         
     |