marty 2.7.3 → 2.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +4 -1
- data/README.md +7 -0
- data/app/components/marty/background_job_schedule_view.rb +94 -0
- data/app/components/marty/main_auth_app.rb +46 -23
- data/app/jobs/marty/cron_job.rb +41 -0
- data/app/models/marty/background_job.rb +4 -0
- data/app/models/marty/background_job/schedule.rb +27 -0
- data/app/services/marty/background_job/update_schedule.rb +34 -0
- data/app/services/marty/jobs/schedule.rb +17 -0
- data/db/migrate/505_add_cron_to_delayed_jobs.rb +9 -0
- data/db/migrate/506_create_marty_delayed_job_schedules.rb +13 -0
- data/lib/marty.rb +1 -0
- data/lib/marty/version.rb +1 -1
- data/lib/tasks/marty_jobs.rake +8 -0
- data/make-dummy.mk +4 -2
- data/marty.gemspec +2 -1
- data/spec/dummy/app/jobs/test_job.rb +4 -0
- data/spec/dummy/app/jobs/test_job2.rb +4 -0
- data/spec/dummy/config/application.rb +2 -0
- data/spec/features/background_job_schedule_spec.rb +112 -0
- data/spec/models/background_job/schedule.rb +43 -0
- data/spec/support/chromedriver.rb +11 -1
- metadata +31 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1e99ecbf41a6cda553cf318fb21bbe9c3150ec13e46b074171eaa1bd1ea12aed
|
4
|
+
data.tar.gz: c6dcdf2a95d456e27189c1369ff54de3d62ce4cd58b5d7125bf8f83d57ba8d57
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a43ae65fe90a06f4c1c35652aaba4627431ea449fedc6c262aa37a384d5d4e02d879a47c145b9dab56c756025d42e92d2c49e1a9658301ba50598164dc3e514b
|
7
|
+
data.tar.gz: ef2702ad5285cb59f777faa7b1ecceecd570945e490100e6542cd3fe7e237e597d491e3b9e7f7b9de32149645959b9142481efc3bf8614330a344a234f9c2397
|
data/Gemfile.lock
CHANGED
@@ -6,8 +6,9 @@ PATH
|
|
6
6
|
axlsx (= 3.0.0pre)
|
7
7
|
coderay
|
8
8
|
daemons (~> 1.3.1)
|
9
|
+
delayed_cron_job
|
9
10
|
delayed_job_active_record
|
10
|
-
delorean_lang (~> 0.6
|
11
|
+
delorean_lang (~> 0.6)
|
11
12
|
json-schema
|
12
13
|
mcfly (~> 0.0.20)
|
13
14
|
net-ldap (~> 0.16.1)
|
@@ -89,6 +90,8 @@ GEM
|
|
89
90
|
crass (1.0.4)
|
90
91
|
daemons (1.3.1)
|
91
92
|
database_cleaner (1.7.0)
|
93
|
+
delayed_cron_job (0.7.2)
|
94
|
+
delayed_job (>= 4.1)
|
92
95
|
delayed_job (4.1.5)
|
93
96
|
activesupport (>= 3.0, < 5.3)
|
94
97
|
delayed_job_active_record (4.1.3)
|
data/README.md
CHANGED
@@ -50,6 +50,13 @@ To delete scripts:
|
|
50
50
|
```
|
51
51
|
$ rake marty:delete_scripts
|
52
52
|
```
|
53
|
+
# Scheduled Job
|
54
|
+
|
55
|
+
To use scheduled backgroud jobs, add to `config/application.rb`:
|
56
|
+
|
57
|
+
```
|
58
|
+
config.active_job.queue_adapter = :delayed_job
|
59
|
+
```
|
53
60
|
|
54
61
|
# Dummy Application & Testing
|
55
62
|
|
@@ -0,0 +1,94 @@
|
|
1
|
+
class Marty::BackgroundJobScheduleView < Marty::Grid
|
2
|
+
ACCESSIBLE_BY = [:admin]
|
3
|
+
|
4
|
+
has_marty_permissions(
|
5
|
+
read: ACCESSIBLE_BY,
|
6
|
+
create: ACCESSIBLE_BY,
|
7
|
+
update: ACCESSIBLE_BY,
|
8
|
+
delete: ACCESSIBLE_BY,
|
9
|
+
destroy: ACCESSIBLE_BY,
|
10
|
+
edit_window__edit_form__submit: ACCESSIBLE_BY,
|
11
|
+
add_window__add_form__submit: ACCESSIBLE_BY
|
12
|
+
)
|
13
|
+
|
14
|
+
def configure(c)
|
15
|
+
super
|
16
|
+
|
17
|
+
c.title ||= I18n.t('delayed_jobs_schedule_view_title', default: 'Background Jobs Schedule')
|
18
|
+
c.model = 'Marty::BackgroundJob::Schedule'
|
19
|
+
c.paging = :buffered
|
20
|
+
c.editing = :in_form
|
21
|
+
|
22
|
+
c.attributes = [
|
23
|
+
:job_class,
|
24
|
+
:cron,
|
25
|
+
:state
|
26
|
+
]
|
27
|
+
end
|
28
|
+
|
29
|
+
def default_context_menu
|
30
|
+
[]
|
31
|
+
end
|
32
|
+
|
33
|
+
attribute :job_class do |c|
|
34
|
+
c.width = 400
|
35
|
+
end
|
36
|
+
|
37
|
+
attribute :cron do |c|
|
38
|
+
c.width = 400
|
39
|
+
end
|
40
|
+
|
41
|
+
attribute :state do |c|
|
42
|
+
c.width = 150
|
43
|
+
editor_config = {
|
44
|
+
trigger_action: :all,
|
45
|
+
xtype: :combo,
|
46
|
+
store: Marty::BackgroundJob::Schedule::ALL_STATES,
|
47
|
+
forceSelection: true,
|
48
|
+
}
|
49
|
+
|
50
|
+
c.column_config = { editor: editor_config }
|
51
|
+
c.field_config = editor_config
|
52
|
+
end
|
53
|
+
|
54
|
+
endpoint :edit_window__edit_form__submit do |params|
|
55
|
+
result = super(params)
|
56
|
+
next result if result.empty?
|
57
|
+
|
58
|
+
obj_hash = result.first
|
59
|
+
Marty::BackgroundJob::UpdateSchedule.call(id: obj_hash['id'], job_class: obj_hash['job_class'])
|
60
|
+
|
61
|
+
result
|
62
|
+
end
|
63
|
+
|
64
|
+
endpoint :add_window__add_form__submit do |params|
|
65
|
+
result = super(params)
|
66
|
+
next result if result.empty?
|
67
|
+
|
68
|
+
obj_hash = result.first
|
69
|
+
Marty::BackgroundJob::UpdateSchedule.call(id: obj_hash['id'], job_class: obj_hash['job_class'])
|
70
|
+
|
71
|
+
result
|
72
|
+
end
|
73
|
+
|
74
|
+
endpoint :multiedit_window__multiedit_form__submit do |_params|
|
75
|
+
client.netzke_notify 'Multiediting is disabled for cron schedules'
|
76
|
+
end
|
77
|
+
|
78
|
+
endpoint :destroy do |params|
|
79
|
+
res = params.each_with_object({}) do |id, hash|
|
80
|
+
job_class = model.find_by(id: id)&.job_class
|
81
|
+
result = super([id])
|
82
|
+
|
83
|
+
# Do nothing If it wasn't destroyed
|
84
|
+
next hash.merge(result) unless result[id.to_i] == 'ok'
|
85
|
+
|
86
|
+
Marty::BackgroundJob::UpdateSchedule.call(id: id, job_class: job_class)
|
87
|
+
hash.merge(result)
|
88
|
+
end
|
89
|
+
|
90
|
+
res
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
BackgroundJobScheduleView = Marty::BackgroundJobScheduleView
|
@@ -1,16 +1,17 @@
|
|
1
|
-
require 'marty/scripting'
|
2
|
-
require 'marty/reporting'
|
3
|
-
require 'marty/posting_window'
|
4
|
-
require 'marty/new_posting_window'
|
5
|
-
require 'marty/import_type_view'
|
6
|
-
require 'marty/user_view'
|
7
|
-
require 'marty/event_view'
|
8
|
-
require 'marty/promise_view'
|
9
1
|
require 'marty/api_auth_view'
|
10
2
|
require 'marty/api_config_view'
|
11
3
|
require 'marty/api_log_view'
|
12
4
|
require 'marty/config_view'
|
13
5
|
require 'marty/data_grid_view'
|
6
|
+
require 'marty/background_job_schedule_view'
|
7
|
+
require 'marty/event_view'
|
8
|
+
require 'marty/import_type_view'
|
9
|
+
require 'marty/new_posting_window'
|
10
|
+
require 'marty/posting_window'
|
11
|
+
require 'marty/promise_view'
|
12
|
+
require 'marty/reporting'
|
13
|
+
require 'marty/scripting'
|
14
|
+
require 'marty/user_view'
|
14
15
|
|
15
16
|
class Marty::MainAuthApp < Marty::AuthApp
|
16
17
|
extend ::Marty::Permissions
|
@@ -112,6 +113,7 @@ class Marty::MainAuthApp < Marty::AuthApp
|
|
112
113
|
:bg_status,
|
113
114
|
:bg_stop,
|
114
115
|
:bg_restart,
|
116
|
+
:background_job_schedule_view,
|
115
117
|
]
|
116
118
|
},
|
117
119
|
]
|
@@ -276,6 +278,14 @@ class Marty::MainAuthApp < Marty::AuthApp
|
|
276
278
|
a.disabled = !self.class.has_admin_perm?
|
277
279
|
end
|
278
280
|
|
281
|
+
action :background_job_schedule_view do |a|
|
282
|
+
a.text = 'Schedule Background Jobs'
|
283
|
+
a.tooltip = 'Edit Delayed Jobs Cron schedules'
|
284
|
+
a.icon_cls = 'fa fa-cog glyph'
|
285
|
+
a.disabled = !self.class.has_admin_perm?
|
286
|
+
a.handler = :netzke_load_component_by_action
|
287
|
+
end
|
288
|
+
|
279
289
|
action :log_view do |a|
|
280
290
|
a.text = 'View Log'
|
281
291
|
a.tooltip = 'View Log'
|
@@ -365,31 +375,44 @@ class Marty::MainAuthApp < Marty::AuthApp
|
|
365
375
|
end
|
366
376
|
|
367
377
|
######################################################################
|
368
|
-
|
369
|
-
component :scripting do |c|
|
370
|
-
c.allow_edit = self.class.has_scripting_perm?
|
371
|
-
end
|
372
|
-
component :reporting
|
373
|
-
component :promise_view
|
374
|
-
component :posting_window
|
375
|
-
component :new_posting_window do |c|
|
376
|
-
c.disabled = Marty::Util.warped? || !self.class.has_posting_perm?
|
377
|
-
end
|
378
|
-
component :import_type_view
|
379
|
-
component :user_view
|
380
|
-
component :event_view
|
381
|
-
component :config_view
|
382
|
-
component :data_grid_view
|
383
378
|
component :api_auth_view do |c|
|
384
379
|
c.disabled = Marty::Util.warped?
|
385
380
|
end
|
381
|
+
|
386
382
|
component :api_log_view
|
383
|
+
|
387
384
|
component :api_config_view
|
388
385
|
|
386
|
+
component :background_job_schedule_view
|
387
|
+
|
388
|
+
component :config_view
|
389
|
+
|
390
|
+
component :data_grid_view
|
391
|
+
|
392
|
+
component :event_view
|
393
|
+
|
394
|
+
component :import_type_view
|
395
|
+
|
389
396
|
component :log_view do |c|
|
390
397
|
c.klass = Marty::LogView
|
391
398
|
end
|
392
399
|
|
400
|
+
component :new_posting_window do |c|
|
401
|
+
c.disabled = Marty::Util.warped? || !self.class.has_posting_perm?
|
402
|
+
end
|
403
|
+
|
404
|
+
component :posting_window
|
405
|
+
|
406
|
+
component :promise_view
|
407
|
+
|
408
|
+
component :reporting
|
409
|
+
|
410
|
+
component :scripting do |c|
|
411
|
+
c.allow_edit = self.class.has_scripting_perm?
|
412
|
+
end
|
413
|
+
|
414
|
+
component :user_view
|
415
|
+
|
393
416
|
endpoint :reload_scripts do |_params|
|
394
417
|
Marty::Script.load_scripts
|
395
418
|
client.netzke_notify 'Scripts have been reloaded'
|
@@ -0,0 +1,41 @@
|
|
1
|
+
class Marty::CronJob < ActiveJob::Base
|
2
|
+
class << self
|
3
|
+
def schedule
|
4
|
+
return reschedule if scheduled?
|
5
|
+
|
6
|
+
cron = cron_expression
|
7
|
+
|
8
|
+
return if cron.blank?
|
9
|
+
|
10
|
+
set(cron: cron).perform_later
|
11
|
+
end
|
12
|
+
|
13
|
+
def reschedule
|
14
|
+
dj = delayed_job
|
15
|
+
return dj.update(cron: cron_expression) if dj.locked_by?
|
16
|
+
|
17
|
+
remove
|
18
|
+
schedule
|
19
|
+
end
|
20
|
+
|
21
|
+
def remove
|
22
|
+
delayed_job.destroy if scheduled?
|
23
|
+
end
|
24
|
+
|
25
|
+
alias remove_schedule remove
|
26
|
+
|
27
|
+
def scheduled?
|
28
|
+
delayed_job.present?
|
29
|
+
end
|
30
|
+
|
31
|
+
def delayed_job
|
32
|
+
Delayed::Job.
|
33
|
+
where('handler LIKE ?', "%job_class: #{name}\n%").
|
34
|
+
first
|
35
|
+
end
|
36
|
+
|
37
|
+
def cron_expression
|
38
|
+
::Marty::BackgroundJob::Schedule.on.find_by(job_class: name)&.cron
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Marty
|
2
|
+
module BackgroundJob
|
3
|
+
class Schedule < Marty::Base
|
4
|
+
self.table_name = 'marty_background_job_schedules'
|
5
|
+
|
6
|
+
# Copied and adjusted:
|
7
|
+
# https://github.com/javan/whenever/blob/e4507e2ed2158c603f0c334a8b0a957711db343a/lib/whenever/cron.rb
|
8
|
+
REGEX = %r{\A(((\*?[\d/,\-]*)\s){3}(\*?([\d/,\-])*\s)(\*?([\d/,\-])*))\z}i
|
9
|
+
|
10
|
+
validates :job_class, :cron, :state, presence: true
|
11
|
+
validates :job_class, uniqueness: true
|
12
|
+
validates :cron, format: { with: REGEX }
|
13
|
+
|
14
|
+
validate :job_class_validation
|
15
|
+
|
16
|
+
ALL_STATES = %w[on off].freeze
|
17
|
+
enum state: ALL_STATES.zip(ALL_STATES).to_h
|
18
|
+
|
19
|
+
def job_class_validation
|
20
|
+
job_class.constantize.respond_to?(:schedule)
|
21
|
+
rescue NameError
|
22
|
+
errors.add(:job_class, "doesn't exist")
|
23
|
+
false
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Marty
|
2
|
+
module BackgroundJob
|
3
|
+
module UpdateSchedule
|
4
|
+
def self.call(id:, job_class:)
|
5
|
+
model = Marty::BackgroundJob::Schedule.find_by(id: id)
|
6
|
+
|
7
|
+
return remove_schedule(job_class: job_class) unless model.present?
|
8
|
+
return remove_schedule(job_class: job_class) if model.off?
|
9
|
+
return schedule(job_class: job_class) if model.on?
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.remove_schedule(job_class:)
|
13
|
+
klass = job_class.constantize
|
14
|
+
klass.remove_schedule if klass.respond_to?(:remove_schedule)
|
15
|
+
|
16
|
+
true
|
17
|
+
rescue NameError
|
18
|
+
false
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.schedule(job_class:)
|
22
|
+
klass = job_class.constantize
|
23
|
+
|
24
|
+
return false unless klass.respond_to?(:schedule)
|
25
|
+
|
26
|
+
klass.schedule
|
27
|
+
|
28
|
+
true
|
29
|
+
rescue NameError
|
30
|
+
false
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Marty
|
2
|
+
module Jobs
|
3
|
+
module Schedule
|
4
|
+
extend Delorean::Functions
|
5
|
+
|
6
|
+
delorean_fn :call, sig: 0 do
|
7
|
+
glob = Rails.root.join('app', 'jobs', '**', '*_job.rb')
|
8
|
+
Dir.glob(glob).each { |f| require f }
|
9
|
+
|
10
|
+
Marty::CronJob.subclasses.map do |klass|
|
11
|
+
klass.schedule
|
12
|
+
[klass.name, klass.cron_expression]
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class CreateMartyDelayedJobSchedules < ActiveRecord::Migration[5.1]
|
2
|
+
def change
|
3
|
+
create_table :marty_background_job_schedules do |t|
|
4
|
+
t.string :job_class, null: false
|
5
|
+
t.string :cron, null: false
|
6
|
+
t.string :state, null: false
|
7
|
+
|
8
|
+
t.timestamps
|
9
|
+
end
|
10
|
+
|
11
|
+
add_index :marty_background_job_schedules, :job_class, unique: true
|
12
|
+
end
|
13
|
+
end
|
data/lib/marty.rb
CHANGED
data/lib/marty/version.rb
CHANGED
data/make-dummy.mk
CHANGED
@@ -2,10 +2,12 @@ dummy-app-build:
|
|
2
2
|
docker-compose --file=docker-compose.dummy.yml build
|
3
3
|
|
4
4
|
dummy-app:
|
5
|
-
docker-compose --file=docker-compose.dummy.yml up
|
5
|
+
docker-compose --file=docker-compose.dummy.yml up -d app
|
6
|
+
docker attach marty_app_1
|
6
7
|
|
7
8
|
dummy-app-start:
|
8
|
-
docker-compose --file=docker-compose.dummy.yml up app
|
9
|
+
docker-compose --file=docker-compose.dummy.yml up -d app
|
10
|
+
docker attach marty_app_1
|
9
11
|
|
10
12
|
dummy-app-stop:
|
11
13
|
docker-compose --file=docker-compose.dummy.yml stop
|
data/marty.gemspec
CHANGED
@@ -33,7 +33,7 @@ Gem::Specification.new do |s|
|
|
33
33
|
|
34
34
|
s.add_dependency 'axlsx', '3.0.0pre'
|
35
35
|
|
36
|
-
s.add_dependency 'delorean_lang', '~> 0.6
|
36
|
+
s.add_dependency 'delorean_lang', '~> 0.6'
|
37
37
|
s.add_dependency 'mcfly', '~> 0.0.20'
|
38
38
|
|
39
39
|
s.add_dependency 'coderay'
|
@@ -46,5 +46,6 @@ Gem::Specification.new do |s|
|
|
46
46
|
s.add_dependency 'aws-sigv4', '~> 1.0', '>= 1.0.2'
|
47
47
|
|
48
48
|
s.add_dependency 'daemons', '~> 1.3.1'
|
49
|
+
s.add_dependency 'delayed_cron_job'
|
49
50
|
s.add_dependency 'delayed_job_active_record'
|
50
51
|
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
feature 'Background jobs schedule view', js: true do
|
4
|
+
before do
|
5
|
+
Delayed::Job.delete_all
|
6
|
+
populate_test_users
|
7
|
+
end
|
8
|
+
|
9
|
+
context 'as dev' do
|
10
|
+
before do
|
11
|
+
log_in_as('dev1')
|
12
|
+
wait_for_ajax
|
13
|
+
press('System')
|
14
|
+
press('Background Jobs')
|
15
|
+
press('Schedule Background Jobs')
|
16
|
+
wait_for_ajax
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'access denied' do
|
20
|
+
expect(page).to_not have_content 'Background Jobs Schedule'
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
context 'as admin' do
|
25
|
+
let(:schedule_view) { netzke_find('background_job_schedule_view') }
|
26
|
+
|
27
|
+
let!(:schedule) do
|
28
|
+
Marty::BackgroundJob::Schedule.create(
|
29
|
+
job_class: 'TestJob2',
|
30
|
+
cron: '0 0 * * *',
|
31
|
+
state: 'on'
|
32
|
+
).tap do |job|
|
33
|
+
Marty::BackgroundJob::UpdateSchedule.call(
|
34
|
+
id: job.id,
|
35
|
+
job_class: job.job_class
|
36
|
+
)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
before do
|
41
|
+
expect(TestJob2.scheduled?).to be true
|
42
|
+
|
43
|
+
log_in_as('admin1')
|
44
|
+
wait_for_ajax
|
45
|
+
press('System')
|
46
|
+
press('Background Jobs')
|
47
|
+
press('Schedule Background Jobs')
|
48
|
+
|
49
|
+
wait_for_ajax
|
50
|
+
|
51
|
+
expect(page).to have_content 'Background Jobs Schedule'
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'creates new schedule' do
|
55
|
+
expect(TestJob.scheduled?).to be false
|
56
|
+
|
57
|
+
press('Add')
|
58
|
+
|
59
|
+
fill_in('Job class', with: 'TestJob')
|
60
|
+
fill_in('cron', with: '1 1 * * *')
|
61
|
+
fill_in('state', with: 'on')
|
62
|
+
|
63
|
+
press 'OK'
|
64
|
+
wait_for_ajax
|
65
|
+
|
66
|
+
find('.x-tool-refresh').click
|
67
|
+
crons = schedule_view.get_col_vals('cron', 2, 0)
|
68
|
+
|
69
|
+
expect(crons).to include('1 1 * * *')
|
70
|
+
expect(crons).to include('0 0 * * *')
|
71
|
+
|
72
|
+
expect(TestJob.scheduled?).to be true
|
73
|
+
expect(TestJob.delayed_job.cron).to eq '1 1 * * *'
|
74
|
+
|
75
|
+
expect(TestJob2.scheduled?).to be true
|
76
|
+
expect(TestJob2.delayed_job.cron).to eq '0 0 * * *'
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'deletes schedule' do
|
80
|
+
find('.x-grid-item', text: 'TestJob2').click
|
81
|
+
press 'Delete'
|
82
|
+
press 'Yes'
|
83
|
+
|
84
|
+
wait_for_ajax
|
85
|
+
|
86
|
+
expect(TestJob2.scheduled?).to be false
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'turns the schedule off' do
|
90
|
+
find('.x-grid-item', text: 'TestJob2').click
|
91
|
+
press 'Edit'
|
92
|
+
fill_in('state', with: 'off')
|
93
|
+
|
94
|
+
press 'OK'
|
95
|
+
wait_for_ajax
|
96
|
+
expect(TestJob2.scheduled?).to be false
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'shows validation errors' do
|
100
|
+
press('Add')
|
101
|
+
|
102
|
+
fill_in('Job class', with: 'TestJob2')
|
103
|
+
fill_in('state', with: 'on')
|
104
|
+
fill_in('cron', with: '1')
|
105
|
+
|
106
|
+
press 'OK'
|
107
|
+
wait_for_ajax
|
108
|
+
expect(page).to have_content('Job class has already been taken')
|
109
|
+
expect(page).to have_content('Cron is invalid')
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'marty/background_job/schedule'
|
3
|
+
|
4
|
+
module Marty
|
5
|
+
module BackgroundJob
|
6
|
+
describe Schedule do
|
7
|
+
let(:subject) do
|
8
|
+
described_class.new(job_class: 'TestJob', cron: '* * * * *', state: 'on')
|
9
|
+
end
|
10
|
+
|
11
|
+
VALID_CRONS = [
|
12
|
+
'* * * * *',
|
13
|
+
'45 23 * * 6',
|
14
|
+
'0 7,17 * * *',
|
15
|
+
'0 17 * * 6',
|
16
|
+
'*/10 * * * *',
|
17
|
+
'30 10 * * *',
|
18
|
+
'0 * * * *',
|
19
|
+
'0 * * * *',
|
20
|
+
].freeze
|
21
|
+
|
22
|
+
INVALID_CRONS = [
|
23
|
+
'text 23 * * 6',
|
24
|
+
'1',
|
25
|
+
'* * *'
|
26
|
+
].freeze
|
27
|
+
|
28
|
+
it 'valid with valid cron expression' do
|
29
|
+
VALID_CRONS.each do |cron|
|
30
|
+
subject.cron = cron
|
31
|
+
expect(subject).to be_valid
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'invalid with valid cron expression' do
|
36
|
+
INVALID_CRONS.each do |cron|
|
37
|
+
subject.cron = cron
|
38
|
+
expect(subject).to_not be_valid
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -12,10 +12,20 @@ module Marty; module RSpec; module Chromedriver
|
|
12
12
|
pageLoadStrategy: 'none',
|
13
13
|
}
|
14
14
|
|
15
|
+
options = ::Selenium::WebDriver::Chrome::Options.new
|
16
|
+
|
17
|
+
# Add arguments to the driver using the Options interface
|
18
|
+
if opts[:args]
|
19
|
+
opts[:args].each do |arg|
|
20
|
+
options.add_argument("--#{arg}")
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
15
24
|
caps = Selenium::WebDriver::Remote::Capabilities.chrome(copts)
|
16
25
|
driver = Capybara::Selenium::Driver.new(app,
|
17
26
|
browser: :chrome,
|
18
|
-
desired_capabilities: caps
|
27
|
+
desired_capabilities: caps,
|
28
|
+
options: options)
|
19
29
|
yield driver if block_given?
|
20
30
|
driver
|
21
31
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: marty
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.8.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Arman Bostani
|
@@ -14,7 +14,7 @@ authors:
|
|
14
14
|
autorequire:
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
|
-
date: 2019-06-
|
17
|
+
date: 2019-06-12 00:00:00.000000000 Z
|
18
18
|
dependencies:
|
19
19
|
- !ruby/object:Gem::Dependency
|
20
20
|
name: pg
|
@@ -64,14 +64,14 @@ dependencies:
|
|
64
64
|
requirements:
|
65
65
|
- - "~>"
|
66
66
|
- !ruby/object:Gem::Version
|
67
|
-
version: 0.6
|
67
|
+
version: '0.6'
|
68
68
|
type: :runtime
|
69
69
|
prerelease: false
|
70
70
|
version_requirements: !ruby/object:Gem::Requirement
|
71
71
|
requirements:
|
72
72
|
- - "~>"
|
73
73
|
- !ruby/object:Gem::Version
|
74
|
-
version: 0.6
|
74
|
+
version: '0.6'
|
75
75
|
- !ruby/object:Gem::Dependency
|
76
76
|
name: mcfly
|
77
77
|
requirement: !ruby/object:Gem::Requirement
|
@@ -190,6 +190,20 @@ dependencies:
|
|
190
190
|
- - "~>"
|
191
191
|
- !ruby/object:Gem::Version
|
192
192
|
version: 1.3.1
|
193
|
+
- !ruby/object:Gem::Dependency
|
194
|
+
name: delayed_cron_job
|
195
|
+
requirement: !ruby/object:Gem::Requirement
|
196
|
+
requirements:
|
197
|
+
- - ">="
|
198
|
+
- !ruby/object:Gem::Version
|
199
|
+
version: '0'
|
200
|
+
type: :runtime
|
201
|
+
prerelease: false
|
202
|
+
version_requirements: !ruby/object:Gem::Requirement
|
203
|
+
requirements:
|
204
|
+
- - ">="
|
205
|
+
- !ruby/object:Gem::Version
|
206
|
+
version: '0'
|
193
207
|
- !ruby/object:Gem::Dependency
|
194
208
|
name: delayed_job_active_record
|
195
209
|
requirement: !ruby/object:Gem::Requirement
|
@@ -240,6 +254,7 @@ files:
|
|
240
254
|
- app/components/marty/api_log_view.rb
|
241
255
|
- app/components/marty/auth_app.rb
|
242
256
|
- app/components/marty/auth_app/client/auth_app.js
|
257
|
+
- app/components/marty/background_job_schedule_view.rb
|
243
258
|
- app/components/marty/base_rule_view.rb
|
244
259
|
- app/components/marty/config_view.rb
|
245
260
|
- app/components/marty/data_grid_view.rb
|
@@ -302,8 +317,11 @@ files:
|
|
302
317
|
- app/helpers/marty/application_helper.rb
|
303
318
|
- app/helpers/marty/enum_helper.rb
|
304
319
|
- app/helpers/marty/script_set.rb
|
320
|
+
- app/jobs/marty/cron_job.rb
|
305
321
|
- app/models/marty/api_auth.rb
|
306
322
|
- app/models/marty/api_config.rb
|
323
|
+
- app/models/marty/background_job.rb
|
324
|
+
- app/models/marty/background_job/schedule.rb
|
307
325
|
- app/models/marty/base.rb
|
308
326
|
- app/models/marty/base_rule.rb
|
309
327
|
- app/models/marty/config.rb
|
@@ -333,6 +351,8 @@ files:
|
|
333
351
|
- app/models/marty/user.rb
|
334
352
|
- app/models/marty/user_role.rb
|
335
353
|
- app/models/marty/vw_promise.rb
|
354
|
+
- app/services/marty/background_job/update_schedule.rb
|
355
|
+
- app/services/marty/jobs/schedule.rb
|
336
356
|
- app/services/marty/promises/delorean.rb
|
337
357
|
- app/services/marty/promises/delorean/create.rb
|
338
358
|
- app/services/marty/promises/ruby.rb
|
@@ -385,6 +405,8 @@ files:
|
|
385
405
|
- db/migrate/502_add_promise_type_enum.rb
|
386
406
|
- db/migrate/503_add_promise_type_to_promises.rb
|
387
407
|
- db/migrate/504_remove_plv8_extension.rb
|
408
|
+
- db/migrate/505_add_cron_to_delayed_jobs.rb
|
409
|
+
- db/migrate/506_create_marty_delayed_job_schedules.rb
|
388
410
|
- db/seeds.rb
|
389
411
|
- db/sql/lookup_grid_distinct_v1.sql
|
390
412
|
- db/sql/query_grid_dir_v1.sql
|
@@ -428,6 +450,7 @@ files:
|
|
428
450
|
- lib/pyxll/gemini.py
|
429
451
|
- lib/pyxll/pyxll.cfg
|
430
452
|
- lib/pyxll/sample.xlsx
|
453
|
+
- lib/tasks/marty_jobs.rake
|
431
454
|
- lib/tasks/marty_tasks.rake
|
432
455
|
- lib/tasks/scripts_tasks.rake
|
433
456
|
- make-dummy.mk
|
@@ -464,6 +487,8 @@ files:
|
|
464
487
|
- spec/dummy/app/controllers/application_controller.rb
|
465
488
|
- spec/dummy/app/controllers/components_controller.rb
|
466
489
|
- spec/dummy/app/helpers/application_helper.rb
|
490
|
+
- spec/dummy/app/jobs/test_job.rb
|
491
|
+
- spec/dummy/app/jobs/test_job2.rb
|
467
492
|
- spec/dummy/app/mailers/.gitkeep
|
468
493
|
- spec/dummy/app/models/.gitkeep
|
469
494
|
- spec/dummy/app/models/gemini/amortization_type.rb
|
@@ -1557,6 +1582,7 @@ files:
|
|
1557
1582
|
- spec/dummy/spec/features/javascripts
|
1558
1583
|
- spec/dummy/tmp/.gitkeep
|
1559
1584
|
- spec/features/auth_app_spec.rb
|
1585
|
+
- spec/features/background_job_schedule_spec.rb
|
1560
1586
|
- spec/features/data_import_spec.rb
|
1561
1587
|
- spec/features/endpoint_access.rb
|
1562
1588
|
- spec/features/enum_spec.rb
|
@@ -1592,6 +1618,7 @@ files:
|
|
1592
1618
|
- spec/lib/xl_spec.rb
|
1593
1619
|
- spec/lib/xl_styles_spec.rb
|
1594
1620
|
- spec/models/api_auth_spec.rb
|
1621
|
+
- spec/models/background_job/schedule.rb
|
1595
1622
|
- spec/models/config_spec.rb
|
1596
1623
|
- spec/models/data_grid_spec.rb
|
1597
1624
|
- spec/models/event_spec.rb
|