foreman-tasks 1.0.1 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +12 -12
  3. data/.rubocop_todo.yml +34 -116
  4. data/app/controllers/foreman_tasks/api/recurring_logics_controller.rb +20 -1
  5. data/app/controllers/foreman_tasks/api/tasks_controller.rb +29 -9
  6. data/app/controllers/foreman_tasks/concerns/hosts_controller_extension.rb +1 -1
  7. data/app/controllers/foreman_tasks/recurring_logics_controller.rb +19 -0
  8. data/app/helpers/foreman_tasks/foreman_tasks_helper.rb +1 -3
  9. data/app/lib/actions/helpers/humanizer.rb +1 -3
  10. data/app/lib/actions/proxy_action.rb +33 -12
  11. data/app/models/foreman_tasks/concerns/action_triggering.rb +1 -1
  12. data/app/models/foreman_tasks/recurring_logic.rb +1 -0
  13. data/app/models/foreman_tasks/remote_task.rb +1 -0
  14. data/app/models/foreman_tasks/task.rb +4 -0
  15. data/app/models/foreman_tasks/task/dynflow_task.rb +1 -1
  16. data/app/models/foreman_tasks/task/search.rb +11 -1
  17. data/app/services/foreman_tasks/troubleshooting_help_generator.rb +0 -4
  18. data/app/views/foreman_tasks/api/recurring_logics/base.json.rabl +2 -1
  19. data/app/views/foreman_tasks/api/tasks/details.json.rabl +1 -0
  20. data/app/views/foreman_tasks/api/tasks/show.json.rabl +1 -1
  21. data/app/views/foreman_tasks/recurring_logics/index.html.erb +30 -0
  22. data/app/views/foreman_tasks/tasks/show.html.erb +3 -0
  23. data/config/routes.rb +7 -0
  24. data/foreman-tasks.gemspec +4 -6
  25. data/lib/foreman_tasks/dynflow/console_authorizer.rb +2 -2
  26. data/lib/foreman_tasks/engine.rb +15 -13
  27. data/lib/foreman_tasks/tasks/cleanup.rake +1 -1
  28. data/lib/foreman_tasks/tasks/export_tasks.rake +2 -2
  29. data/lib/foreman_tasks/test_extensions.rb +1 -1
  30. data/lib/foreman_tasks/version.rb +1 -1
  31. data/locale/action_names.rb +1 -1
  32. data/package.json +1 -2
  33. data/script/rails +2 -2
  34. data/test/factories/task_factory.rb +34 -2
  35. data/test/foreman_tasks_test_helper.rb +4 -0
  36. data/test/unit/actions/action_with_sub_plans_test.rb +1 -1
  37. data/test/unit/task_test.rb +160 -74
  38. data/webpack/ForemanTasks/Components/TaskDetails/Components/Task.js +4 -0
  39. data/webpack/ForemanTasks/Components/TaskDetails/Components/TaskInfo.js +3 -12
  40. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/Task.test.js +1 -0
  41. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/Task.test.js.snap +3 -1
  42. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/TaskInfo.test.js.snap +2 -6
  43. data/webpack/ForemanTasks/Components/TaskDetails/TaskDetailsSelectors.js +4 -1
  44. data/webpack/ForemanTasks/Components/TaskDetails/__tests__/__snapshots__/TaskDetails.test.js.snap +1 -0
  45. data/webpack/ForemanTasks/Components/TaskDetails/index.js +2 -0
  46. data/webpack/ForemanTasks/Components/TasksTable/SubTasksPage.js +3 -1
  47. data/webpack/ForemanTasks/Components/TasksTable/TasksTableActions.js +87 -21
  48. data/webpack/ForemanTasks/Components/TasksTable/TasksTableConstants.js +7 -7
  49. data/webpack/ForemanTasks/Components/TasksTable/TasksTablePage.js +31 -22
  50. data/webpack/ForemanTasks/Components/TasksTable/__tests__/TasksTable.fixtures.js +2 -1
  51. data/webpack/ForemanTasks/Components/TasksTable/__tests__/TasksTableActions.test.js +44 -46
  52. data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/SubTasksPage.test.js.snap +3 -1
  53. data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/TasksIndexPage.test.js.snap +2 -1
  54. data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/TasksTableActions.test.js.snap +61 -5
  55. data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/TasksTablePage.test.js.snap +6 -2
  56. metadata +10 -10
@@ -158,7 +158,7 @@ module ForemanTasks
158
158
  end
159
159
  end
160
160
  end
161
- return true
161
+ true
162
162
  ensure
163
163
  # to not execute the same execution plan twice in a row
164
164
  @execution_plan = nil
@@ -14,6 +14,7 @@ module ForemanTasks
14
14
  scoped_search :on => :max_iteration, :complete_value => false, :rename => :iteration_limit
15
15
  scoped_search :on => :iteration, :complete_value => false
16
16
  scoped_search :on => :cron_line, :complete_value => true
17
+ scoped_search :on => :state, :complete_value => true
17
18
 
18
19
  before_create do
19
20
  task_group.save
@@ -9,6 +9,7 @@ module ForemanTasks
9
9
 
10
10
  scope :triggered, -> { where(:state => 'triggered') }
11
11
  scope :pending, -> { where(:state => 'new') }
12
+ scope :external, -> { where(:state => 'external') }
12
13
 
13
14
  delegate :proxy_action_name, :to => :action
14
15
 
@@ -42,6 +42,10 @@ module ForemanTasks
42
42
  scoped_search :on => :start_at, :complete_value => false
43
43
  scoped_search :on => :ended_at, :complete_value => false
44
44
  scoped_search :on => :parent_task_id, :complete_value => true
45
+ scoped_search :on => :duration, :complete_value => false, :ext_method => :search_by_duration, :operators => %w[> >= = <= <], :only_explicit => true
46
+
47
+ # Note: the following searches may return duplicates, this is due to
48
+ # one task maybe having multiple locks (e.g. read/write) for the same resource_id
45
49
  scoped_search :relation => :locks, :on => :resource_id, :complete_value => false, :rename => 'location_id', :ext_method => :search_by_taxonomy, :only_explicit => true
46
50
  scoped_search :relation => :locks, :on => :resource_id, :complete_value => false, :rename => 'organization_id', :ext_method => :search_by_taxonomy, :only_explicit => true
47
51
  scoped_search :relation => :locks, :on => :resource_type, :complete_value => true, :rename => 'resource_type', :ext_method => :search_by_generic_resource, :only_explicit => true
@@ -228,7 +228,7 @@ module ForemanTasks
228
228
  # if we fail updating the data from dynflow, it usually means there is something
229
229
  # odd with the data consistency and at this point it is not possible to resume, switching
230
230
  # the task to stopped/error
231
- task.update_attributes(:state => 'stopped', :result => 'error')
231
+ task.update(:state => 'stopped', :result => 'error')
232
232
  Foreman::Logging.exception("Failed at consistency check for task #{task.id}", e, :logger => 'foreman-tasks')
233
233
  end
234
234
  end
@@ -4,7 +4,8 @@ module ForemanTasks
4
4
  def search_by_generic_resource(key, operator, value)
5
5
  key = 'resource_type' if key.blank?
6
6
  key_name = connection.quote_column_name(key.sub(/^.*\./, ''))
7
- condition = sanitize_sql_for_conditions(["foreman_tasks_locks.#{key_name} #{operator} ?", value])
7
+ value = value.split(',') if operator.index(/IN/i)
8
+ condition = sanitize_sql_for_conditions(["foreman_tasks_locks.#{key_name} #{operator} (?)", value])
8
9
 
9
10
  { :conditions => condition, :joins => :locks }
10
11
  end
@@ -22,6 +23,15 @@ module ForemanTasks
22
23
  sql = "foreman_tasks_locks_taxonomy#{uniq_suffix}.resource_id #{operator} ? OR foreman_tasks_locks_taxonomy#{uniq_suffix}.resource_id IS NULL"
23
24
  { :conditions => sanitize_sql_for_conditions([sql, value]), :joins => joins }
24
25
  end
26
+
27
+ # Expects the time in the format "\d+ (seconds|minutes|hours|days|months|years)"
28
+ SUPPORTED_DURATION_FORMAT = /\A\s*(\d+(\s+\b(seconds?|minutes?|hours?|days?|months?|years?)\b)?)\b\s*\z/i.freeze
29
+ def search_by_duration(_key, operator, value)
30
+ raise "Unsupported duration '#{value}' specified for searching" unless value =~ SUPPORTED_DURATION_FORMAT
31
+ value = value.strip
32
+ { :conditions => "coalesce(ended_at, current_timestamp) - coalesce(coalesce(started_at, ended_at), current_timestamp) #{operator} ?::interval",
33
+ :parameter => [value] }
34
+ end
25
35
  end
26
36
  end
27
37
  end
@@ -44,10 +44,6 @@ module ForemanTasks
44
44
  # rubocop:enable Rails/OutputSafety
45
45
  end
46
46
 
47
- def generate_text
48
- (description + link_descriptions_html).join("\n")
49
- end
50
-
51
47
  def link_descriptions_html
52
48
  links.map do |link|
53
49
  link.description % { link: %(<a href="%{href}">%{title}</a>) % link.to_h }
@@ -1,3 +1,4 @@
1
1
  object @recurring_logic
2
2
 
3
- attributes :id, :cron_line, :end_time, :iteration, :task_group_id, :state
3
+ attributes :id, :cron_line, :end_time, :iteration, :task_group_id, :state,
4
+ :max_iteration
@@ -16,3 +16,4 @@ node(:locks) do
16
16
  end
17
17
  end
18
18
  node(:username_path) { username_link_task(@task.owner, @task.username) }
19
+ node(:dynflow_enable_console) { Setting['dynflow_enable_console'] }
@@ -2,5 +2,5 @@ object @task if @task
2
2
 
3
3
  attributes :id, :label, :pending, :action
4
4
  attributes :username, :started_at, :ended_at, :state, :result, :progress
5
- attributes :input, :output, :humanized, :cli_example
5
+ attributes :input, :output, :humanized, :cli_example, :start_at
6
6
  node(:available_actions) { |t| { cancellable: t.execution_plan&.cancellable?, resumable: t.resumable? } }
@@ -5,6 +5,36 @@
5
5
  <%= alert(:class => 'alert-info', :id => 'multiple-alert', :close => false, :header => '', :text => @errors) %>
6
6
  <% end %>
7
7
 
8
+ <% if authorized_for(:permission => :edit_recurring_logics, :auth_object => @recurring_logics) %>
9
+ <% title_actions link_to(_('Clear Cancelled'),
10
+ clear_cancelled_foreman_tasks_recurring_logics_path,
11
+ class: ['btn', 'btn-sm', 'btn-danger'],
12
+ :'data-toggle' => "modal",
13
+ :'data-target' => "#clear_modal")
14
+ %>
15
+
16
+ <div class="modal fade" id="clear_modal" tabindex="-1" role="dialog" aria-labelledby="Deploy" aria-hidden="true">
17
+ <div class="modal-dialog">
18
+ <div class="modal-content">
19
+ <div class="modal-header">
20
+ <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
21
+ <h2 class="modal-title" id="deploy_modal_label">
22
+ <span class="glyphicon glyphicon-warning-sign"></span>
23
+ <%= _("Clear Cancelled") %>
24
+ </h2>
25
+ </div>
26
+ <div class="modal-body">
27
+ <%= _("This action will delete all cancelled recurring logics. Please note that this action can't be reversed.") %>
28
+ </div>
29
+ <div class="modal-footer">
30
+ <button type="button" class="btn btn-default" data-dismiss="modal"><%= _("Cancel") %></button>
31
+ <%= link_to(_('Clear Cancelled'), clear_cancelled_foreman_tasks_recurring_logics_path, method: :post, class: 'btn btn-danger modal-submit') %>
32
+ </div>
33
+ </div>
34
+ </div>
35
+ </div>
36
+ <% end %>
37
+
8
38
  <table class="<%= table_css_classes('table-condensed table-fixed') %>">
9
39
  <thead>
10
40
  <th><%= N_("Cron line") %></th>
@@ -5,6 +5,9 @@
5
5
  <% content_for(:stylesheets) do %>
6
6
  <%= webpacked_plugins_css_for :'foreman-tasks' %>
7
7
  <% end %>
8
+
9
+ <% title _("Details of %s task") % @task.to_s %>
10
+
8
11
  <%= breadcrumbs(
9
12
  items: breadcrumb_items,
10
13
  name_field: 'action',
@@ -6,6 +6,9 @@ Foreman::Application.routes.draw do
6
6
  put :enable
7
7
  put :disable
8
8
  end
9
+ collection do
10
+ post :clear_cancelled
11
+ end
9
12
  end
10
13
 
11
14
  resources :tasks, :only => [:show] do
@@ -39,6 +42,9 @@ Foreman::Application.routes.draw do
39
42
  member do
40
43
  post :cancel
41
44
  end
45
+ collection do
46
+ post :bulk_destroy
47
+ end
42
48
  end
43
49
 
44
50
  resources :tasks, :only => [:show, :index] do
@@ -49,6 +55,7 @@ Foreman::Application.routes.draw do
49
55
  collection do
50
56
  post :bulk_search
51
57
  post :bulk_resume
58
+ post :bulk_cancel
52
59
  get :summary
53
60
  get '/summary/:id/sub_tasks/', action: 'summary_sub_tasks'
54
61
  post :callback
@@ -1,6 +1,4 @@
1
- # -*- coding: utf-8 -*-
2
-
3
- $LOAD_PATH.push File.expand_path("../lib", __FILE__)
1
+ $LOAD_PATH.push File.expand_path('lib', __dir__)
4
2
 
5
3
  # Maintain your gem's version:
6
4
  require "foreman_tasks/version"
@@ -29,11 +27,11 @@ same resource. It also optionally provides Dynflow infrastructure for using it f
29
27
  s.test_files = `git ls-files test`.split("\n")
30
28
  s.extra_rdoc_files = Dir['README*', 'LICENSE']
31
29
 
32
- s.add_dependency "foreman-tasks-core"
33
30
  s.add_dependency "dynflow", '>= 1.2.3'
34
- s.add_dependency "sinatra" # for Dynflow web console
35
- s.add_dependency "parse-cron", '~> 0.1.4'
31
+ s.add_dependency "foreman-tasks-core"
36
32
  s.add_dependency "get_process_mem" # for memory polling
33
+ s.add_dependency "parse-cron", '~> 0.1.4'
34
+ s.add_dependency "sinatra" # for Dynflow web console
37
35
 
38
36
  s.add_development_dependency 'factory_bot_rails', '~> 4.8.0'
39
37
  end
@@ -34,7 +34,7 @@ module ForemanTasks
34
34
  # console no matter what task it is...
35
35
  edit_permission = Permission.where(:name => :edit_foreman_tasks, :resource_type => ForemanTasks::Task.name).first
36
36
  if @user.filters.joins(:filterings).unlimited.where('filterings.permission_id' => edit_permission).first
37
- return true
37
+ true
38
38
  end
39
39
  end
40
40
 
@@ -43,7 +43,7 @@ module ForemanTasks
43
43
  begin
44
44
  original_user = User.current
45
45
  User.current = @user
46
- return Authorizer.new(@user).can?(:edit_foreman_tasks, task)
46
+ Authorizer.new(@user).can?(:edit_foreman_tasks, task)
47
47
  ensure
48
48
  User.current = original_user
49
49
  end
@@ -7,10 +7,10 @@ module ForemanTasks
7
7
  engine_name 'foreman_tasks'
8
8
 
9
9
  initializer 'foreman_tasks.load_default_settings', :before => :load_config_initializers do
10
- require_dependency File.expand_path('../../../app/models/setting/foreman_tasks.rb', __FILE__) if begin
10
+ require_dependency File.expand_path('../../app/models/setting/foreman_tasks.rb', __dir__) if begin
11
11
  Setting.table_exists?
12
- rescue
13
- false
12
+ rescue
13
+ false
14
14
  end
15
15
  end
16
16
 
@@ -26,7 +26,7 @@ module ForemanTasks
26
26
  end
27
27
 
28
28
  initializer 'foreman_tasks.register_gettext', :after => :load_config_initializers do
29
- locale_dir = File.join(File.expand_path('../../..', __FILE__), 'locale')
29
+ locale_dir = File.join(File.expand_path('../..', __dir__), 'locale')
30
30
  locale_domain = 'foreman_tasks'
31
31
 
32
32
  Foreman::Gettext::Support.add_text_domain locale_domain, locale_dir
@@ -53,15 +53,15 @@ module ForemanTasks
53
53
  :'foreman_tasks/react' => [:index],
54
54
  :'foreman_tasks/api/tasks' => [:bulk_search, :show, :index, :summary, :summary_sub_tasks, :details, :sub_tasks] }, :resource_type => ForemanTasks::Task.name
55
55
  permission :edit_foreman_tasks, { :'foreman_tasks/tasks' => [:resume, :unlock, :force_unlock, :cancel_step, :cancel, :abort],
56
- :'foreman_tasks/api/tasks' => [:bulk_resume] }, :resource_type => ForemanTasks::Task.name
56
+ :'foreman_tasks/api/tasks' => [:bulk_resume, :bulk_cancel] }, :resource_type => ForemanTasks::Task.name
57
57
 
58
58
  permission :create_recurring_logics, {}, :resource_type => ForemanTasks::RecurringLogic.name
59
59
 
60
60
  permission :view_recurring_logics, { :'foreman_tasks/recurring_logics' => [:index, :show],
61
61
  :'foreman_tasks/api/recurring_logics' => [:index, :show] }, :resource_type => ForemanTasks::RecurringLogic.name
62
62
 
63
- permission :edit_recurring_logics, { :'foreman_tasks/recurring_logics' => [:cancel, :enable, :disable],
64
- :'foreman_tasks/api/recurring_logics' => [:cancel, :update] }, :resource_type => ForemanTasks::RecurringLogic.name
63
+ permission :edit_recurring_logics, { :'foreman_tasks/recurring_logics' => [:cancel, :enable, :disable, :clear_cancelled],
64
+ :'foreman_tasks/api/recurring_logics' => [:cancel, :update, :bulk_destroy] }, :resource_type => ForemanTasks::RecurringLogic.name
65
65
  end
66
66
 
67
67
  add_all_permissions_to_default_roles
@@ -69,8 +69,10 @@ module ForemanTasks
69
69
  logger :dynflow, :enabled => true
70
70
  logger :action, :enabled => true
71
71
 
72
- role 'Tasks Manager', [:view_foreman_tasks, :edit_foreman_tasks]
73
- role 'Tasks Reader', [:view_foreman_tasks]
72
+ role 'Tasks Manager', [:view_foreman_tasks, :edit_foreman_tasks],
73
+ 'Role granting permissions to inspect, cancel, resume and unlock tasks'
74
+ role 'Tasks Reader', [:view_foreman_tasks],
75
+ 'Role granting permissions to inspect tasks'
74
76
 
75
77
  widget 'foreman_tasks/tasks/dashboard/tasks_status', :sizex => 6, :sizey => 1, :name => N_('Task Status')
76
78
  widget 'foreman_tasks/tasks/dashboard/latest_tasks_in_error_warning', :sizex => 6, :sizey => 1, :name => N_('Latest Warning/Error Tasks')
@@ -133,16 +135,16 @@ module ForemanTasks
133
135
  # to enable async Foreman operations using Dynflow
134
136
  if ENV['FOREMAN_TASKS_MONKEYS'] == 'true'
135
137
  config.to_prepare do
136
- ::Api::V2::HostsController.send :prepend, ForemanTasks::Concerns::HostsControllerExtension
137
- ::Host::Base.send :include, ForemanTasks::Concerns::HostActionSubject
138
+ ::Api::V2::HostsController.prepend ForemanTasks::Concerns::HostsControllerExtension
139
+ ::Host::Base.include ForemanTasks::Concerns::HostActionSubject
138
140
  end
139
141
  end
140
142
 
141
143
  config.to_prepare do
142
144
  ForemanTasks.dynflow.eager_load_actions! if ForemanTasks.dynflow.initialized?
143
145
 
144
- Authorizer.send(:prepend, AuthorizerExt)
145
- User.send(:include, ForemanTasks::Concerns::UserExtensions)
146
+ Authorizer.prepend AuthorizerExt
147
+ User.include ForemanTasks::Concerns::UserExtensions
146
148
  end
147
149
 
148
150
  rake_tasks do
@@ -1,6 +1,6 @@
1
1
  namespace :foreman_tasks do
2
2
  namespace :cleanup do
3
- desc <<-DESC.strip_heredoc
3
+ desc <<~DESC
4
4
  Clean tasks based on filter and age. ENV variables:
5
5
 
6
6
  * TASK_SEARCH : scoped search filter (example: 'label = "Actions::Foreman::Host::ImportFacts"')
@@ -7,7 +7,7 @@
7
7
  require 'csv'
8
8
 
9
9
  namespace :foreman_tasks do
10
- desc <<-DESC.strip_heredoc
10
+ desc <<~DESC
11
11
  Export dynflow tasks based on filter. ENV variables:
12
12
 
13
13
  * TASK_SEARCH : scoped search filter (example: 'label = "Actions::Foreman::Host::ImportFacts"')
@@ -259,7 +259,7 @@ namespace :foreman_tasks do
259
259
 
260
260
  File.open(File.join(tmp_dir, 'index.html'), 'w') { |file| file.write(PageHelper.pagify(PageHelper.generate_index(tasks))) }
261
261
 
262
- sh("tar cvzf #{export_filename} #{tmp_dir} > /dev/null")
262
+ system("tar", "czf", export_filename, tmp_dir)
263
263
  end
264
264
  elsif format == 'csv'
265
265
  CSV.open(export_filename, 'wb') do |csv|
@@ -14,4 +14,4 @@ module ForemanTasks
14
14
  end
15
15
  end
16
16
 
17
- ActiveSupport::TestCase.send(:include, ForemanTasks::TestExtensions::AccessPermissionsTestExtension)
17
+ ActiveSupport::TestCase.include ForemanTasks::TestExtensions::AccessPermissionsTestExtension
@@ -1,3 +1,3 @@
1
1
  module ForemanTasks
2
- VERSION = '1.0.1'.freeze
2
+ VERSION = '1.1.0'.freeze
3
3
  end
@@ -2,4 +2,4 @@
2
2
  _("Remote action:")
3
3
  _("Import Puppet classes")
4
4
  _("Import facts")
5
- _("Action with sub plans")
5
+ _("Action with sub plans")
@@ -27,6 +27,7 @@
27
27
  "dependencies": {
28
28
  "c3": "^0.4.11",
29
29
  "humanize-duration": "^3.20.1",
30
+ "react-html-parser": "^2.0.2",
30
31
  "react-intl": "^2.8.0"
31
32
  },
32
33
  "devDependencies": {
@@ -38,10 +39,8 @@
38
39
  "@theforeman/vendor-dev": "^4.0.2",
39
40
  "babel-eslint": "^10.0.3",
40
41
  "eslint": "^6.7.2",
41
- "identity-obj-proxy": "^3.0.0",
42
42
  "jed": "^1.1.1",
43
43
  "prettier": "^1.13.5",
44
- "react-remarkable": "^1.1.3",
45
44
  "stylelint": "^9.3.0",
46
45
  "stylelint-config-standard": "^18.0.0",
47
46
  "surge": "^0.20.3"
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env ruby
2
2
  # This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.
3
3
 
4
- ENGINE_ROOT = File.expand_path('../..', __FILE__)
5
- ENGINE_PATH = File.expand_path('../../lib/foreman_tasks/engine', __FILE__)
4
+ ENGINE_ROOT = File.expand_path('..', __dir__)
5
+ ENGINE_PATH = File.expand_path('../lib/foreman_tasks/engine', __dir__)
6
6
 
7
7
  require 'rails/all'
8
8
  require 'rails/engine/commands'
@@ -22,7 +22,7 @@ FactoryBot.define do
22
22
  execution_plan = ForemanTasks.dynflow.world.plan(Support::DummyDynflowAction)
23
23
  # remove the task created automatically by the persistence
24
24
  ForemanTasks::Task.where(:external_id => execution_plan.id).delete_all
25
- task.update_attributes!(:external_id => execution_plan.id)
25
+ task.update!(:external_id => execution_plan.id)
26
26
  if evaluator.sync_with_dynflow
27
27
  task.update_from_dynflow(execution_plan.to_hash)
28
28
  end
@@ -38,9 +38,41 @@ FactoryBot.define do
38
38
 
39
39
  trait :inconsistent_dynflow_task do
40
40
  after(:build) do |task|
41
- task.update_attributes!(:state => 'running')
41
+ task.update!(:state => 'running')
42
+ end
43
+ end
44
+
45
+ factory :task_with_locks do
46
+ # posts_count is declared as a transient attribute and available in
47
+ # attributes on the factory, as well as the callback via the evaluator
48
+ transient do
49
+ locks_count { 3 }
50
+ resource_id { 1 }
51
+ resource_type { 'type1' }
52
+ end
53
+
54
+ # the after(:create) yields two values; the user instance itself and the
55
+ # evaluator, which stores all values from the factory, including transient
56
+ # attributes; `create_list`'s second argument is the number of records
57
+ # to create and we make sure the user is associated properly to the post
58
+ after(:create) do |task, evaluator|
59
+ create_list(
60
+ :lock,
61
+ evaluator.locks_count,
62
+ task: task,
63
+ resource_type: evaluator.resource_type,
64
+ resource_id: evaluator.resource_id
65
+ )
42
66
  end
43
67
  end
44
68
  end
45
69
  end
70
+
71
+ factory :lock, :class => ForemanTasks::Lock do
72
+ name { 'read' }
73
+ resource_type { 'Katello::Repository' }
74
+ resource_id { 1 }
75
+ exclusive { true }
76
+ association :task, factory: :task_with_locks
77
+ end
46
78
  end
@@ -27,3 +27,7 @@ def wait_for(waiting_message = 'something to happen')
27
27
  end
28
28
  raise "waiting for #{waiting_message} was not successful"
29
29
  end
30
+
31
+ def on_postgresql?
32
+ ActiveRecord::Base.connection.adapter_name == 'PostgreSQL'
33
+ end
@@ -8,7 +8,7 @@ module ForemanTasks
8
8
  end
9
9
 
10
10
  # to be able to use the locking
11
- ::User.send(:include, ForemanTasks::Concerns::ActionSubject)
11
+ ::User.include ForemanTasks::Concerns::ActionSubject
12
12
 
13
13
  class ParentAction < Actions::ActionWithSubPlans
14
14
  def plan(user)