From 2682000224ed9fd2f7bc260c50e66491a16fe760 Mon Sep 17 00:00:00 2001 From: mahlon Date: Tue, 21 Mar 2023 18:21:32 +0000 Subject: [PATCH] Moderizing dev environment. - Use rake-deveiate. - Fixes for README - Add History, break out Manifest - Remove keyword expansion constant REVISION - Use current Configurability APIs instead of the (now ancient) methods - Whitespace changes FossilOrigin-Name: a778fb275af99a238d9d2311cc601c58adf80e28bd68a37e06acdfb6efeb018d --- .fossil-settings/ignore-glob | 9 ++ .gems | 8 - .hgignore | 11 -- .hgtags | 1 - .ruby-gemset | 1 + .ruby-version | 1 + .rvmrc | 32 ---- History.md | 27 ++++ Manifest.txt | 10 ++ README.md | 88 +++++++--- Rakefile | 152 +++--------------- certs/mahlon.pem | 25 +++ gem.deps.rb | 17 ++ lib/symphony/metronome.rb | 5 +- lib/symphony/metronome/intervalexpression.rl | 4 +- lib/symphony/metronome/scheduledevent.rb | 17 +- lib/symphony/metronome/scheduler.rb | 17 +- .../symphony/metronome/scheduledevent_spec.rb | 12 +- 18 files changed, 210 insertions(+), 227 deletions(-) create mode 100644 .fossil-settings/ignore-glob delete mode 100644 .gems delete mode 100644 .hgignore delete mode 100644 .hgtags create mode 100644 .ruby-gemset create mode 100644 .ruby-version delete mode 100644 .rvmrc create mode 100644 History.md create mode 100644 Manifest.txt create mode 100644 certs/mahlon.pem create mode 100644 gem.deps.rb diff --git a/.fossil-settings/ignore-glob b/.fossil-settings/ignore-glob new file mode 100644 index 0000000..feef999 --- /dev/null +++ b/.fossil-settings/ignore-glob @@ -0,0 +1,9 @@ +Session.vim +certs/* +coverage/* +docs/* +gem.deps.rb.lock +*.so +tmp/* +lib/symphony/metronome/intervalexpression.rb + diff --git a/.gems b/.gems deleted file mode 100644 index a5193ff..0000000 --- a/.gems +++ /dev/null @@ -1,8 +0,0 @@ -autotest -v4.4.6 -configurability -v2.1.1 -sequel -v5.4.0 -sqlite3 -v1.3.9 -symphony -v0.9.2 -rspec -v3.3.1 -timecop -v0.7.1 -simplecov -v0.9.1 diff --git a/.hgignore b/.hgignore deleted file mode 100644 index 2f0f74e..0000000 --- a/.hgignore +++ /dev/null @@ -1,11 +0,0 @@ -\.orig$ -\.rej$ -etc/.*\.(conf|yml)$ -\.DS_Store -~$ -pkg/ -^ChangeLog$ -^docs/ -^coverage/ -lib/symphony/metronome/intervalexpression.rb - diff --git a/.hgtags b/.hgtags deleted file mode 100644 index da3ca8a..0000000 --- a/.hgtags +++ /dev/null @@ -1 +0,0 @@ -bc6d5e12d577e1a982dfd4cd8ae63e90ce94f876 v0.2.1 diff --git a/.ruby-gemset b/.ruby-gemset new file mode 100644 index 0000000..2dae5c4 --- /dev/null +++ b/.ruby-gemset @@ -0,0 +1 @@ +metronome diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..a3ec5a4 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +3.2 diff --git a/.rvmrc b/.rvmrc deleted file mode 100644 index a949892..0000000 --- a/.rvmrc +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/env bash - -# This is an RVM Project .rvmrc file, used to automatically load the ruby -# development environment upon cd'ing into the directory - -environment_id="2.1.1@metronome" - -if [[ -d "${rvm_path:-$HOME/.rvm}/environments" \ - && -s "${rvm_path:-$HOME/.rvm}/environments/$environment_id" ]]; then - echo "Using ${environment_id}" - . "${rvm_path:-$HOME/.rvm}/environments/$environment_id" - - if [[ -s "${rvm_path:-$HOME/.rvm}/hooks/after_use" ]]; then - . "${rvm_path:-$HOME/.rvm}/hooks/after_use" - fi -else - # If the environment file has not yet been created, use the RVM CLI to select. - if ! rvm --create use "$environment_id" - then - echo "Failed to create RVM environment '${environment_id}'." - exit 1 - fi -fi - -filename=".gems" -if [[ -s "$filename" ]]; then - rvm gemset import "$filename" -fi - - - - diff --git a/History.md b/History.md new file mode 100644 index 0000000..abbe968 --- /dev/null +++ b/History.md @@ -0,0 +1,27 @@ +# Release History for Symphony-Metronome + +--- + +## v0.3.0 [2023-03-20] Mahlon E. Smith + +- Updates for Ruby 3. +- Dependency updates. +- Conversion to more modern ruby development tooling. + + +## v0.2.1 [2015-07-08] Mahlon E. Smith + +Enhancements: + +- Add "last run" timestamps for recurring events. + +Fixes: + +- Repair exact start times for recurring events, ie + 'starting at 2015-01-01 09:00:00 run every other minute for 2 days' + + +## v0.1.0 [2014-04-22] Mahlon E. Smith + +Initial release. + diff --git a/Manifest.txt b/Manifest.txt new file mode 100644 index 0000000..c61412e --- /dev/null +++ b/Manifest.txt @@ -0,0 +1,10 @@ +data/symphony-metronome/migrations/20140419_initial.rb +data/symphony-metronome/migrations/20141028_lastrun.rb +lib/symphony/metronome/intervalexpression.rb +lib/symphony/metronome/mixins.rb +lib/symphony/metronome/scheduledevent.rb +lib/symphony/metronome/scheduler.rb +lib/symphony/metronome.rb +lib/symphony/tasks/scheduletask.rb +History.md +README.md diff --git a/README.md b/README.md index 8cbc651..b5fe969 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,26 @@ # Metronome +home +: https://code.martini.nu/fossil/symphony-metronome + +docs +: https://martini.nu/docs/symphony-metronome + +github_mirror +: https://github.com/mahlonsmith/symphony-metronome + + + ## Description -Metronome is an interval scheduler and task runner. It can be used -locally as a cron replacement, or as a network-wide job executor. +Metronome is an interval scheduler and task runner. It can be used locally as a +cron replacement, or as a network-wide job executor. It is intended to be run +alongside Symphony, a Ruby AMQP event consumer. -Events are stored via simple database rows, and optionally managed -via AMQP events. Interval/time values are expressed with intuitive -English phrases, ie.: 'at 2pm', or 'Starting in 20 minutes, run every 10 -seconds and then finish in 2 days', or 'execute 12 times during the next -minute'. +Events are stored via simple database rows, and optionally themselves managed +via AMQP events. Interval/time values are expressed with intuitive English +phrases, ie.: 'at 2pm', or 'Starting in 20 minutes, run every 10 seconds and +then finish in 2 days', or 'execute 12 times during the next minute'. ## Synopsis @@ -31,8 +42,8 @@ end ``` -And here's a simplistic AMQP message broadcaster, using existing -Symphony connection information: +And here's a simplistic timed AMQP message broadcaster, using existing Symphony +connection information: ``` #!ruby @@ -156,19 +167,58 @@ gem install symphony-metronome ## Contributing -You can check out the current development source with Mercurial -[here](http://code.martini.nu/symphony-metronome), or via a mirror: +You can check out the source via Fossil from the following uri: - * github: https://github.com/mahlonsmith/Symphony-Metronome - * SourceHut: https://hg.sr.ht/~mahlon/Symphony-Metronome +% fossil clone https://code.martini.nu/fossil/symphony-metronome + +or via its GitHub mirror at: + +% git clone https://github.com/mahlonsmith/Symphony-Metronome After checking out the source, run: -``` -$ rake -``` + $ gem install -Ng + $ rake setup -This task will run the tests/specs and generate API documentation. +This will install dependencies, and do any other necessary setup for +development. + +Please report any issues +[here](https://code.martini.nu/fossil/symphony-metronome/tktnew). + + +## Authors + +- Mahlon E. Smith + + +## License + +Copyright (c) 2014-2023 Mahlon E. Smith +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the author/s, nor the names of the project's + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -If you use [rvm](http://rvm.io/), entering the project directory will -install any required development dependencies. diff --git a/Rakefile b/Rakefile index e1b9e49..e5a2609 100644 --- a/Rakefile +++ b/Rakefile @@ -1,28 +1,35 @@ -#!/usr/bin/env rake -# vim: set nosta noet ts=4 sw=4: +# vim: set noet sta sw=4 ts=4 : +# -*- ruby -*- -require 'rake/clean' +require 'rake/deveiate' require 'pathname' -PROJECT = 'metronome' -BASEDIR = Pathname( __FILE__ ).dirname.relative_path_from( Pathname.pwd ) -LIBDIR = BASEDIR + 'lib' + 'symphony' +Rake::DevEiate.setup( 'symphony-metronome' ) do |project| + project.publish_to = 'martini.nu:martini/www/docs/symphony-metronome' + project.summary = <<~END_SUM + A natural language scheduling and task runner for Symphony. + END_SUM + project.description = <<~END_DESC + Metronome is a scheduler and task runner. It can be used locally as a + cron replacement, or as a network-wide job executor. Events are stored + via simple database rows, and optionally managed via AMQP events. + Interval/time values are expressed with reasonably intuitive English + phrases, ie.: 'at 2pm', or 'Starting in 20 minutes, run every 10 seconds + and then finish in 2 days'. + END_DESC + project.authors = [ 'Mahlon E. Smith ' ] + project.rdoc_generator = :sixfish +end + CLOBBER.include( 'coverage' ) -$LOAD_PATH.unshift( LIBDIR.to_s ) +BASEDIR = Pathname( __FILE__ ).dirname.relative_path_from( Pathname.pwd ) +LIBDIR = BASEDIR + 'lib' + 'symphony' EXPRESSION_RL = LIBDIR + 'metronome' + 'intervalexpression.rl' EXPRESSION_RB = LIBDIR + 'metronome' + 'intervalexpression.rb' - -if Rake.application.options.trace - $trace = true - $stderr.puts '$trace is enabled' -end - -# get the current library version -$version = ( LIBDIR + "#{PROJECT}.rb" ).read.split(/\n/). - select{|line| line =~ /VERSION =/}.first.match(/([\d|.]+)/)[1] +CLOBBER.include( EXPRESSION_RB.to_s ) task :default => [ :spec, :docs, :package ] @@ -32,116 +39,7 @@ file EXPRESSION_RB task EXPRESSION_RB => EXPRESSION_RL do |task| sh 'ragel', '-R', '-T1', '-Ls', task.prerequisites.first end + task :spec => EXPRESSION_RB - - -######################################################################## -### P A C K A G I N G -######################################################################## - -require 'rubygems' -require 'rubygems/package_task' -spec = Gem::Specification.new do |s| - s.email = 'mahlon@martini.nu' - s.homepage = 'http://projects.martini.nu/ruby-modules' - s.authors = [ 'Mahlon E. Smith ' ] - s.platform = Gem::Platform::RUBY - s.summary = "A natural language scheduling and task runner." - s.name = 'symphony-' + PROJECT - s.version = $version - s.license = 'BSD' - s.has_rdoc = true - s.require_path = 'lib' - s.bindir = 'bin' - s.files = File.read( __FILE__ ).split( /^__END__/, 2 ).last.split - s.executables = %w[ metronome-exp ] - s.description = <<-EOF - Metronome is a scheduler and task runner. It can be used locally as a - cron replacement, or as a network-wide job executor. Events are stored - via simple database rows, and optionally managed via AMQP events. - Interval/time values are expressed with reasonably intuitive English - phrases, ie.: 'at 2pm', or 'Starting in 20 minutes, run every 10 seconds - and then finish in 2 days'. - EOF - s.required_rubygems_version = '>= 2.0.3' - s.required_ruby_version = '>= 2.0.0' - - s.add_dependency 'symphony', '~> 0.11' - s.add_dependency 'sequel', '~> 5' - s.add_dependency 'sqlite3', '~> 1.3' - - s.add_development_dependency 'rspec', '~> 3.3' - s.add_development_dependency 'simplecov', '~> 0.9' - s.add_development_dependency 'timecop', '~> 0.7' -end - -Gem::PackageTask.new( spec ) do |pkg| - pkg.need_zip = true - pkg.need_tar = true -end - -######################################################################## -### D O C U M E N T A T I O N -######################################################################## - -begin - require 'rdoc/task' - - desc 'Generate rdoc documentation' - RDoc::Task.new do |rdoc| - rdoc.name = :docs - rdoc.rdoc_dir = 'docs' - rdoc.main = "README.rdoc" - rdoc.rdoc_files = [ 'lib', *FileList['*.rdoc'] ] - end - - RDoc::Task.new do |rdoc| - rdoc.name = :doc_coverage - rdoc.options = [ '-C1' ] - end - -rescue LoadError - $stderr.puts "Omitting 'docs' tasks, rdoc doesn't seem to be installed." -end - - -######################################################################## -### T E S T I N G -######################################################################## - -begin - require 'rspec/core/rake_task' - task :test => :spec - - desc "Run specs" - RSpec::Core::RakeTask.new do |t| - t.pattern = "spec/**/*_spec.rb" - end - - desc "Build a coverage report" - task :coverage do - ENV[ 'COVERAGE' ] = "yep" - Rake::Task[ :spec ].invoke - end - -rescue LoadError - $stderr.puts "Omitting testing tasks, rspec doesn't seem to be installed." -end - - -######################################################################## -### M A N I F E S T -######################################################################## -__END__ -bin/metronome-exp -data/symphony-metronome/migrations/20140419_initial.rb -data/symphony-metronome/migrations/20141028_lastrun.rb -lib/symphony/metronome/intervalexpression.rb -lib/symphony/metronome/intervalexpression.rl -lib/symphony/metronome/mixins.rb -lib/symphony/metronome/scheduledevent.rb -lib/symphony/metronome/scheduler.rb -lib/symphony/metronome.rb -lib/symphony/tasks/scheduletask.rb -README.rdoc +task :package => EXPRESSION_RB diff --git a/certs/mahlon.pem b/certs/mahlon.pem new file mode 100644 index 0000000..971e007 --- /dev/null +++ b/certs/mahlon.pem @@ -0,0 +1,25 @@ +-----BEGIN CERTIFICATE----- +MIIENDCCApygAwIBAgIBATANBgkqhkiG9w0BAQsFADAiMSAwHgYDVQQDDBdtYWhs +b24vREM9bWFydGluaS9EQz1udTAeFw0yMTAxMTcwMDQzMDZaFw0zMTAxMTUwMDQz +MDZaMCIxIDAeBgNVBAMMF21haGxvbi9EQz1tYXJ0aW5pL0RDPW51MIIBojANBgkq +hkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAsRZyNGaL3I8T2AkQsHKyixW10CY6T715 +uOztbmZImekhmgE9Uj5xZCnUP4xG5ToJffgkxcbepyJwIHCjEQg7viL9EsA+rMNb +UX8dsa9jpvVD6nHAdoW8G0ee7SRBXhCfyNma8FtkDJfw2bwdKhxUKiHsULCSQ0Pd +p+4d5NnldgfB8cf4Hz9Ai/8FHacWnZVEiHa4Ngb5Fe42OUs+4XDQdpcgA7wCY633 +q9rRVGK7MW9BzMv+hhQfElQMn1eDMgQVpO543viDT8JatwhhcYmKdzwTIIPAIybf +8MfJaimsh20OAqs3FAXNKjDVFbcXFfKUXXgVgMjUoEK5+Lp+pKPZXU4bIi5oYZqB +OttGPMD5rOWlAooWNQ7xbdHByUVqJmALSWHqPHdvVmAVsW8tNoB1qGbM+C6o80Ie +9H0389ja3TW4JK/0w/gFUmrVvYKRll44HaxS9nXNpiYBipbJmlR/R9qoe54ImQje +Z4vsWrWiDrK/oVYlUXOy7SE/jUAQF9UzAgMBAAGjdTBzMAkGA1UdEwQCMAAwCwYD +VR0PBAQDAgSwMB0GA1UdDgQWBBSx8TRqCmTPOARICKiZ3c66sIG3pTAcBgNVHREE +FTATgRFtYWhsb25AbWFydGluaS5udTAcBgNVHRIEFTATgRFtYWhsb25AbWFydGlu +aS5udTANBgkqhkiG9w0BAQsFAAOCAYEAHbiAZTe46/kp1Tkm4s6D30VBaYaAdaYG +bZIaAaHtJO9MbUNS0FA01fxQpptjpOQT3cNNf8CX8UHPTaSuPFMfgVWj1xiX7Byb +hqhUcUTENOuUxxWGDCa4orCFctc3yihojTKGtbhODHVSHf9DRDyalRcvmyWzxMFT +XtBS05OUXc9O1bKqzNaRc9nMGw6Y+V79hIex4mZlMBkhTeVKxeeweCXfELXOQRmB +FgPgUyQn0AaSpplx0YoWdy/99fEkXSMvgeEoiR1ApR6aUuTlvIr1yUgzVBpWU4mE +XC+Ig+3jhqufGyE/Do+1M7n5QLpgGfpy3QmoOiKeYt3XzR5Z7XoxCAaKHNRxVEga +ojmVnDNlLQkkZZkbFNGPHjCIBs7h+6eoIYvy/eQ82c4vd6w9rR4v9bKUL8NNkcSz +49pOzX5KHZLTS9DKeaP/xcGPz6C8MiwQdYrZarr2SHRASX1zFa79rkItO8kE6RDr +b6WDF79UvZ55ajtE00TiwqjQL/ZPEtbd +-----END CERTIFICATE----- diff --git a/gem.deps.rb b/gem.deps.rb new file mode 100644 index 0000000..69b1a22 --- /dev/null +++ b/gem.deps.rb @@ -0,0 +1,17 @@ +source 'https://rubygems.org/' + +gem 'sequel', '~> 5.66' +gem 'sorted_set', '~> 1.0' +gem 'sqlite3', '~> 1.6' +gem 'symphony', '~> 0.14' +gem 'yajl-ruby', '~> 1.4' + +group :development do + gem 'rake-deveiate', '~> 0.22' + gem 'rspec', '~> 3.12' + gem 'rdoc-generator-sixfish', '~> 0.3' + gem 'simplecov', '~> 0.22' + gem 'timecop', '~> 0.9' + gem 'pry', '~> 0.14' +end + diff --git a/lib/symphony/metronome.rb b/lib/symphony/metronome.rb index 4d74f67..c755906 100644 --- a/lib/symphony/metronome.rb +++ b/lib/symphony/metronome.rb @@ -9,10 +9,7 @@ module Symphony::Metronome Configurability # Library version constant - VERSION = '0.2.3' - - # Version-control revision constant - REVISION = %q$Revision: e3d11b2c9e48 $ + VERSION = '0.3.0' # The name of the environment variable to check for config file overrides CONFIG_ENV = 'METRONOME_CONFIG' diff --git a/lib/symphony/metronome/intervalexpression.rl b/lib/symphony/metronome/intervalexpression.rl index 653d73d..0218965 100644 --- a/lib/symphony/metronome/intervalexpression.rl +++ b/lib/symphony/metronome/intervalexpression.rl @@ -239,7 +239,7 @@ class Symphony::Metronome::IntervalExpression ### an expression was generated, you can 'reconstitute' an interval ### object this way. ### - def self::parse( exp, time=nil ) + def self::parse( exp, time=Time.now ) # Normalize the expression before parsing # @@ -250,7 +250,7 @@ class Symphony::Metronome::IntervalExpression gsub( /([:\-])+/, '\1' ). # collapse multiple - or : chars gsub( /\.+$/, '' ) # trailing periods - event = new( exp, time || Time.now ) + event = new( exp, time ) data = event.instance_variable_get( :@data ) # Ragel interface variables diff --git a/lib/symphony/metronome/scheduledevent.rb b/lib/symphony/metronome/scheduledevent.rb index 8926ef6..886f93d 100644 --- a/lib/symphony/metronome/scheduledevent.rb +++ b/lib/symphony/metronome/scheduledevent.rb @@ -21,19 +21,17 @@ class Symphony::Metronome::ScheduledEvent config_key :metronome - # Configure defaults. - # - CONFIG_DEFAULTS = { - :db => 'sqlite:///tmp/metronome.db', - :splay => 0 - } + ### Configurability API. + ### + configurability do - class << self + ## # A Sequel-style DB connection URI. - attr_reader :db + setting :db, default: 'sqlite:///tmp/metronome.db' + ## # Adjust recurring intervals by a random window. - attr_reader :splay + setting :splay, default: 0 end @@ -62,7 +60,6 @@ class Symphony::Metronome::ScheduledEvent ### Delete any rows that are invalid expressions. ### def self::load - now = Time.now events = SortedSet.new # Force reset the DB handle. diff --git a/lib/symphony/metronome/scheduler.rb b/lib/symphony/metronome/scheduler.rb index a1bc1a8..49778c9 100644 --- a/lib/symphony/metronome/scheduler.rb +++ b/lib/symphony/metronome/scheduler.rb @@ -17,22 +17,15 @@ class Symphony::Metronome::Scheduler # Signals the daemon responds to. SIGNALS = [ :HUP, :INT, :TERM ] - CONFIG_DEFAULTS = { - :listen => false - } - class << self + ### Configurability API. + ### + configurability do + # Should Metronome register and schedule events via AMQP? # If +false+, you'll need a separate way to add event actions # to the database, and manually HUP the daemon. - attr_reader :listen - end - - ### Configurability API - ### - def self::configure( config=nil ) - config = self.defaults.merge( config || {} ) - @listen = config.delete( :listen ) + setting :listen, default: false end diff --git a/spec/symphony/metronome/scheduledevent_spec.rb b/spec/symphony/metronome/scheduledevent_spec.rb index 8558658..d16a45b 100644 --- a/spec/symphony/metronome/scheduledevent_spec.rb +++ b/spec/symphony/metronome/scheduledevent_spec.rb @@ -33,11 +33,13 @@ describe Symphony::Metronome::ScheduledEvent do Timecop.travel( time ) end + it 'applies migrations upon initial config' do migrations = described_class.db[ :schema_migrations ].all expect( migrations.first[:filename] ).to eq( '20140419_initial.rb' ) end + it 'can load all stored events sorted by next execution time' do ds.insert( :created => Time.now, @@ -61,6 +63,7 @@ describe Symphony::Metronome::ScheduledEvent do expect( events.last.event.instance_variable_get(:@exp) ).to eq( 'at 3pm' ) end + it 'removes invalid expressions from storage when loading' do ds.insert( :created => Time.now, @@ -77,6 +80,7 @@ describe Symphony::Metronome::ScheduledEvent do end end + context 'an instance' do let( :time ) { Time.at(1262376000) } @@ -94,6 +98,7 @@ describe Symphony::Metronome::ScheduledEvent do expect( ev.runtime ).to eq( time ) end + it 'can reschedule itself into the future when recurring (past start)' do ev = described_class.new( :created => time, @@ -107,6 +112,7 @@ describe Symphony::Metronome::ScheduledEvent do expect( ev.runtime ).to be >= time + 3600 + 30 end + it 'can reschedule itself into the future when recurring (recently run)' do ds.insert( :created => time, @@ -120,9 +126,10 @@ describe Symphony::Metronome::ScheduledEvent do ev.reset_runtime end - expect( ev.runtime ).to be >= time + 18 + expect( ev.runtime ).to be >= time + 17 end + it 'removes itself when firing if expired' do ds.insert( :created => time, @@ -135,6 +142,7 @@ describe Symphony::Metronome::ScheduledEvent do expect( ds.count ).to eq( 0 ) end + it 'yields a deserialized options hash if okay to fire' do ev = described_class.new( :created => time, @@ -150,6 +158,7 @@ describe Symphony::Metronome::ScheduledEvent do expect( res ).to be( 12 ) end + it "won't re-fire recurring events if they already fired within their interval window" do ds.insert( :created => time, @@ -170,6 +179,7 @@ describe Symphony::Metronome::ScheduledEvent do expect( res ).to be( 0 ) end + it 'randomizes start times if a splay is configured' do described_class.instance_variable_set( :@splay, 5 )