foreman_dlm 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
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