Merge pull request #102 from cristianbica/integration_tests

Integration testing
This commit is contained in:
David Heinemeier Hansson 2014-08-08 09:15:30 -07:00
commit 14f74a8331
45 changed files with 574 additions and 52 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
/test/dummy/log/*
/test/dummy/tmp/*

View File

@ -1,5 +1,10 @@
before_install:
- travis_retry gem install bundler
- sudo apt-get update -qq
- sudo apt-get install beanstalkd
- echo "START=yes" | sudo tee -a /etc/default/beanstalkd
- sudo /etc/init.d/beanstalkd start
rvm:
- 1.9.3
- 2.0.0
@ -7,6 +12,8 @@ rvm:
- ruby-head
- rbx-2
- jruby
env:
- QC_DATABASE_URL="postgres://postgres@localhost/active_jobs_qc_int_test" QUE_DATABASE_URL="postgres://postgres@localhost/active_jobs_qc_int_test"
matrix:
allow_failures:
- rvm: rbx-2
@ -27,3 +34,6 @@ notifications:
- secure: AgZwJA+9VdnWAw7QN9Z5s6RpQIzsEB0q7V+p3pCzXY45156WocL8iNQx+KnyOQ8jbRUt4L/XIOiZl5xHf4pHjXytHWHNhetAlVQP/hPeDcCSk/h0g5gqgf6QABdp38tBNaUq866bXHgCOZYPwwP9bypcmuv2SLyfIO+b/PBgqN0=
services:
- redis
- rabbitmq
addons:
postgresql: "9.3"

View File

@ -14,3 +14,12 @@ gem 'que'
gem 'backburner'
gem 'qu-rails', github: "bkeepers/qu", branch: "master"
gem 'qu-redis'
#for integration testing
gem 'arel', github: 'rails/arel'
gem 'rack', github: 'rack/rack'
gem 'i18n', github: 'svenfuchs/i18n'
gem 'rails', github: 'rails/rails'
gem 'sqlite3'
gem 'delayed_job_active_record'
gem 'sequel'

View File

@ -1,6 +1,6 @@
GIT
remote: git://github.com/bkeepers/qu.git
revision: 2175633a834504423368d71cb10fb9f072d76cd2
revision: 50f3788f2b55ddd4dc939767fb35aebefa260322
branch: master
specs:
qu (0.2.0)
@ -11,6 +11,70 @@ GIT
qu (= 0.2.0)
redis-namespace
GIT
remote: git://github.com/rack/rack.git
revision: e98a9f7ef0ddd9589145ea953948c73a8ce3caa9
specs:
rack (1.6.0.alpha)
GIT
remote: git://github.com/rails/arel.git
revision: 66cee768bc163537087037a583f60639eae49fc3
specs:
arel (6.0.0.20140505020427)
GIT
remote: git://github.com/rails/rails.git
revision: b2e88043b52a8f83820a0f4e8a65aa42fd40c544
specs:
actionmailer (4.2.0.alpha)
actionpack (= 4.2.0.alpha)
actionview (= 4.2.0.alpha)
mail (~> 2.5, >= 2.5.4)
actionpack (4.2.0.alpha)
actionview (= 4.2.0.alpha)
activesupport (= 4.2.0.alpha)
rack (~> 1.6.0.alpha)
rack-test (~> 0.6.2)
actionview (4.2.0.alpha)
activesupport (= 4.2.0.alpha)
builder (~> 3.1)
erubis (~> 2.7.0)
activemodel (4.2.0.alpha)
activesupport (= 4.2.0.alpha)
builder (~> 3.1)
activerecord (4.2.0.alpha)
activemodel (= 4.2.0.alpha)
activesupport (= 4.2.0.alpha)
arel (~> 6.0.0)
activesupport (4.2.0.alpha)
i18n (>= 0.7.0.dev, < 0.8)
json (~> 1.7, >= 1.7.7)
minitest (~> 5.1)
thread_safe (~> 0.1)
tzinfo (~> 1.1)
rails (4.2.0.alpha)
actionmailer (= 4.2.0.alpha)
actionpack (= 4.2.0.alpha)
actionview (= 4.2.0.alpha)
activemodel (= 4.2.0.alpha)
activerecord (= 4.2.0.alpha)
activesupport (= 4.2.0.alpha)
bundler (>= 1.3.0, < 2.0)
railties (= 4.2.0.alpha)
sprockets-rails (~> 2.1)
railties (4.2.0.alpha)
actionpack (= 4.2.0.alpha)
activesupport (= 4.2.0.alpha)
rake (>= 0.8.7)
thor (>= 0.18.1, < 2.0)
GIT
remote: git://github.com/svenfuchs/i18n.git
revision: cb679b8cdbab675703a3f88de4d48a48f7b50e06
specs:
i18n (0.7.0.dev)
PATH
remote: .
specs:
@ -21,27 +85,9 @@ PATH
GEM
remote: https://rubygems.org/
specs:
actionpack (4.1.1)
actionview (= 4.1.1)
activesupport (= 4.1.1)
rack (~> 1.5.2)
rack-test (~> 0.6.2)
actionview (4.1.1)
activesupport (= 4.1.1)
builder (~> 3.1)
erubis (~> 2.7.0)
activemodel (4.1.1)
activesupport (= 4.1.1)
builder (~> 3.1)
activemodel-globalid (0.1.0)
activemodel-globalid (0.1.1)
activemodel (>= 4.1.0)
activesupport (>= 4.1.0)
activesupport (4.1.1)
i18n (~> 0.6, >= 0.6.9)
json (~> 1.7, >= 1.7.7)
minitest (~> 5.1)
thread_safe (~> 0.1)
tzinfo (~> 1.1)
amq-protocol (1.9.2)
backburner (0.4.5)
beaneater (~> 0.3.1)
@ -54,54 +100,56 @@ GEM
timers (~> 1.1.0)
connection_pool (2.0.0)
dante (0.1.5)
delayed_job (4.0.1)
delayed_job (4.0.2)
activesupport (>= 3.0, < 4.2)
delayed_job_active_record (4.0.1)
activerecord (>= 3.0, < 4.2)
delayed_job (>= 3.0, < 4.1)
erubis (2.7.0)
i18n (0.6.9)
hike (1.2.3)
json (1.8.1)
minitest (5.3.4)
mail (2.6.1)
mime-types (>= 1.16, < 3)
mime-types (2.3)
minitest (5.4.0)
mono_logger (1.1.0)
multi_json (1.9.3)
multi_json (1.10.1)
pg (0.17.1)
que (0.7.3)
que (0.8.1)
queue_classic (2.2.3)
pg (~> 0.17.0)
rack (1.5.2)
rack-protection (1.5.2)
rack-protection (1.5.3)
rack
rack-test (0.6.2)
rack (>= 1.0)
railties (4.1.1)
actionpack (= 4.1.1)
activesupport (= 4.1.1)
rake (>= 0.8.7)
thor (>= 0.18.1, < 2.0)
rake (10.3.2)
redis (3.0.7)
redis-namespace (1.4.1)
redis (~> 3.0.4)
resque (1.24.1)
redis (3.1.0)
redis-namespace (1.5.1)
redis (~> 3.0, >= 3.0.4)
resque (1.25.2)
mono_logger (~> 1.0)
multi_json (~> 1.0)
redis-namespace (~> 1.2)
redis-namespace (~> 1.3)
sinatra (>= 0.9.2)
vegas (~> 0.1.2)
resque-scheduler (2.2.0)
redis (>= 3.0.0)
resque (>= 1.20.0, < 1.25)
resque-scheduler (3.0.0)
mono_logger (~> 1.0)
redis (~> 3.0)
resque (~> 1.25)
rufus-scheduler (~> 2.0)
rufus-scheduler (2.0.24)
tzinfo (>= 0.3.22)
serverengine (1.5.7)
sequel (4.8.0)
serverengine (1.5.9)
sigdump (~> 0.2.2)
sidekiq (3.0.2)
sidekiq (3.2.1)
celluloid (>= 0.15.2)
connection_pool (>= 2.0.0)
json
redis (>= 3.0.6)
redis-namespace (>= 1.3.1)
sigdump (0.2.2)
sinatra (1.4.4)
sinatra (1.4.5)
rack (~> 1.4)
rack-protection (~> 1.4)
tilt (~> 1.3, >= 1.3.4)
@ -110,14 +158,24 @@ GEM
serverengine
thor
thread
sucker_punch (1.0.5)
sprockets (2.12.1)
hike (~> 1.2)
multi_json (~> 1.0)
rack (~> 1.0)
tilt (~> 1.1, != 1.3.0)
sprockets-rails (2.1.3)
actionpack (>= 3.0)
activesupport (>= 3.0)
sprockets (~> 2.8)
sqlite3 (1.3.9)
sucker_punch (1.1)
celluloid (~> 0.15.2)
thor (0.19.1)
thread (0.1.4)
thread_safe (0.3.3)
thread_safe (0.3.4)
tilt (1.4.1)
timers (1.1.0)
tzinfo (1.1.0)
tzinfo (1.2.1)
thread_safe (~> 0.1)
vegas (0.1.11)
rack (>= 1.0.0)
@ -127,15 +185,22 @@ PLATFORMS
DEPENDENCIES
activejob!
arel!
backburner
delayed_job
delayed_job_active_record
i18n!
qu-rails!
qu-redis
que
queue_classic
rack!
rails!
rake
resque
resque-scheduler
sequel
sidekiq
sneakers (= 0.1.1.pre)
sqlite3
sucker_punch

View File

@ -18,13 +18,15 @@ end
task default: :test
ADAPTERS = %w(inline delayed_job qu que queue_classic resque sidekiq sneakers sucker_punch backburner)
desc 'Run all adapter tests'
task :test do
tasks = %w(test_inline test_delayed_job test_qu test_que test_queue_classic test_resque test_sidekiq test_sneakers test_sucker_punch test_backburner)
tasks = ADAPTERS.map{|a| "test_#{a}" }+["integration_test"]
run_without_aborting(*tasks)
end
%w(inline delayed_job qu que queue_classic resque sidekiq sneakers sucker_punch backburner).each do |adapter|
ADAPTERS.each do |adapter|
Rake::TestTask.new("test_#{adapter}") do |t|
t.libs << 'test'
t.test_files = FileList['test/cases/**/*_test.rb']
@ -38,3 +40,29 @@ end
task "test_#{adapter}" => "#{adapter}:env"
end
desc 'Run all adapter integration tests'
task :integration_test do
tasks = (ADAPTERS-['inline']).map{|a| "integration_test_#{a}" }
run_without_aborting(*tasks)
end
(ADAPTERS-['inline']).each do |adapter|
Rake::TestTask.new("integration_test_#{adapter}") do |t|
t.libs << 'test'
t.test_files = FileList['test/integration/**/*_test.rb']
t.verbose = true
end
namespace "integration_#{adapter}" do
task test: "integration_test_#{adapter}"
task(:env) do
ENV['AJADAPTER'] = adapter
ENV['AJ_INTEGRATION_TESTS'] = "1"
end
end
task "integration_test_#{adapter}" => "integration_#{adapter}:env"
end

View File

@ -21,6 +21,7 @@ module ActiveJob
class JobWrapper
include Sneakers::Worker
from_queue 'active_jobs_default'
def work(msg)
job_name, *args = ActiveSupport::JSON.decode(msg)

3
test/dummy/Rakefile Normal file
View File

@ -0,0 +1,3 @@
require 'sneakers/tasks'
require File.expand_path('../config/application', __FILE__)
Rails.application.load_tasks

View File

View File

@ -0,0 +1,3 @@
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
end

View File

@ -0,0 +1,2 @@
module ApplicationHelper
end

View File

@ -0,0 +1,9 @@
class TestJob < ActiveJob::Base
queue_as :default
def perform(x)
File.open(Rails.root.join("tmp/#{x}"), "w+") do |f|
f.write x
end
end
end

View File

View File

View File

4
test/dummy/config.ru Normal file
View File

@ -0,0 +1,4 @@
# This file is used by Rack-based servers to start the application.
require ::File.expand_path('../config/environment', __FILE__)
run Rails.application

View File

@ -0,0 +1,9 @@
require File.expand_path('../boot', __FILE__)
require 'rails/all'
Bundler.require(*Rails.groups)
module Dummy
class Application < Rails::Application
end
end

View File

@ -0,0 +1,5 @@
# Set up gems listed in the Gemfile.
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../../../Gemfile', __FILE__)
require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
$LOAD_PATH.unshift File.expand_path('../../../../lib', __FILE__)

View File

@ -0,0 +1,3 @@
test:
adapter: sqlite3
database: "db/test.sqlite3"

View File

@ -0,0 +1,2 @@
require File.expand_path('../application', __FILE__)
Rails.application.initialize!

View File

@ -0,0 +1,13 @@
Rails.application.configure do
config.cache_classes = true
config.eager_load = false
config.serve_static_assets = true
config.static_cache_control = 'public, max-age=3600'
config.consider_all_requests_local = true
config.action_controller.perform_caching = false
config.action_dispatch.show_exceptions = false
config.action_controller.allow_forgery_protection = false
config.action_mailer.delivery_method = :test
config.active_support.deprecation = :stderr
config.log_level = :debug
end

View File

@ -0,0 +1,65 @@
case ENV['AJADAPTER']
when "delayed_job"
ActiveJob::Base.queue_adapter = :delayed_job
when "sidekiq"
ActiveJob::Base.queue_adapter = :sidekiq
when "resque"
ActiveJob::Base.queue_adapter = :resque
Resque.redis = Redis::Namespace.new 'active_jobs_int_test', redis: Redis.connect(url: "tcp://127.0.0.1:6379/12", :thread_safe => true)
Resque.logger = Rails.logger
when 'qu'
ActiveJob::Base.queue_adapter = :qu
ENV['REDISTOGO_URL'] = "tcp://127.0.0.1:6379/12"
backend = Qu::Backend::Redis.new
backend.namespace = "active_jobs_int_test"
Qu.backend = backend
Qu.logger = Rails.logger
Qu.interval = 0.5
when 'que'
ActiveJob::Base.queue_adapter = :que
QUE_URL = ENV['QUE_DATABASE_URL'] || 'postgres://localhost/active_jobs_que_int_test'
uri = URI.parse(QUE_URL)
user = uri.user||ENV['USER']
pass = uri.password
db = uri.path[1..-1]
%x{#{"PGPASSWORD=\"#{pass}\"" if pass} psql -c 'drop database "#{db}"' -U #{user} -t template1}
%x{#{"PGPASSWORD=\"#{pass}\"" if pass} psql -c 'create database "#{db}"' -U #{user} -t template1}
Que.connection = Sequel.connect(QUE_URL)
Que.migrate!
Que.mode = :off
Que.worker_count = 1
when 'queue_classic'
ENV['QC_DATABASE_URL'] ||= 'postgres://localhost/active_jobs_qc_int_test'
ENV['QC_LISTEN_TIME'] = "0.5"
ActiveJob::Base.queue_adapter = :queue_classic
uri = URI.parse(ENV['QC_DATABASE_URL'])
user = uri.user||ENV['USER']
pass = uri.password
db = uri.path[1..-1]
%x{#{"PGPASSWORD=\"#{pass}\"" if pass} psql -c 'drop database "#{db}"' -U #{user} -t template1}
%x{#{"PGPASSWORD=\"#{pass}\"" if pass} psql -c 'create database "#{db}"' -U #{user} -t template1}
QC::Setup.create
when 'sidekiq'
ActiveJob::Base.queue_adapter = :sidekiq
when 'sneakers'
ActiveJob::Base.queue_adapter = :sneakers
Sneakers.configure :heartbeat => 2,
:amqp => 'amqp://guest:guest@localhost:5672',
:vhost => '/',
:exchange => 'active_jobs_sneakers_int_test',
:exchange_type => :direct,
:daemonize => true,
:threads => 1,
:workers => 1,
:pid_path => Rails.root.join("tmp/sneakers.pid").to_s,
:log => Rails.root.join("log/sneakers.log").to_s
when 'sucker_punch'
ActiveJob::Base.queue_adapter = :sucker_punch
when 'backburner'
ActiveJob::Base.queue_adapter = :backburner
Backburner.configure do |config|
config.logger = Rails.logger
end
else
ActiveJob::Base.queue_adapter = nil
end

View File

@ -0,0 +1 @@
Rails.application.config.session_store :cookie_store, key: '_dummy_session'

View File

@ -0,0 +1,2 @@
Rails.application.routes.draw do
end

View File

@ -0,0 +1,2 @@
test:
secret_key_base: b83ee5aeada663bc4270a1817d0ca43b2784017cc77dc8afcd60967cc968d4ce30caff9eb682766129e18a4048c4d5ebf14eabf463fc37ad67c18934f4345545

View File

@ -0,0 +1,22 @@
class CreateDelayedJobs < ActiveRecord::Migration
def self.up
create_table :delayed_jobs, :force => true do |table|
table.integer :priority, :default => 0, :null => false # Allows some jobs to jump to the front of the queue
table.integer :attempts, :default => 0, :null => false # Provides for retries, but still fail eventually.
table.text :handler, :null => false # YAML-encoded string of the object that will do work
table.text :last_error # reason for last failure (See Note below)
table.datetime :run_at # When to run. Could be Time.zone.now for immediately, or sometime in the future.
table.datetime :locked_at # Set when a client is working on this object
table.datetime :failed_at # Set when all retries have failed (actually, by default, the record is deleted instead)
table.string :locked_by # Who is working on this object (if locked)
table.string :queue # The name of the queue this job is in
table.timestamps
end
add_index :delayed_jobs, [:priority, :run_at], :name => 'delayed_jobs_priority'
end
def self.down
drop_table :delayed_jobs
end
end

32
test/dummy/db/schema.rb Normal file
View File

@ -0,0 +1,32 @@
# encoding: UTF-8
# This file is auto-generated from the current state of the database. Instead
# of editing this file, please use the migrations feature of Active Record to
# incrementally modify your database, and then regenerate this schema definition.
#
# Note that this schema.rb definition is the authoritative source for your
# database schema. If you need to create the application database on another
# system, you should be using db:schema:load, not running all the migrations
# from scratch. The latter is a flawed and unsustainable approach (the more migrations
# you'll amass, the slower it'll run and the greater likelihood for issues).
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20140804200445) do
create_table "delayed_jobs", force: true do |t|
t.integer "priority", default: 0, null: false
t.integer "attempts", default: 0, null: false
t.text "handler", null: false
t.text "last_error"
t.datetime "run_at"
t.datetime "locked_at"
t.datetime "failed_at"
t.string "locked_by"
t.string "queue"
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "delayed_jobs", ["priority", "run_at"], name: "delayed_jobs_priority"
end

BIN
test/dummy/db/test.sqlite3 Normal file

Binary file not shown.

View File

0
test/dummy/log/.keep Normal file
View File

0
test/dummy/tmp/.keep Normal file
View File

View File

@ -6,10 +6,14 @@ $LOAD_PATH << File.dirname(__FILE__) + "/../lib"
require 'active_job'
adapter = ENV['AJADAPTER'] || 'inline'
require "adapters/#{adapter}"
puts "Testing using #{adapter}"
puts "Testing#{" integration" if ENV['AJ_INTEGRATION_TESTS']} using #{adapter}"
if ENV['AJ_INTEGRATION_TESTS']
require 'support/integration/helper'
else
require "adapters/#{adapter}"
end
require 'active_support/testing/autorun'
ActiveJob::Base.logger.level = Logger::ERROR
ActiveJob::Base.logger.level = Logger::DEBUG

View File

@ -0,0 +1,18 @@
require 'helper'
require 'jobs/logging_job'
require 'active_support/core_ext/numeric/time'
class QueuingTest < ActiveSupport::TestCase
setup do
end
test 'run queued job' do
id = "AJ-#{SecureRandom.uuid}"
TestJob.enqueue id
sleep 2
assert Dummy::Application.root.join("tmp/#{id}").exist?
end
end

View File

@ -0,0 +1,15 @@
module BackburnerJobsManager
def clear_jobs
Backburner::Worker.connection.tubes.all.map &:clear
end
def start_workers
@thread = Thread.new { Backburner.work "active-jobs-default" }
end
def stop_workers
@thread.kill
end
end

View File

@ -0,0 +1,14 @@
module DelayedJobJobsManager
def clear_jobs
Delayed::Job.delete_all
end
def start_workers
@worker = Delayed::Worker.new(quiet: false, sleep_delay: 0.5)
@thread = Thread.new { @worker.start }
end
def stop_workers
@worker.stop
end
end

View File

@ -0,0 +1,14 @@
module QuJobsManager
def clear_jobs
Qu.clear "active_jobs_default"
end
def start_workers
@thread = Thread.new { Qu::Worker.new("active_jobs_default").start }
end
def stop_workers
@thread.kill
end
end

View File

@ -0,0 +1,19 @@
module QueJobsManager
def clear_jobs
Que.clear!
end
def start_workers
@thread = Thread.new do
loop do
Que::Job.work("active_jobs_default")
sleep 0.5
end
end
end
def stop_workers
@thread.kill
end
end

View File

@ -0,0 +1,21 @@
module QC; WAIT_TIME = 0.5; end
module QueueClassicJobsManager
def clear_jobs
# disabling this as it locks
# QC::Queue.new("active_jobs_default").delete_all
end
def start_workers
@pid = fork do
QC::Conn.connection = QC::Conn.connect
worker = QC::Worker.new(q_name: 'active_jobs_default')
worker.start
end
end
def stop_workers
Process.kill 'HUP', @pid
end
end

View File

@ -0,0 +1,18 @@
module ResqueJobsManager
def clear_jobs
Resque.queues.each { |queue_name| Resque.redis.del "queue:#{queue_name}" }
Resque.redis.keys("delayed:*").each { |key| Resque.redis.del "#{key}" }
Resque.redis.del "delayed_queue_schedule"
end
def start_workers
@thread = Thread.new do
Resque::Worker.new("*").work(0.5)
end
end
def stop_workers
@thread.kill
end
end

View File

@ -0,0 +1,19 @@
require 'sidekiq/launcher'
require 'sidekiq/api'
module SidekiqJobsManager
def clear_jobs
Sidekiq::Queue.new("active_jobs_default").clear
end
def start_workers
options = {:queues=>["active_jobs_default"], :concurrency=>1, :environment=>"test", :timeout=>8, :daemon=>true, :strict=>true}
@launcher = Sidekiq::Launcher.new(options)
@launcher.run
end
def stop_workers
@launcher.stop
end
end

View File

@ -0,0 +1,18 @@
require 'sneakers/runner'
module SneakersJobsManager
def clear_jobs
end
def start_workers
cmd = %{cd #{Rails.root.to_s} && (RAILS_ENV=test AJADAPTER=sneakers WORKERS=ActiveJob::QueueAdapters::SneakersAdapter::JobWrapper bundle exec rake --trace sneakers:run)}
`#{cmd}`
while !Rails.root.join("tmp/sneakers.pid").exist? do
sleep 0.5
end
end
def stop_workers
Process.kill 'TERM', File.open(Rails.root.join("tmp/sneakers.pid").to_s).read.to_i
end
end

View File

@ -0,0 +1,5 @@
module SuckerPunchJobsManager
def clear_jobs
end
end

View File

@ -0,0 +1,12 @@
ENV["RAILS_ENV"] = "test"
require File.expand_path("../../../dummy/config/environment.rb", __FILE__)
require "rails/test_help"
Rails.backtrace_cleaner.remove_silencers!
require_relative 'test_case_helpers'
ActiveSupport::TestCase.send(:include, TestCaseHelpers)
JobsManager.current_manager.setup
JobsManager.current_manager.start_workers
Minitest.after_run { JobsManager.current_manager.stop_workers }

View File

@ -0,0 +1,23 @@
class JobsManager
@@managers = {}
attr :adapter_name
def self.current_manager
@@managers[ENV['AJADAPTER']] ||= new(ENV['AJADAPTER'])
end
def initialize(adapter_name)
@adapter_name = adapter_name
require_relative "adapters/#{adapter_name}"
extend "#{adapter_name.camelize}JobsManager".constantize
end
def setup
end
def start_workers
end
def stop_workers
end
end

View File

@ -0,0 +1,30 @@
require 'active_support/concern'
require 'support/integration/jobs_manager'
module TestCaseHelpers
extend ActiveSupport::Concern
included do
self.use_transactional_fixtures = false
setup do
clear_jobs
end
teardown do
clear_jobs
FileUtils.rm_rf Dir[Dummy::Application.root.join("tmp/AJ-*")]
end
end
protected
def jobs_manager
JobsManager.current_manager
end
def clear_jobs
jobs_manager.clear_jobs
end
end