setting_spec.rb 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. # Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
  2. require 'rails_helper'
  3. RSpec.describe Setting, type: :model do
  4. subject(:setting) { create(:setting) }
  5. describe '.get' do
  6. context 'when given a valid Setting#name' do
  7. it 'returns #state_current[:value]' do
  8. expect { setting.update(state_current: { value: 'foo' }) }
  9. .to change { described_class.get(setting.name) }.to('foo')
  10. end
  11. end
  12. context 'when interpolated value was set and cache is still valid' do
  13. it 'stores interpolated value' do
  14. create(:setting, name: 'broadcast_test', state: 'test')
  15. described_class.send(:load) # prewarm cache
  16. described_class.set('broadcast_test', 'test #{config.fqdn}') # rubocop:disable Lint/InterpolationCheck
  17. expect(described_class.get('broadcast_test'))
  18. .to eq("test #{described_class.get('fqdn')}")
  19. end
  20. end
  21. end
  22. describe '.set' do
  23. context 'when given a valid Setting#name' do
  24. it 'sets #state_current = { value: <arg> }' do
  25. expect { described_class.set(setting.name, 'foo') }
  26. .to change { setting.reload.state_current }.to({ 'value' => 'foo' })
  27. end
  28. end
  29. context 'when #preferences hash includes a :cache key' do
  30. subject(:setting) { create(:setting, preferences: { cache: ['foo'] }) }
  31. before { Rails.cache.write('foo', 'bar') }
  32. it 'resets the cache key' do
  33. expect { described_class.set(setting.name, 'baz') }
  34. .to change { Rails.cache.read('foo') }.to(nil)
  35. end
  36. end
  37. end
  38. describe '.reset' do
  39. context 'when given a valid Setting#name' do
  40. it 'sets #state_current = { value: <orig> } (via #state_initial[:value])' do
  41. setting.update(state_initial: { value: 'foo' })
  42. described_class.set(setting.name, 'bar')
  43. expect { described_class.reset(setting.name) }
  44. .to change { setting.reload.state_current }.to({ value: 'foo' })
  45. end
  46. end
  47. end
  48. describe '.cache_valid?' do
  49. context 'when loading first time' do
  50. before do
  51. # ensure no cache checks are set
  52. described_class.class_variable_set(:@@lookup_at, nil) # rubocop:disable Style/ClassVars
  53. described_class.class_variable_set(:@@query_cache_key, nil) # rubocop:disable Style/ClassVars
  54. end
  55. it 'cache is not valid' do
  56. expect(described_class).not_to be_cache_valid
  57. end
  58. end
  59. context 'when cache is valid' do
  60. before do
  61. # ensure cache is warm
  62. described_class.send(:load)
  63. # ensure cache is not touched by broadcasting the new value
  64. allow_any_instance_of(described_class).to receive(:broadcast_frontend)
  65. end
  66. it 'cache is valid' do
  67. expect(described_class).to be_cache_valid
  68. end
  69. it 'cache is still valid after some time' do
  70. travel 1.minute
  71. expect(described_class).to be_cache_valid
  72. end
  73. context 'when Setting is updated in the same process' do
  74. before { described_class.set('maintenance_login', 'sample message') }
  75. it 'cache is not valid' do
  76. expect(described_class).not_to be_cache_valid
  77. end
  78. end
  79. context 'when Setting updated outside of the process and class variables were not touched' do
  80. before { described_class.find_by(name: 'maintenance_login').touch }
  81. it 'cache is seen as valid' do
  82. expect(described_class).to be_cache_valid
  83. end
  84. it 'cache is seen as invalid after some time' do
  85. travel 1.minute
  86. expect(described_class).not_to be_cache_valid
  87. end
  88. end
  89. end
  90. end
  91. describe 'attributes' do
  92. describe '#state_initial' do
  93. subject(:setting) { build(:setting, state: 'foo') }
  94. it 'is set on creation, based on #state' do
  95. expect { setting.save }
  96. .to change(setting, :state_initial).from({}).to({ value: 'foo' })
  97. end
  98. end
  99. end
  100. describe 'broadcast_frontend' do
  101. subject(:setting) do
  102. build(:setting, name: 'broadcast_test', state: value, frontend: frontend)
  103. .tap { |setting| setting.preferences = { authentication: true } if authentication_required }
  104. end
  105. let(:value) { 'foo' }
  106. let(:frontend) { true }
  107. let(:authentication_required) { false }
  108. context 'when setting is non-frontend' do
  109. let(:frontend) { false }
  110. it 'does not broadcast' do
  111. allow(Sessions).to receive(:broadcast)
  112. setting.save
  113. expect(Sessions).not_to have_received(:broadcast)
  114. end
  115. it 'does not trigger subscription' do
  116. allow(Gql::Subscriptions::ConfigUpdates).to receive(:trigger)
  117. setting.save
  118. expect(Gql::Subscriptions::ConfigUpdates).not_to have_received(:trigger).with(setting)
  119. end
  120. end
  121. context 'when setting is public' do
  122. it 'broadcasts to public' do
  123. allow(Sessions).to receive(:broadcast)
  124. setting.save
  125. expect(Sessions).to have_received(:broadcast)
  126. .with({ data: { name: 'broadcast_test', value: 'foo' }, event: 'config_update' }, 'public')
  127. end
  128. it 'triggers subscription' do
  129. allow(Gql::Subscriptions::ConfigUpdates).to receive(:trigger)
  130. setting.save
  131. expect(Gql::Subscriptions::ConfigUpdates).to have_received(:trigger).with(setting)
  132. end
  133. end
  134. context 'when setting requires authentication' do
  135. let(:authentication_required) { true }
  136. it 'broadcasts to authenticated only' do
  137. allow(Sessions).to receive(:broadcast)
  138. setting.save
  139. expect(Sessions).to have_received(:broadcast)
  140. .with({ data: { name: 'broadcast_test', value: 'foo' }, event: 'config_update' }, 'authenticated')
  141. end
  142. it 'triggers subscription' do
  143. allow(Gql::Subscriptions::ConfigUpdates).to receive(:trigger)
  144. setting.save
  145. expect(Gql::Subscriptions::ConfigUpdates).to have_received(:trigger).with(setting)
  146. end
  147. end
  148. context 'when setting uses interpolation' do
  149. let(:value) { 'test #{config.fqdn}' } # rubocop:disable Lint/InterpolationCheck
  150. it 'broadcasts to authenticated only' do
  151. allow(Sessions).to receive(:broadcast)
  152. setting.save
  153. expect(Sessions)
  154. .to have_received(:broadcast)
  155. .with(
  156. { data: { name: 'broadcast_test', value: "test #{described_class.get('fqdn')}" }, event: 'config_update' },
  157. 'public'
  158. )
  159. end
  160. it 'triggers subscription' do
  161. allow(Gql::Subscriptions::ConfigUpdates).to receive(:trigger)
  162. setting.save
  163. expect(Gql::Subscriptions::ConfigUpdates).to have_received(:trigger).with(setting)
  164. end
  165. end
  166. end
  167. end