foreman_dlm 1.0.0 → 1.1.0

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.
Files changed (64) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +9 -1
  3. data/app/controllers/api/v2/dlmlock_events_controller.rb +41 -0
  4. data/app/controllers/api/v2/dlmlocks_controller.rb +10 -4
  5. data/app/controllers/concerns/foreman_dlm/update_checkin_time.rb +21 -0
  6. data/app/controllers/foreman_dlm/application_controller.rb +19 -0
  7. data/app/controllers/foreman_dlm/dlmlocks_controller.rb +73 -0
  8. data/app/helpers/foreman_dlm/dlmlock_helper.rb +31 -0
  9. data/app/jobs/foreman_dlm/refresh_dlmlock_status.rb +17 -0
  10. data/app/models/concerns/foreman_dlm/dlm_facet_host_extensions.rb +13 -0
  11. data/app/models/concerns/foreman_dlm/expirable.rb +35 -0
  12. data/app/models/concerns/foreman_dlm/host_extensions.rb +11 -0
  13. data/app/models/concerns/foreman_dlm/user_extensions.rb +13 -0
  14. data/app/models/foreman_dlm/dlm_facet.rb +7 -0
  15. data/app/models/foreman_dlm/dlmlock.rb +136 -0
  16. data/app/models/foreman_dlm/dlmlock/update.rb +9 -0
  17. data/app/models/foreman_dlm/dlmlock_event.rb +23 -0
  18. data/app/models/host_status/dlmlock_status.rb +44 -0
  19. data/app/models/settings/dlm.rb +20 -0
  20. data/app/views/api/v2/dlmlock_events/index.json.rabl +2 -0
  21. data/app/views/foreman_dlm/api/v2/dlm_facets/base.json.rabl +1 -0
  22. data/app/views/foreman_dlm/api/v2/dlm_facets/base_with_root.json.rabl +3 -0
  23. data/app/views/foreman_dlm/api/v2/dlm_facets/show.json.rabl +3 -0
  24. data/app/views/foreman_dlm/dlmlocks/_details.html.erb +42 -0
  25. data/app/views/{dlmlocks → foreman_dlm/dlmlocks}/_list.html.erb +3 -1
  26. data/app/views/{dlmlocks → foreman_dlm/dlmlocks}/index.html.erb +0 -0
  27. data/app/views/foreman_dlm/dlmlocks/show.html.erb +10 -0
  28. data/app/views/{dlmlocks → foreman_dlm/dlmlocks}/welcome.html.erb +0 -0
  29. data/app/views/hosts/_dlmlocks_tab.html.erb +39 -0
  30. data/config/routes.rb +10 -3
  31. data/contrib/systemd/foreman-dlm-expire-events.service +10 -0
  32. data/contrib/systemd/foreman-dlm-expire-events.timer +8 -0
  33. data/db/migrate/20180627150003_rename_dlmlock_sti_models.rb +9 -0
  34. data/db/migrate/20180704162345_add_dlmlock_events.rb +11 -0
  35. data/db/migrate/20180711090022_add_hosts_fk_to_dlmlocks.rb +5 -0
  36. data/db/migrate/20180711111903_create_dlm_facets.foreman_dlm.rb +10 -0
  37. data/db/migrate/20180713113208_update_permissions_for_scoped_models.rb +13 -0
  38. data/lib/foreman_dlm/engine.rb +43 -7
  39. data/lib/foreman_dlm/version.rb +1 -1
  40. data/lib/tasks/dlmlock_events.rake +19 -0
  41. data/test/controllers/api/v2/dlmlocks_controller_test.rb +32 -11
  42. data/test/controllers/api/v2/dlmlocks_dlmlock_events_controller_test.rb +81 -0
  43. data/test/controllers/api/v2/hosts_controller_test.rb +28 -0
  44. data/test/controllers/foreman_dlm/dlmlocks_test.rb +55 -0
  45. data/test/controllers/hosts_controller_test.rb +12 -0
  46. data/test/factories/dlm_facets.rb +6 -0
  47. data/test/factories/dlmlock.rb +6 -2
  48. data/test/factories/dlmlock_events.rb +13 -0
  49. data/test/factories/host.rb +7 -0
  50. data/test/jobs/refresh_dlmlock_status_test.rb +10 -0
  51. data/test/models/foreman_dlm/dlm_facet_test.rb +13 -0
  52. data/test/models/foreman_dlm/dlmlock_event_test.rb +19 -0
  53. data/test/models/foreman_dlm/dlmlock_test.rb +299 -0
  54. data/test/models/host_managed_test.rb +23 -0
  55. data/test/models/host_status/dlmlock_status_test.rb +49 -0
  56. data/test/models/user_test.rb +5 -0
  57. metadata +63 -15
  58. data/app/controllers/dlmlocks_controller.rb +0 -12
  59. data/app/models/dlmlock.rb +0 -79
  60. data/app/models/dlmlock/update.rb +0 -7
  61. data/app/views/dlmlocks/_details.html.erb +0 -35
  62. data/app/views/dlmlocks/show.html.erb +0 -7
  63. data/test/controllers/dlmlocks_test.rb +0 -24
  64. data/test/models/dlmlock_test.rb +0 -201
@@ -24,12 +24,12 @@ class Api::V2::DlmlocksControllerTest < ActionController::TestCase
24
24
 
25
25
  context '#create' do
26
26
  test 'should create dlmlock' do
27
- assert_difference('Dlmlock.unscoped.count') do
27
+ assert_difference('ForemanDlm::Dlmlock.unscoped.count') do
28
28
  post :create, params: valid_attrs_with_root
29
29
  end
30
30
  assert_response :success
31
31
  body = ActiveSupport::JSON.decode(@response.body)
32
- dlmlock = Dlmlock.find(body['id'])
32
+ dlmlock = ForemanDlm::Dlmlock.find(body['id'])
33
33
  assert dlmlock
34
34
  assert_equal valid_attrs['name'], dlmlock.name
35
35
  assert_equal valid_attrs['type'], dlmlock.type
@@ -99,11 +99,11 @@ class Api::V2::DlmlocksControllerTest < ActionController::TestCase
99
99
  context '#destroy' do
100
100
  test 'should destroy dlmlock' do
101
101
  dlmlock = FactoryBot.create(:dlmlock)
102
- assert_difference('Dlmlock.unscoped.count', -1) do
102
+ assert_difference('ForemanDlm::Dlmlock.unscoped.count', -1) do
103
103
  delete :destroy, params: { :id => dlmlock.to_param }
104
104
  end
105
105
  assert_response :success
106
- assert_equal 0, Dlmlock.where(:id => dlmlock.id).count
106
+ assert_equal 0, ForemanDlm::Dlmlock.where(:id => dlmlock.id).count
107
107
  end
108
108
  end
109
109
 
@@ -168,7 +168,7 @@ class Api::V2::DlmlocksControllerTest < ActionController::TestCase
168
168
  dlmlock = as_admin { FactoryBot.create(:dlmlock) }
169
169
  delete :destroy, params: { :id => dlmlock.to_param }
170
170
  assert_response :unauthorized
171
- assert_equal 1, as_admin { Dlmlock.where(:id => dlmlock.id).count }
171
+ assert_equal 1, as_admin { ForemanDlm::Dlmlock.where(:id => dlmlock.id).count }
172
172
  end
173
173
  end
174
174
 
@@ -217,6 +217,13 @@ class Api::V2::DlmlocksControllerTest < ActionController::TestCase
217
217
  assert_equal host2.name, host['name']
218
218
  assert_equal false, host['self']
219
219
  end
220
+
221
+ test 'should update checkin time' do
222
+ dlmlock = as_admin { FactoryBot.create(:dlmlock) }
223
+ refute as_admin { host1.dlm_facet }
224
+ put :show, params: { :id => dlmlock.to_param }
225
+ assert as_admin { host1.reload.dlm_facet.last_checkin_at }
226
+ end
220
227
  end
221
228
 
222
229
  context '#acquire' do
@@ -243,13 +250,20 @@ class Api::V2::DlmlocksControllerTest < ActionController::TestCase
243
250
 
244
251
  test 'should transparently create non-existing dlmlock' do
245
252
  lockname = 'Test Lock'
246
- assert_equal 0, as_admin { Dlmlock.where(:name => lockname).count }
253
+ assert_equal 0, as_admin { ForemanDlm::Dlmlock.where(:name => lockname).count }
247
254
  put :acquire, params: { :id => lockname }
248
255
  assert_response :success
249
- dlmlock = as_admin { Dlmlock.find_by(:name => lockname) }
256
+ dlmlock = as_admin { ForemanDlm::Dlmlock.find_by(:name => lockname) }
250
257
  assert_equal lockname, dlmlock.name
251
258
  assert_equal host1, dlmlock.host
252
259
  end
260
+
261
+ test 'should update checkin time' do
262
+ dlmlock = as_admin { FactoryBot.create(:dlmlock) }
263
+ refute as_admin { host1.dlm_facet }
264
+ put :acquire, params: { :id => dlmlock.to_param }
265
+ assert as_admin { host1.reload.dlm_facet.last_checkin_at }
266
+ end
253
267
  end
254
268
 
255
269
  context '#release' do
@@ -276,13 +290,20 @@ class Api::V2::DlmlocksControllerTest < ActionController::TestCase
276
290
 
277
291
  test 'should transparently create non-existing dlmlock' do
278
292
  lockname = 'Test Lock'
279
- assert_equal 0, as_admin { Dlmlock.where(:name => lockname).count }
293
+ assert_equal 0, as_admin { ForemanDlm::Dlmlock.where(:name => lockname).count }
280
294
  delete :release, params: { :id => lockname }
281
295
  assert_response :success
282
- dlmlock = as_admin { Dlmlock.find_by(:name => lockname) }
296
+ dlmlock = as_admin { ForemanDlm::Dlmlock.find_by(:name => lockname) }
283
297
  assert_equal lockname, dlmlock.name
284
298
  assert_nil dlmlock.host
285
299
  end
300
+
301
+ test 'should update checkin time' do
302
+ dlmlock = as_admin { FactoryBot.create(:dlmlock) }
303
+ refute as_admin { host1.dlm_facet }
304
+ put :release, params: { :id => dlmlock.to_param }
305
+ assert as_admin { host1.reload.dlm_facet.last_checkin_at }
306
+ end
286
307
  end
287
308
  end
288
309
 
@@ -329,7 +350,7 @@ class Api::V2::DlmlocksControllerTest < ActionController::TestCase
329
350
  dlmlock = as_admin { FactoryBot.create(:dlmlock) }
330
351
  delete :destroy, params: { :id => dlmlock.to_param }
331
352
  assert_response :unauthorized
332
- assert_equal 1, as_admin { Dlmlock.where(:id => dlmlock.id).count }
353
+ assert_equal 1, as_admin { ForemanDlm::Dlmlock.where(:id => dlmlock.id).count }
333
354
  end
334
355
  end
335
356
 
@@ -357,7 +378,7 @@ class Api::V2::DlmlocksControllerTest < ActionController::TestCase
357
378
  def valid_attrs
358
379
  {
359
380
  'name' => 'testlock',
360
- 'type' => 'Dlmlock::Update'
381
+ 'type' => 'ForemanDlm::Dlmlock::Update'
361
382
  }
362
383
  end
363
384
 
@@ -0,0 +1,81 @@
1
+ require 'test_plugin_helper'
2
+
3
+ class Api::V2::DlmlockEventsControllerTest < ActionController::TestCase
4
+ let(:host) { as_admin { FactoryBot.create(:host, :managed) } }
5
+
6
+ context 'with user authentication' do
7
+ context '#index' do
8
+ test 'should return the dlmlock_events for a given dlm_lock' do
9
+ # A random dlmlock with events, that should not be in the response.
10
+ dlmlock1 = FactoryBot.create(:dlmlock, host: host)
11
+ FactoryBot.create_list(:dlmlock_event, 2, dlmlock: dlmlock1)
12
+
13
+ dlmlock = FactoryBot.create(:dlmlock, host: host)
14
+ FactoryBot.create_list(:dlmlock_event, 3, dlmlock: dlmlock)
15
+
16
+ expected_size = dlmlock.dlmlock_events.count
17
+ expected_ids = dlmlock.dlmlock_events.pluck(:id).sort
18
+ expected_keys = ['id', 'event_type', 'created_at', 'updated_at']
19
+
20
+ get :index, params: { dlmlock_id: dlmlock.id }
21
+ assert_response :success
22
+
23
+ body = ActiveSupport::JSON.decode(@response.body)
24
+ assert_equal expected_size, body['total']
25
+ assert_equal expected_keys, body['results'].first.keys
26
+ assert_equal expected_ids, body['results'].map { |event| event['id'] }.sort
27
+ end
28
+ end
29
+ end
30
+
31
+ context 'as user with required permissions' do
32
+ let(:permissions) { Permission.where(name: ['view_dlmlocks', 'view_dlmlock_events']) }
33
+ let(:role) { FactoryBot.create(:role, permissions: permissions) }
34
+ let(:user) { FactoryBot.create(:user, roles: [role]) }
35
+
36
+ setup do
37
+ User.current = user
38
+ reset_api_credentials
39
+ end
40
+
41
+ context '#index' do
42
+ test 'should allow access' do
43
+ dlmlock = as_admin { FactoryBot.create(:dlmlock) }
44
+ get :index, params: { dlmlock_id: dlmlock.id }
45
+ assert_response :success
46
+ end
47
+ end
48
+ end
49
+
50
+ context 'as user without required permissions' do
51
+ let(:user) { FactoryBot.create(:user, roles: []) }
52
+
53
+ setup do
54
+ User.current = user
55
+ reset_api_credentials
56
+ end
57
+
58
+ context '#index' do
59
+ test 'should deny access' do
60
+ dlmlock = as_admin { FactoryBot.create(:dlmlock) }
61
+ get :index, params: { dlmlock_id: dlmlock.id }
62
+ assert_response :forbidden
63
+ end
64
+ end
65
+ end
66
+
67
+ context 'without any credentials' do
68
+ setup do
69
+ User.current = nil
70
+ reset_api_credentials
71
+ end
72
+
73
+ context '#index' do
74
+ test 'should deny access' do
75
+ dlmlock = as_admin { FactoryBot.create(:dlmlock) }
76
+ get :index, params: { dlmlock_id: dlmlock.id }
77
+ assert_response :unauthorized
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,28 @@
1
+ require 'test_plugin_helper'
2
+
3
+ class Api::V2::HostsControllerTest < ActionController::TestCase
4
+ let(:host) { FactoryBot.create(:host, :managed, :with_dlm_facet) }
5
+
6
+ test 'should get index with dlm_facet attributes' do
7
+ host
8
+ get :index
9
+ assert_response :success
10
+ results = ActiveSupport::JSON.decode(@response.body)
11
+ hosts = results['results']
12
+ assert_not_empty hosts
13
+ host_with_facet = hosts.detect { |h| h['dlm_facet_attributes'].present? }
14
+ assert_not_nil host_with_facet
15
+ assert_equal host.dlm_facet.id, host_with_facet['dlm_facet_attributes']['id']
16
+ assert_equal host.dlm_facet.last_checkin_at.to_s, host_with_facet['dlm_facet_attributes']['last_checkin_at']
17
+ end
18
+
19
+ test 'should show individual record with dlm_facet attributes' do
20
+ get :show, params: { :id => host.to_param }
21
+ assert_response :success
22
+ show_response = ActiveSupport::JSON.decode(@response.body)
23
+ assert_not_empty show_response
24
+ assert_includes show_response.keys, 'dlm_facet_attributes'
25
+ assert_equal host.dlm_facet.id, show_response['dlm_facet_attributes']['id']
26
+ assert_equal host.dlm_facet.last_checkin_at.to_s, show_response['dlm_facet_attributes']['last_checkin_at']
27
+ end
28
+ end
@@ -0,0 +1,55 @@
1
+ require 'test_plugin_helper'
2
+
3
+ module ForemanDlm
4
+ class DlmlocksControllerTest < ActionController::TestCase
5
+ test '#index' do
6
+ FactoryBot.create(:dlmlock)
7
+ get :index, session: set_session_user
8
+ assert_response :success
9
+ assert_not_nil assigns('dlmlocks')
10
+ assert_template 'index'
11
+ end
12
+
13
+ test '#index with no lock shows welcome page' do
14
+ get :index, session: set_session_user
15
+ assert_response :success
16
+ assert_template 'welcome'
17
+ end
18
+
19
+ test '#show' do
20
+ dlmlock = FactoryBot.create(:dlmlock)
21
+ get :show, params: { :id => dlmlock.id }, session: set_session_user
22
+ assert_response :success
23
+ assert_template 'show'
24
+ end
25
+
26
+ test '#destroy' do
27
+ dlmlock = FactoryBot.create(:dlmlock)
28
+ delete :destroy, params: { :id => dlmlock.id }, session: set_session_user
29
+ assert_redirected_to foreman_dlm_dlmlocks_url
30
+ refute Dlmlock.exists?(dlmlock.id)
31
+ end
32
+
33
+ test '#enable' do
34
+ dlmlock = FactoryBot.create(:dlmlock, enabled: false)
35
+ put :enable, params: { :id => dlmlock.id }, session: set_session_user
36
+ assert_redirected_to foreman_dlm_dlmlocks_url
37
+ assert dlmlock.reload.enabled?
38
+ end
39
+
40
+ test '#disable' do
41
+ dlmlock = FactoryBot.create(:dlmlock, enabled: true)
42
+ put :disable, params: { :id => dlmlock.id }, session: set_session_user
43
+ assert_redirected_to foreman_dlm_dlmlocks_url
44
+ assert dlmlock.reload.disabled?
45
+ end
46
+
47
+ test '#release' do
48
+ host = FactoryBot.create(:host)
49
+ dlmlock = FactoryBot.create(:dlmlock, host: host)
50
+ put :release, params: { :id => dlmlock.id }, session: set_session_user
51
+ assert_redirected_to foreman_dlm_dlmlocks_url
52
+ refute dlmlock.reload.taken?
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,12 @@
1
+ require 'test_plugin_helper'
2
+
3
+ class HostsControllerTest < ActionController::TestCase
4
+ let(:host) { FactoryBot.create(:host, :with_dlm_facet) }
5
+
6
+ test '#show shows dlm locks of that host' do
7
+ FactoryBot.create_list(:dlmlock, 2, host: host)
8
+ get :show, params: { :id => host.to_param }, session: set_session_user
9
+ assert_response :success
10
+ assert @response.body.match(/id='pagelet-id-locks'/)
11
+ end
12
+ end
@@ -0,0 +1,6 @@
1
+ FactoryBot.define do
2
+ factory :dlm_facet, class: 'ForemanDlm::DlmFacet' do
3
+ sequence(:last_checkin_at) { |n| n.minutes.ago }
4
+ host
5
+ end
6
+ end
@@ -1,6 +1,10 @@
1
1
  FactoryBot.define do
2
- factory :dlmlock do
2
+ factory :dlmlock, class: ::ForemanDlm::Dlmlock::Update do
3
3
  sequence(:name) { |n| "Lock #{n}" }
4
- type 'Dlmlock::Update'
4
+ type 'ForemanDlm::Dlmlock::Update'
5
+
6
+ trait :locked do
7
+ host
8
+ end
5
9
  end
6
10
  end
@@ -0,0 +1,13 @@
1
+ FactoryBot.define do
2
+ factory :dlmlock_event, class: ::ForemanDlm::DlmlockEvent do
3
+ dlmlock
4
+ event_type 'release'
5
+ host
6
+
7
+ trait :old_event do
8
+ after(:build) do |event|
9
+ event.created_at = 2.weeks.ago
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,7 @@
1
+ FactoryBot.modify do
2
+ factory :host do
3
+ trait :with_dlm_facet do
4
+ association :dlm_facet, :factory => :dlm_facet, :strategy => :build
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,10 @@
1
+ require 'test_plugin_helper'
2
+
3
+ class RefreshDlmlockStatusTest < ActiveJob::TestCase
4
+ let(:host) { FactoryBot.create(:host, :managed) }
5
+
6
+ test 'should refresh dlmlock status' do
7
+ Host::Managed.any_instance.expects(:refresh_dlmlock_status).once
8
+ perform_enqueued_jobs { ForemanDlm::RefreshDlmlockStatus.perform_later(host.id) }
9
+ end
10
+ end
@@ -0,0 +1,13 @@
1
+ require 'test_plugin_helper'
2
+
3
+ module ForemanDlm
4
+ class DlmFacetTest < ActiveSupport::TestCase
5
+ setup do
6
+ User.current = users(:admin)
7
+ end
8
+
9
+ subject { FactoryBot.create(:dlm_facet) }
10
+ should belong_to(:host)
11
+ should validate_presence_of(:host)
12
+ end
13
+ end
@@ -0,0 +1,19 @@
1
+ require 'test_plugin_helper'
2
+
3
+ module ForemanDlm
4
+ class DlmlockEventTest < ActiveSupport::TestCase
5
+ should belong_to(:dlmlock)
6
+ should belong_to(:host)
7
+ should belong_to(:user)
8
+
9
+ test 'should expire lock events' do
10
+ event_count = 5
11
+ FactoryBot.create_list(:dlmlock_event, event_count)
12
+ FactoryBot.create_list(:dlmlock_event, event_count, :old_event)
13
+ assert_difference(-> { ForemanDlm::DlmlockEvent.count }, -1 * event_count) do
14
+ ForemanDlm::DlmlockEvent.expire(created_before: 7.days, batch_size: 2, sleep_time: 0.0001)
15
+ end
16
+ assert_equal event_count, ForemanDlm::DlmlockEvent.count
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,299 @@
1
+ require 'test_plugin_helper'
2
+
3
+ module ForemanDlm
4
+ class DlmlockTest < ActiveSupport::TestCase
5
+ setup do
6
+ User.current = users(:admin)
7
+ end
8
+
9
+ should belong_to(:host)
10
+ should have_many(:dlmlock_events)
11
+
12
+ subject { FactoryBot.create(:dlmlock) }
13
+ should validate_presence_of(:name)
14
+ should validate_uniqueness_of(:name)
15
+
16
+ let(:host1) { FactoryBot.create(:host, :managed) }
17
+ let(:host2) { FactoryBot.create(:host, :managed) }
18
+
19
+ class HostWithCallbacks < ::Host::Managed
20
+ attr_accessor :callbacks
21
+
22
+ def initialize(*attributes, &block)
23
+ super
24
+ @callbacks = []
25
+ end
26
+
27
+ after_lock :callback1
28
+ after_unlock :callback2
29
+
30
+ def callback1
31
+ Rails.logger.debug "callback1 executed for #{self} (#{self.class})"
32
+ callbacks << 'callback1'
33
+ end
34
+
35
+ def callback2
36
+ Rails.logger.debug "callback2 executed for #{self} (#{self.class})"
37
+ callbacks << 'callback2'
38
+ end
39
+ end
40
+
41
+ let(:host1_with_callbacks) { HostWithCallbacks.create(:name => 'test1.example.com') }
42
+ let(:host2_with_callbacks) { HostWithCallbacks.create(:name => 'test2.example.com') }
43
+
44
+ context 'a free and enabled DLM lock' do
45
+ let(:dlmlock) { FactoryBot.create(:dlmlock) }
46
+
47
+ test 'should be enabled and unlocked' do
48
+ assert_equal true, dlmlock.enabled?
49
+ assert_equal false, dlmlock.disabled?
50
+ assert_equal false, dlmlock.locked?
51
+ assert_equal false, dlmlock.taken?
52
+ end
53
+
54
+ test 'can be acquired' do
55
+ assert_nil dlmlock.host
56
+ assert dlmlock.acquire!(host1)
57
+ assert_equal host1, dlmlock.reload.host
58
+ end
59
+
60
+ test 'can be released' do
61
+ assert_nil dlmlock.host
62
+ assert dlmlock.release!(host1)
63
+ assert_nil dlmlock.reload.host
64
+ end
65
+
66
+ test 'creates a dlmlock_event on acquisition by owner' do
67
+ assert_difference -> { DlmlockEvent.count }, 1 do
68
+ assert dlmlock.acquire!(host1)
69
+ end
70
+
71
+ event = DlmlockEvent.last
72
+ assert_equal 'acquire', event.event_type
73
+ assert_equal host1.id, event.host_id
74
+ assert_equal users(:admin).id, event.user_id
75
+ assert_equal dlmlock.id, event.dlmlock_id
76
+ end
77
+
78
+ test 'triggers after_lock callback' do
79
+ host = HostWithCallbacks.new
80
+ host.name = 'test.example.com'
81
+ host.save
82
+ assert dlmlock.acquire!(host)
83
+ assert_equal ['callback1'], host.callbacks
84
+ end
85
+ end
86
+
87
+ context 'a free and disabled DLM lock' do
88
+ let(:dlmlock) { FactoryBot.create(:dlmlock, :enabled => false) }
89
+
90
+ test 'should be disabled and unlocked' do
91
+ assert_equal false, dlmlock.enabled?
92
+ assert_equal true, dlmlock.disabled?
93
+ assert_equal false, dlmlock.locked?
94
+ assert_equal false, dlmlock.taken?
95
+ end
96
+
97
+ test 'can not be acquired' do
98
+ assert_nil dlmlock.host
99
+ assert_equal false, dlmlock.acquire!(host1)
100
+ assert_nil dlmlock.reload.host
101
+ end
102
+
103
+ test 'can not be released' do
104
+ assert_nil dlmlock.host
105
+ assert_equal false, dlmlock.release!(host1)
106
+ assert_nil dlmlock.reload.host
107
+ end
108
+
109
+ test 'triggers no callbacks' do
110
+ host = HostWithCallbacks.new
111
+ host.name = 'test.example.com'
112
+ host.save
113
+ assert_equal false, dlmlock.release!(host)
114
+ assert_equal [], host.callbacks
115
+ end
116
+ end
117
+
118
+ context 'an acquired DLM lock' do
119
+ let(:dlmlock) { FactoryBot.create(:dlmlock, :host => host1) }
120
+
121
+ test 'should be enabled and locked' do
122
+ assert_equal true, dlmlock.enabled?
123
+ assert_equal false, dlmlock.disabled?
124
+ assert_equal true, dlmlock.locked?
125
+ assert_equal true, dlmlock.taken?
126
+ assert_equal true, dlmlock.locked_by?(host1)
127
+ assert_equal true, dlmlock.acquired_by?(host1)
128
+ end
129
+
130
+ test 'can be acquired by owner' do
131
+ assert_equal host1, dlmlock.host
132
+ assert dlmlock.acquire!(host1)
133
+ assert_equal host1, dlmlock.reload.host
134
+ end
135
+
136
+ test 'can not be acquired by other host' do
137
+ assert_equal host1, dlmlock.host
138
+ assert_equal false, dlmlock.acquire!(host2)
139
+ assert_equal host1, dlmlock.reload.host
140
+ end
141
+
142
+ test 'can be released by owner' do
143
+ assert_equal host1, dlmlock.host
144
+ assert dlmlock.release!(host1)
145
+ assert_nil dlmlock.reload.host
146
+ end
147
+
148
+ test 'can not be released by other host' do
149
+ assert_equal host1, dlmlock.host
150
+ assert_equal false, dlmlock.release!(host2)
151
+ assert_equal host1, dlmlock.reload.host
152
+ end
153
+
154
+ test 'records audit change on release by owner' do
155
+ dlmlock
156
+ assert_difference -> { DlmlockEvent.count }, 1 do
157
+ assert dlmlock.release!(host1)
158
+ end
159
+
160
+ event = DlmlockEvent.last
161
+ assert_equal 'release', event.event_type
162
+ assert_equal host1.id, event.host_id
163
+ assert_equal users(:admin).id, event.user_id
164
+ assert_equal dlmlock.id, event.dlmlock_id
165
+ end
166
+
167
+ test 'records no audit change on acquisition by owner' do
168
+ assert_no_difference "Audit.where(auditable_type: 'ForemanDlm::Dlmlock', action: 'update').count" do
169
+ assert dlmlock.acquire!(host1)
170
+ end
171
+ end
172
+
173
+ test 'triggers after_unlock callback on release by owner' do
174
+ host = HostWithCallbacks.new
175
+ host.name = 'test.example.com'
176
+ host.save
177
+ dlmlock.host = host
178
+ dlmlock.save
179
+ assert dlmlock.release!(host)
180
+ assert_equal ['callback2'], host.callbacks
181
+ end
182
+
183
+ test 'triggers no callbacks on release attempt by other host' do
184
+ assert host1_with_callbacks
185
+ assert host2_with_callbacks
186
+ dlmlock.update(:host => host1_with_callbacks)
187
+ assert_equal false, dlmlock.release!(host2_with_callbacks)
188
+ assert_equal [], host1_with_callbacks.callbacks
189
+ assert_equal [], host2_with_callbacks.callbacks
190
+ end
191
+
192
+ test 'triggers no callbacks on acquiry attempt by owner' do
193
+ assert host1_with_callbacks
194
+ dlmlock.update(:host => host1_with_callbacks)
195
+ assert dlmlock.acquire!(host1_with_callbacks)
196
+ assert_equal [], host1_with_callbacks.callbacks
197
+ end
198
+ end
199
+
200
+ context 'scoped search' do
201
+ test 'can be searched by name' do
202
+ dlmlock = FactoryBot.create(:dlmlock)
203
+ assert_equal Dlmlock::Update.find(dlmlock.id), Dlmlock.search_for("name ~ #{dlmlock.name}").first
204
+ end
205
+ end
206
+
207
+ describe '#locked' do
208
+ subject { Dlmlock.locked }
209
+
210
+ it 'includes only Distributed Locks that are locked' do
211
+ locked = FactoryBot.create(:dlmlock, :locked)
212
+ not_locked = FactoryBot.create(:dlmlock)
213
+
214
+ assert_includes subject, locked
215
+ refute_includes subject, not_locked
216
+ end
217
+ end
218
+
219
+ describe '#stale' do
220
+ setup do
221
+ FactoryBot.create(:setting, category: Setting::General, name: 'dlm_stale_time', value: 4)
222
+ end
223
+
224
+ subject { Dlmlock.stale }
225
+
226
+ it 'includes only Distributed Locks that are stale' do
227
+ now = Time.now.utc
228
+
229
+ travel_to now do
230
+ stale = FactoryBot.create(:dlmlock, :locked, updated_at: now - 5.hours)
231
+ not_stale = FactoryBot.create(:dlmlock, :locked, updated_at: now)
232
+ not_locked = FactoryBot.create(:dlmlock)
233
+
234
+ assert_includes subject, stale
235
+ refute_includes subject, not_stale
236
+ refute_includes subject, not_locked
237
+ end
238
+ end
239
+ end
240
+
241
+ context '#log_events' do
242
+ let(:dlmlock) { FactoryBot.create(:dlmlock) }
243
+
244
+ test 'logs acquire event' do
245
+ assert_difference -> { DlmlockEvent.count }, 1 do
246
+ dlmlock.acquire!(host1)
247
+ end
248
+
249
+ event = DlmlockEvent.last
250
+ assert_equal 'acquire', event.event_type
251
+ assert_equal host1, event.host
252
+ end
253
+
254
+ test 'logs disable event' do
255
+ assert_difference -> { DlmlockEvent.count }, 1 do
256
+ dlmlock.disable!
257
+ end
258
+
259
+ event = DlmlockEvent.last
260
+ assert_equal 'disable', event.event_type
261
+ end
262
+
263
+ test 'logs enable event' do
264
+ dlmlock.update(enabled: false)
265
+
266
+ assert_difference -> { DlmlockEvent.count }, 1 do
267
+ dlmlock.enable!
268
+ end
269
+
270
+ event = DlmlockEvent.last
271
+ assert_equal 'enable', event.event_type
272
+ end
273
+
274
+ test 'logs failed event' do
275
+ dlmlock.acquire!(host1)
276
+
277
+ assert_difference -> { DlmlockEvent.count }, 1 do
278
+ dlmlock.acquire!(host2)
279
+ end
280
+
281
+ event = DlmlockEvent.last
282
+ assert_equal 'fail', event.event_type
283
+ assert_equal host1, event.host
284
+ end
285
+
286
+ test 'logs release event' do
287
+ dlmlock.acquire!(host1)
288
+
289
+ assert_difference -> { DlmlockEvent.count }, 1 do
290
+ assert dlmlock.release!(host1)
291
+ end
292
+
293
+ event = DlmlockEvent.last
294
+ assert_equal 'release', event.event_type
295
+ assert_equal host1, event.host
296
+ end
297
+ end
298
+ end
299
+ end