Commit 31cc872b authored by Mark Chao's avatar Mark Chao

Merge branch 'ag-re-factor-read-only-mode-specs' into 'master'

Re-factor tests for read-only GitLab instance

See merge request gitlab-org/gitlab!46342
parents 76980df6 945e4c13
...@@ -13,12 +13,11 @@ RSpec.describe 'Geo read-only message', :geo do ...@@ -13,12 +13,11 @@ RSpec.describe 'Geo read-only message', :geo do
sign_in(user) sign_in(user)
end end
it 'shows read-only banner when on a Geo secondary' do context 'when on a Geo secondary' do
before do
stub_current_geo_node(secondary) stub_current_geo_node(secondary)
end
visit root_dashboard_path it_behaves_like 'Read-only instance', /You are on a secondary, read\-only Geo node\. If you want to make changes, you must visit the primary site.*Go to the primary site/
expect(page).to have_content('You are on a secondary, read-only Geo node. If you want to make changes, you must visit the primary site.')
expect(page).to have_content('Go to the primary site')
end end
end end
...@@ -3,78 +3,9 @@ ...@@ -3,78 +3,9 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Gitlab::Middleware::ReadOnly do RSpec.describe Gitlab::Middleware::ReadOnly do
include Rack::Test::Methods
using RSpec::Parameterized::TableSyntax
let(:rack_stack) do
rack = Rack::Builder.new do
use ActionDispatch::Session::CacheStore
use ActionDispatch::Flash
end
rack.run(subject)
rack.to_app
end
let(:observe_env) do
Module.new do
attr_reader :env
def call(env)
@env = env
super
end
end
end
let(:request) { Rack::MockRequest.new(rack_stack) }
subject do
described_class.new(fake_app).tap do |app|
app.extend(observe_env)
end
end
context 'normal requests to a read-only GitLab instance' do
let(:fake_app) { lambda { |env| [200, { 'Content-Type' => 'text/plain' }, ['OK']] } }
before do before do
allow(Gitlab::Database).to receive(:read_only?) { true } allow(Gitlab::Database).to receive(:read_only?) { true }
end end
shared_examples 'whitelisted request' do |request_type, request_url| it_behaves_like 'write access for a read-only GitLab (EE) instance'
it "expects a #{request_type.upcase} request to #{request_url} to be allowed" do
expect(Rails.application.routes).to receive(:recognize_path).and_call_original
response = request.send(request_type, request_url)
expect(response).not_to be_redirect
expect(subject).not_to disallow_request
end
end
context 'whitelisted requests' do
it_behaves_like 'whitelisted request', :patch, '/admin/geo/nodes/1'
it_behaves_like 'whitelisted request', :delete, '/admin/geo/replication/projects/1'
it_behaves_like 'whitelisted request', :post, '/admin/geo/replication/projects/1/resync'
it_behaves_like 'whitelisted request', :post, '/admin/geo/replication/projects/1/reverify'
it_behaves_like 'whitelisted request', :post, '/admin/geo/replication/projects/reverify_all'
it_behaves_like 'whitelisted request', :post, '/admin/geo/replication/projects/resync_all'
it_behaves_like 'whitelisted request', :post, '/admin/geo/replication/projects/1/force_redownload'
it_behaves_like 'whitelisted request', :delete, '/admin/geo/replication/uploads/1'
end
it 'expects geo replication node api requests to be allowed' do
response = request.post("/api/#{API::API.version}/geo_replication/designs/resync")
expect(response).not_to be_redirect
expect(subject).not_to disallow_request
end
end
end end
...@@ -38,7 +38,7 @@ RSpec.describe Gitlab::GitAccess do ...@@ -38,7 +38,7 @@ RSpec.describe Gitlab::GitAccess do
let(:primary_repo_url) { geo_primary_http_url_to_repo(project) } let(:primary_repo_url) { geo_primary_http_url_to_repo(project) }
let(:primary_repo_ssh_url) { geo_primary_ssh_url_to_repo(project) } let(:primary_repo_ssh_url) { geo_primary_ssh_url_to_repo(project) }
it_behaves_like 'a read-only GitLab instance' it_behaves_like 'git access for a read-only GitLab instance'
end end
describe "push_rule_check" do describe "push_rule_check" do
......
...@@ -130,7 +130,7 @@ RSpec.describe Gitlab::GitAccessWiki do ...@@ -130,7 +130,7 @@ RSpec.describe Gitlab::GitAccessWiki do
let(:primary_repo_url) { geo_primary_http_url_to_repo(project.wiki) } let(:primary_repo_url) { geo_primary_http_url_to_repo(project.wiki) }
let(:primary_repo_ssh_url) { geo_primary_ssh_url_to_repo(project.wiki) } let(:primary_repo_ssh_url) { geo_primary_ssh_url_to_repo(project.wiki) }
it_behaves_like 'a read-only GitLab instance' it_behaves_like 'git access for a read-only GitLab instance'
end end
context 'when wiki is disabled' do context 'when wiki is disabled' do
......
# frozen_string_literal: true # frozen_string_literal: true
RSpec.shared_examples 'a read-only GitLab instance' do RSpec.shared_examples 'git access for a read-only GitLab instance' do
it 'denies push access' do it 'denies push access' do
project.add_maintainer(user) project.add_maintainer(user)
......
# frozen_string_literal: true
RSpec.shared_examples 'write access for a read-only GitLab (EE) instance' do
include Rack::Test::Methods
using RSpec::Parameterized::TableSyntax
include_context 'with a mocked GitLab instance'
context 'normal requests to a read-only GitLab instance' do
let(:fake_app) { lambda { |env| [200, { 'Content-Type' => 'text/plain' }, ['OK']] } }
shared_examples 'allowlisted request' do |request_type, request_url|
it "expects a #{request_type.upcase} request to #{request_url} to be allowed" do
expect(Rails.application.routes).to receive(:recognize_path).and_call_original
response = request.send(request_type, request_url)
expect(response).not_to be_redirect
expect(subject).not_to disallow_request
end
end
context 'allowlisted requests' do
it_behaves_like 'allowlisted request', :patch, '/admin/geo/nodes/1'
it_behaves_like 'allowlisted request', :delete, '/admin/geo/replication/projects/1'
it_behaves_like 'allowlisted request', :post, '/admin/geo/replication/projects/1/resync'
it_behaves_like 'allowlisted request', :post, '/admin/geo/replication/projects/1/reverify'
it_behaves_like 'allowlisted request', :post, '/admin/geo/replication/projects/reverify_all'
it_behaves_like 'allowlisted request', :post, '/admin/geo/replication/projects/resync_all'
it_behaves_like 'allowlisted request', :post, '/admin/geo/replication/projects/1/force_redownload'
it_behaves_like 'allowlisted request', :delete, '/admin/geo/replication/uploads/1'
end
it 'expects geo replication node api requests to be allowed' do
response = request.post("/api/#{API::API.version}/geo_replication/designs/resync")
expect(response).not_to be_redirect
expect(subject).not_to disallow_request
end
end
end
...@@ -9,19 +9,19 @@ RSpec.describe 'read-only message' do ...@@ -9,19 +9,19 @@ RSpec.describe 'read-only message' do
sign_in(user) sign_in(user)
end end
it 'shows read-only banner when database is read-only' do context 'when database is read-only' do
before do
allow(Gitlab::Database).to receive(:read_only?).and_return(true) allow(Gitlab::Database).to receive(:read_only?).and_return(true)
end
visit root_dashboard_path it_behaves_like 'Read-only instance', /You are on a read\-only GitLab instance./
expect(page).to have_content('You are on a read-only GitLab instance.')
end end
it 'does not show read-only banner when database is able to read-write' do context 'when database is in read-write mode' do
before do
allow(Gitlab::Database).to receive(:read_only?).and_return(false) allow(Gitlab::Database).to receive(:read_only?).and_return(false)
end
visit root_dashboard_path it_behaves_like 'Read-write instance', /You are on a read\-only GitLab instance./
expect(page).not_to have_content('You are on a read-only GitLab instance.')
end end
end end
...@@ -3,209 +3,11 @@ ...@@ -3,209 +3,11 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Gitlab::Middleware::ReadOnly do RSpec.describe Gitlab::Middleware::ReadOnly do
include Rack::Test::Methods context 'when database is read-only' do
using RSpec::Parameterized::TableSyntax
let(:rack_stack) do
rack = Rack::Builder.new do
use ActionDispatch::Session::CacheStore
use ActionDispatch::Flash
end
rack.run(subject)
rack.to_app
end
let(:observe_env) do
Module.new do
attr_reader :env
def call(env)
@env = env
super
end
end
end
let(:request) { Rack::MockRequest.new(rack_stack) }
subject do
described_class.new(fake_app).tap do |app|
app.extend(observe_env)
end
end
context 'normal requests to a read-only GitLab instance' do
let(:fake_app) { lambda { |env| [200, { 'Content-Type' => 'text/plain' }, ['OK']] } }
before do before do
allow(Gitlab::Database).to receive(:read_only?) { true } allow(Gitlab::Database).to receive(:read_only?) { true }
end end
it 'expects PATCH requests to be disallowed' do it_behaves_like 'write access for a read-only GitLab instance'
response = request.patch('/test_request')
expect(response).to be_redirect
expect(subject).to disallow_request
end
it 'expects PUT requests to be disallowed' do
response = request.put('/test_request')
expect(response).to be_redirect
expect(subject).to disallow_request
end
it 'expects POST requests to be disallowed' do
response = request.post('/test_request')
expect(response).to be_redirect
expect(subject).to disallow_request
end
it 'expects a internal POST request to be allowed after a disallowed request' do
response = request.post('/test_request')
expect(response).to be_redirect
response = request.post("/api/#{API::API.version}/internal")
expect(response).not_to be_redirect
end
it 'expects DELETE requests to be disallowed' do
response = request.delete('/test_request')
expect(response).to be_redirect
expect(subject).to disallow_request
end
it 'expects POST of new file that looks like an LFS batch url to be disallowed' do
expect(Rails.application.routes).to receive(:recognize_path).and_call_original
response = request.post('/root/gitlab-ce/new/master/app/info/lfs/objects/batch')
expect(response).to be_redirect
expect(subject).to disallow_request
end
it 'returns last_vistited_url for disallowed request' do
response = request.post('/test_request')
expect(response.location).to eq 'http://localhost/'
end
context 'whitelisted requests' do
it 'expects a POST internal request to be allowed' do
expect(Rails.application.routes).not_to receive(:recognize_path)
response = request.post("/api/#{API::API.version}/internal")
expect(response).not_to be_redirect
expect(subject).not_to disallow_request
end
it 'expects a graphql request to be allowed' do
response = request.post("/api/graphql")
expect(response).not_to be_redirect
expect(subject).not_to disallow_request
end
context 'relative URL is configured' do
before do
stub_config_setting(relative_url_root: '/gitlab')
end
it 'expects a graphql request to be allowed' do
response = request.post("/gitlab/api/graphql")
expect(response).not_to be_redirect
expect(subject).not_to disallow_request
end
end
context 'sidekiq admin requests' do
where(:mounted_at) do
[
'',
'/',
'/gitlab',
'/gitlab/',
'/gitlab/gitlab',
'/gitlab/gitlab/'
]
end
with_them do
before do
stub_config_setting(relative_url_root: mounted_at)
end
it 'allows requests' do
path = File.join(mounted_at, 'admin/sidekiq')
response = request.post(path)
expect(response).not_to be_redirect
expect(subject).not_to disallow_request
response = request.get(path)
expect(response).not_to be_redirect
expect(subject).not_to disallow_request
end
end
end
where(:description, :path) do
'LFS request to batch' | '/root/rouge.git/info/lfs/objects/batch'
'LFS request to locks verify' | '/root/rouge.git/info/lfs/locks/verify'
'LFS request to locks create' | '/root/rouge.git/info/lfs/locks'
'LFS request to locks unlock' | '/root/rouge.git/info/lfs/locks/1/unlock'
'request to git-upload-pack' | '/root/rouge.git/git-upload-pack'
'request to git-receive-pack' | '/root/rouge.git/git-receive-pack'
end
with_them do
it "expects a POST #{description} URL to be allowed" do
expect(Rails.application.routes).to receive(:recognize_path).and_call_original
response = request.post(path)
expect(response).not_to be_redirect
expect(subject).not_to disallow_request
end
end
end
end
context 'json requests to a read-only GitLab instance' do
let(:fake_app) { lambda { |env| [200, { 'Content-Type' => 'application/json' }, ['OK']] } }
let(:content_json) { { 'CONTENT_TYPE' => 'application/json' } }
before do
allow(Gitlab::Database).to receive(:read_only?) { true }
end
it 'expects PATCH requests to be disallowed' do
response = request.patch('/test_request', content_json)
expect(response).to disallow_request_in_json
end
it 'expects PUT requests to be disallowed' do
response = request.put('/test_request', content_json)
expect(response).to disallow_request_in_json
end
it 'expects POST requests to be disallowed' do
response = request.post('/test_request', content_json)
expect(response).to disallow_request_in_json
end
it 'expects DELETE requests to be disallowed' do
response = request.delete('/test_request', content_json)
expect(response).to disallow_request_in_json
end
end end
end end
...@@ -3,55 +3,11 @@ ...@@ -3,55 +3,11 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe 'Requests on a read-only node' do RSpec.describe 'Requests on a read-only node' do
include GraphqlHelpers context 'when db is read-only' do
before do before do
allow(Gitlab::Database).to receive(:read_only?) { true } allow(Gitlab::Database).to receive(:read_only?) { true }
end end
context 'mutations' do it_behaves_like 'graphql on a read-only GitLab instance'
let(:current_user) { note.author }
let!(:note) { create(:note) }
let(:mutation) do
variables = {
id: GitlabSchema.id_from_object(note).to_s
}
graphql_mutation(:destroy_note, variables)
end
def mutation_response
graphql_mutation_response(:destroy_note)
end
it 'disallows the query' do
post_graphql_mutation(mutation, current_user: current_user)
expect(json_response['errors'].first['message']).to eq(Mutations::BaseMutation::ERROR_MESSAGE)
end
it 'does not destroy the Note' do
expect do
post_graphql_mutation(mutation, current_user: current_user)
end.not_to change { Note.count }
end
end
context 'read-only queries' do
let(:current_user) { create(:user) }
let(:project) { create(:project, :repository) }
before do
project.add_developer(current_user)
end
it 'allows the query' do
query = graphql_query_for('project', 'fullPath' => project.full_path)
post_graphql(query, current_user: current_user)
expect(graphql_data['project']).not_to be_nil
end
end end
end end
# frozen_string_literal: true
RSpec.shared_context 'with a mocked GitLab instance' do
let(:rack_stack) do
rack = Rack::Builder.new do
use ActionDispatch::Session::CacheStore
use ActionDispatch::Flash
end
rack.run(subject)
rack.to_app
end
let(:observe_env) do
Module.new do
attr_reader :env
def call(env)
@env = env
super
end
end
end
let(:request) { Rack::MockRequest.new(rack_stack) }
subject do
described_class.new(fake_app).tap do |app|
app.extend(observe_env)
end
end
end
# frozen_string_literal: true
RSpec.shared_examples 'write access for a read-only GitLab instance' do
include Rack::Test::Methods
using RSpec::Parameterized::TableSyntax
include_context 'with a mocked GitLab instance'
context 'normal requests to a read-only GitLab instance' do
let(:fake_app) { lambda { |env| [200, { 'Content-Type' => 'text/plain' }, ['OK']] } }
it 'expects PATCH requests to be disallowed' do
response = request.patch('/test_request')
expect(response).to be_redirect
expect(subject).to disallow_request
end
it 'expects PUT requests to be disallowed' do
response = request.put('/test_request')
expect(response).to be_redirect
expect(subject).to disallow_request
end
it 'expects POST requests to be disallowed' do
response = request.post('/test_request')
expect(response).to be_redirect
expect(subject).to disallow_request
end
it 'expects a internal POST request to be allowed after a disallowed request' do
response = request.post('/test_request')
expect(response).to be_redirect
response = request.post("/api/#{API::API.version}/internal")
expect(response).not_to be_redirect
end
it 'expects DELETE requests to be disallowed' do
response = request.delete('/test_request')
expect(response).to be_redirect
expect(subject).to disallow_request
end
it 'expects POST of new file that looks like an LFS batch url to be disallowed' do
expect(Rails.application.routes).to receive(:recognize_path).and_call_original
response = request.post('/root/gitlab-ce/new/master/app/info/lfs/objects/batch')
expect(response).to be_redirect
expect(subject).to disallow_request
end
it 'returns last_vistited_url for disallowed request' do
response = request.post('/test_request')
expect(response.location).to eq 'http://localhost/'
end
context 'allowlisted requests' do
it 'expects a POST internal request to be allowed' do
expect(Rails.application.routes).not_to receive(:recognize_path)
response = request.post("/api/#{API::API.version}/internal")
expect(response).not_to be_redirect
expect(subject).not_to disallow_request
end
it 'expects a graphql request to be allowed' do
response = request.post("/api/graphql")
expect(response).not_to be_redirect
expect(subject).not_to disallow_request
end
context 'relative URL is configured' do
before do
stub_config_setting(relative_url_root: '/gitlab')
end
it 'expects a graphql request to be allowed' do
response = request.post("/gitlab/api/graphql")
expect(response).not_to be_redirect
expect(subject).not_to disallow_request
end
end
context 'sidekiq admin requests' do
where(:mounted_at) do
[
'',
'/',
'/gitlab',
'/gitlab/',
'/gitlab/gitlab',
'/gitlab/gitlab/'
]
end
with_them do
before do
stub_config_setting(relative_url_root: mounted_at)
end
it 'allows requests' do
path = File.join(mounted_at, 'admin/sidekiq')
response = request.post(path)
expect(response).not_to be_redirect
expect(subject).not_to disallow_request
response = request.get(path)
expect(response).not_to be_redirect
expect(subject).not_to disallow_request
end
end
end
where(:description, :path) do
'LFS request to batch' | '/root/rouge.git/info/lfs/objects/batch'
'LFS request to locks verify' | '/root/rouge.git/info/lfs/locks/verify'
'LFS request to locks create' | '/root/rouge.git/info/lfs/locks'
'LFS request to locks unlock' | '/root/rouge.git/info/lfs/locks/1/unlock'
'request to git-upload-pack' | '/root/rouge.git/git-upload-pack'
'request to git-receive-pack' | '/root/rouge.git/git-receive-pack'
end
with_them do
it "expects a POST #{description} URL to be allowed" do
expect(Rails.application.routes).to receive(:recognize_path).and_call_original
response = request.post(path)
expect(response).not_to be_redirect
expect(subject).not_to disallow_request
end
end
end
end
context 'json requests to a read-only GitLab instance' do
let(:fake_app) { lambda { |env| [200, { 'Content-Type' => 'application/json' }, ['OK']] } }
let(:content_json) { { 'CONTENT_TYPE' => 'application/json' } }
before do
allow(Gitlab::Database).to receive(:read_only?) { true }
end
it 'expects PATCH requests to be disallowed' do
response = request.patch('/test_request', content_json)
expect(response).to disallow_request_in_json
end
it 'expects PUT requests to be disallowed' do
response = request.put('/test_request', content_json)
expect(response).to disallow_request_in_json
end
it 'expects POST requests to be disallowed' do
response = request.post('/test_request', content_json)
expect(response).to disallow_request_in_json
end
it 'expects DELETE requests to be disallowed' do
response = request.delete('/test_request', content_json)
expect(response).to disallow_request_in_json
end
end
end
# frozen_string_literal: true
RSpec.shared_examples 'Read-only instance' do |message|
it 'shows read-only banner' do
visit root_dashboard_path
expect(page).to have_content(message)
end
end
RSpec.shared_examples 'Read-write instance' do |message|
it 'does not show read-only banner' do
visit root_dashboard_path
expect(page).not_to have_content(message)
end
end
# frozen_string_literal: true
RSpec.shared_examples 'graphql on a read-only GitLab instance' do
include GraphqlHelpers
context 'mutations' do
let(:current_user) { note.author }
let!(:note) { create(:note) }
let(:mutation) do
variables = {
id: GitlabSchema.id_from_object(note).to_s
}
graphql_mutation(:destroy_note, variables)
end
it 'disallows the query' do
post_graphql_mutation(mutation, current_user: current_user)
expect(json_response['errors'].first['message']).to eq(Mutations::BaseMutation::ERROR_MESSAGE)
end
it 'does not destroy the Note' do
expect do
post_graphql_mutation(mutation, current_user: current_user)
end.not_to change { Note.count }
end
end
context 'read-only queries' do
let(:current_user) { create(:user) }
let(:project) { create(:project, :repository) }
before do
project.add_developer(current_user)
end
it 'allows the query' do
query = graphql_query_for('project', 'fullPath' => project.full_path)
post_graphql(query, current_user: current_user)
expect(graphql_data['project']).not_to be_nil
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