Commit 6afe6fa6 authored by Rémy Coutable's avatar Rémy Coutable

Make Gitlab::CurrentSettings.current_application_settings return cached...

Make Gitlab::CurrentSettings.current_application_settings return cached settings early if they exist without issuing any DB query
Signed-off-by: default avatarRémy Coutable <remy@rymai.me>
parent 1bcdd25c
...@@ -32,8 +32,10 @@ module Gitlab ...@@ -32,8 +32,10 @@ module Gitlab
begin begin
::ApplicationSetting.cached ::ApplicationSetting.cached
rescue ::Redis::BaseError, ::Errno::ENOENT, ::Errno::EADDRNOTAVAIL rescue
# In case Redis isn't running or the Redis UNIX socket file is not available # In case Redis isn't running
# or the Redis UNIX socket file is not available
# or the DB is not running (we use migrations in the cache key)
end end
end end
......
...@@ -5,6 +5,13 @@ describe Gitlab::CurrentSettings do ...@@ -5,6 +5,13 @@ describe Gitlab::CurrentSettings do
stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false') stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false')
end end
shared_context 'with settings in cache' do
before do
create(:application_setting)
described_class.current_application_settings # warm the cache
end
end
describe '#current_application_settings', :use_clean_rails_memory_store_caching do describe '#current_application_settings', :use_clean_rails_memory_store_caching do
it 'allows keys to be called directly' do it 'allows keys to be called directly' do
db_settings = create(:application_setting, db_settings = create(:application_setting,
...@@ -31,16 +38,29 @@ describe Gitlab::CurrentSettings do ...@@ -31,16 +38,29 @@ describe Gitlab::CurrentSettings do
end end
context 'with DB unavailable' do context 'with DB unavailable' do
before do context 'and settings in cache' do
# For some reason, `allow(described_class).to receive(:connect_to_db?).and_return(false)` causes issues include_context 'with settings in cache'
# during the initialization phase of the test suite, so instead let's mock the internals of it
allow(ActiveRecord::Base.connection).to receive(:active?).and_return(false) it 'fetches the settings from cache without issuing any query' do
expect(ActiveRecord::QueryRecorder.new { described_class.current_application_settings }.count).to eq(0)
end
end end
it 'returns an in-memory ApplicationSetting object' do context 'and no settings in cache' do
expect(ApplicationSetting).not_to receive(:current) before do
# For some reason, `allow(described_class).to receive(:connect_to_db?).and_return(false)` causes issues
# during the initialization phase of the test suite, so instead let's mock the internals of it
allow(ActiveRecord::Base.connection).to receive(:active?).and_return(false)
expect(ApplicationSetting).not_to receive(:current)
end
expect(described_class.current_application_settings).to be_a(Gitlab::FakeApplicationSettings) it 'returns an in-memory ApplicationSetting object' do
expect(described_class.current_application_settings).to be_a(Gitlab::FakeApplicationSettings)
end
it 'does not issue any query' do
expect(ActiveRecord::QueryRecorder.new { described_class.current_application_settings }.count).to eq(0)
end
end end
end end
...@@ -52,73 +72,86 @@ describe Gitlab::CurrentSettings do ...@@ -52,73 +72,86 @@ describe Gitlab::CurrentSettings do
ar_wrapped_defaults.slice(*::ApplicationSetting.defaults.keys) ar_wrapped_defaults.slice(*::ApplicationSetting.defaults.keys)
end end
before do context 'and settings in cache' do
# For some reason, `allow(described_class).to receive(:connect_to_db?).and_return(true)` causes issues include_context 'with settings in cache'
# during the initialization phase of the test suite, so instead let's mock the internals of it
allow(ActiveRecord::Base.connection).to receive(:active?).and_return(true)
allow(ActiveRecord::Base.connection).to receive(:cached_table_exists?).with('application_settings').and_return(true)
end
it 'creates default ApplicationSettings if none are present' do it 'fetches the settings from cache' do
settings = described_class.current_application_settings # For some reason, `allow(described_class).to receive(:connect_to_db?).and_return(true)` causes issues
# during the initialization phase of the test suite, so instead let's mock the internals of it
expect(settings).to be_a(ApplicationSetting) expect(ActiveRecord::Base.connection).not_to receive(:active?)
expect(settings).to be_persisted expect(ActiveRecord::Base.connection).not_to receive(:cached_table_exists?)
expect(settings).to have_attributes(settings_from_defaults) expect(ActiveRecord::Migrator).not_to receive(:needs_migration?)
expect(ActiveRecord::QueryRecorder.new { described_class.current_application_settings }.count).to eq(0)
end
end end
context 'with migrations pending' do context 'and no settings in cache' do
before do before do
expect(ActiveRecord::Migrator).to receive(:needs_migration?).and_return(true) allow(ActiveRecord::Base.connection).to receive(:active?).and_return(true)
allow(ActiveRecord::Base.connection).to receive(:cached_table_exists?).with('application_settings').and_return(true)
end end
it 'returns an in-memory ApplicationSetting object' do it 'creates default ApplicationSettings if none are present' do
settings = described_class.current_application_settings settings = described_class.current_application_settings
expect(settings).to be_a(Gitlab::FakeApplicationSettings) expect(settings).to be_a(ApplicationSetting)
expect(settings.sign_in_enabled?).to eq(settings.sign_in_enabled) expect(settings).to be_persisted
expect(settings.sign_up_enabled?).to eq(settings.sign_up_enabled) expect(settings).to have_attributes(settings_from_defaults)
end end
it 'uses the existing database settings and falls back to defaults' do context 'with migrations pending' do
db_settings = create(:application_setting, before do
home_page_url: 'http://mydomain.com', expect(ActiveRecord::Migrator).to receive(:needs_migration?).and_return(true)
signup_enabled: false) end
settings = described_class.current_application_settings
app_defaults = ApplicationSetting.last it 'returns an in-memory ApplicationSetting object' do
settings = described_class.current_application_settings
expect(settings).to be_a(Gitlab::FakeApplicationSettings)
expect(settings.home_page_url).to eq(db_settings.home_page_url) expect(settings).to be_a(Gitlab::FakeApplicationSettings)
expect(settings.signup_enabled?).to be_falsey expect(settings.sign_in_enabled?).to eq(settings.sign_in_enabled)
expect(settings.signup_enabled).to be_falsey expect(settings.sign_up_enabled?).to eq(settings.sign_up_enabled)
end
# Check that unspecified values use the defaults
settings.reject! { |key, _| [:home_page_url, :signup_enabled].include? key } it 'uses the existing database settings and falls back to defaults' do
settings.each { |key, _| expect(settings[key]).to eq(app_defaults[key]) } db_settings = create(:application_setting,
home_page_url: 'http://mydomain.com',
signup_enabled: false)
settings = described_class.current_application_settings
app_defaults = ApplicationSetting.last
expect(settings).to be_a(Gitlab::FakeApplicationSettings)
expect(settings.home_page_url).to eq(db_settings.home_page_url)
expect(settings.signup_enabled?).to be_falsey
expect(settings.signup_enabled).to be_falsey
# Check that unspecified values use the defaults
settings.reject! { |key, _| [:home_page_url, :signup_enabled].include? key }
settings.each { |key, _| expect(settings[key]).to eq(app_defaults[key]) }
end
end end
end
context 'when ApplicationSettings.current is present' do context 'when ApplicationSettings.current is present' do
it 'returns the existing application settings' do it 'returns the existing application settings' do
expect(ApplicationSetting).to receive(:current).and_return(:current_settings) expect(ApplicationSetting).to receive(:current).and_return(:current_settings)
expect(described_class.current_application_settings).to eq(:current_settings) expect(described_class.current_application_settings).to eq(:current_settings)
end
end end
end
context 'when the application_settings table does not exists' do context 'when the application_settings table does not exists' do
it 'returns an in-memory ApplicationSetting object' do it 'returns an in-memory ApplicationSetting object' do
expect(ApplicationSetting).to receive(:create_from_defaults).and_raise(ActiveRecord::StatementInvalid) expect(ApplicationSetting).to receive(:create_from_defaults).and_raise(ActiveRecord::StatementInvalid)
expect(described_class.current_application_settings).to be_a(Gitlab::FakeApplicationSettings) expect(described_class.current_application_settings).to be_a(Gitlab::FakeApplicationSettings)
end
end end
end
context 'when the application_settings table is not fully migrated' do context 'when the application_settings table is not fully migrated' do
it 'returns an in-memory ApplicationSetting object' do it 'returns an in-memory ApplicationSetting object' do
expect(ApplicationSetting).to receive(:create_from_defaults).and_raise(ActiveRecord::UnknownAttributeError) expect(ApplicationSetting).to receive(:create_from_defaults).and_raise(ActiveRecord::UnknownAttributeError)
expect(described_class.current_application_settings).to be_a(Gitlab::FakeApplicationSettings) expect(described_class.current_application_settings).to be_a(Gitlab::FakeApplicationSettings)
end
end end
end end
end end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment