diff options
Diffstat (limited to 'spec/requests/api/internal/pages_spec.rb')
-rw-r--r-- | spec/requests/api/internal/pages_spec.rb | 382 |
1 files changed, 199 insertions, 183 deletions
diff --git a/spec/requests/api/internal/pages_spec.rb b/spec/requests/api/internal/pages_spec.rb index 56f1089843b..1006319eabf 100644 --- a/spec/requests/api/internal/pages_spec.rb +++ b/spec/requests/api/internal/pages_spec.rb @@ -3,193 +3,97 @@ require 'spec_helper' RSpec.describe API::Internal::Pages, feature_category: :pages do - let(:auth_headers) do - jwt_token = JWT.encode({ 'iss' => 'gitlab-pages' }, Gitlab::Pages.secret, 'HS256') - { Gitlab::Pages::INTERNAL_API_REQUEST_HEADER => jwt_token } + let_it_be(:group) { create(:group) } + let_it_be_with_reload(:project) { create(:project, group: group) } + + let(:auth_header) do + { + Gitlab::Pages::INTERNAL_API_REQUEST_HEADER => JWT.encode( + { 'iss' => 'gitlab-pages' }, + Gitlab::Pages.secret, 'HS256') + } end - let(:pages_secret) { SecureRandom.random_bytes(Gitlab::Pages::SECRET_LENGTH) } - before do - allow(Gitlab::Pages).to receive(:secret).and_return(pages_secret) + allow(Gitlab::Pages) + .to receive(:secret) + .and_return(SecureRandom.random_bytes(Gitlab::Pages::SECRET_LENGTH)) + stub_pages_object_storage(::Pages::DeploymentUploader) end - describe "GET /internal/pages/status" do - def query_enabled(headers = {}) - get api("/internal/pages/status"), headers: headers - end - + describe 'GET /internal/pages/status' do it 'responds with 401 Unauthorized' do - query_enabled + get api('/internal/pages/status') expect(response).to have_gitlab_http_status(:unauthorized) end it 'responds with 204 no content' do - query_enabled(auth_headers) + get api('/internal/pages/status'), headers: auth_header expect(response).to have_gitlab_http_status(:no_content) expect(response.body).to be_empty end end - describe "GET /internal/pages" do - def query_host(host, headers = {}) - get api("/internal/pages"), headers: headers, params: { host: host } - end - - around do |example| - freeze_time do - example.run - end - end - - context 'not authenticated' do + describe 'GET /internal/pages' do + context 'when not authenticated' do it 'responds with 401 Unauthorized' do - query_host('pages.gitlab.io') + get api('/internal/pages') expect(response).to have_gitlab_http_status(:unauthorized) end end - context 'authenticated' do - def query_host(host) - jwt_token = JWT.encode({ 'iss' => 'gitlab-pages' }, Gitlab::Pages.secret, 'HS256') - headers = { Gitlab::Pages::INTERNAL_API_REQUEST_HEADER => jwt_token } - - super(host, headers) + context 'when authenticated' do + before do + project.update_pages_deployment!(create(:pages_deployment, project: project)) end - def deploy_pages(project) - deployment = create(:pages_deployment, project: project) - project.mark_pages_as_deployed - project.update_pages_deployment!(deployment) + around do |example| + freeze_time do + example.run + end end - context 'domain does not exist' do + context 'when domain does not exist' do it 'responds with 204 no content' do - query_host('pages.gitlab.io') + get api('/internal/pages'), headers: auth_header, params: { host: 'any-domain.gitlab.io' } expect(response).to have_gitlab_http_status(:no_content) expect(response.body).to be_empty end end - context 'serverless domain' do - let(:namespace) { create(:namespace, name: 'gitlab-org') } - let(:project) { create(:project, namespace: namespace, name: 'gitlab-ce') } - let(:environment) { create(:environment, project: project) } - let(:pages_domain) { create(:pages_domain, domain: 'serverless.gitlab.io') } - let(:knative_without_ingress) { create(:clusters_applications_knative) } - let(:knative_with_ingress) { create(:clusters_applications_knative, external_ip: '10.0.0.1') } - - context 'without a knative ingress gateway IP' do - let!(:serverless_domain_cluster) do - create( - :serverless_domain_cluster, - uuid: 'abcdef12345678', - pages_domain: pages_domain, - knative: knative_without_ingress - ) - end - - let(:serverless_domain) do - create( - :serverless_domain, - serverless_domain_cluster: serverless_domain_cluster, - environment: environment - ) - end - - it 'responds with 204 no content' do - query_host(serverless_domain.uri.host) - - expect(response).to have_gitlab_http_status(:no_content) - expect(response.body).to be_empty - end - end - - context 'with a knative ingress gateway IP' do - let!(:serverless_domain_cluster) do - create( - :serverless_domain_cluster, - uuid: 'abcdef12345678', - pages_domain: pages_domain, - knative: knative_with_ingress - ) - end - - let(:serverless_domain) do - create( - :serverless_domain, - serverless_domain_cluster: serverless_domain_cluster, - environment: environment - ) - end - - it 'responds with 204 because of feature deprecation' do - query_host(serverless_domain.uri.host) + context 'when querying a custom domain' do + let_it_be(:pages_domain) { create(:pages_domain, domain: 'pages.io', project: project) } - expect(response).to have_gitlab_http_status(:no_content) - expect(response.body).to be_empty - - ## - # Serverless serving and reverse proxy to Kubernetes / Knative has - # been deprecated and disabled, as per - # https://gitlab.com/gitlab-org/gitlab-pages/-/issues/467 - # - # expect(response).to match_response_schema('internal/serverless/virtual_domain') - # expect(json_response['certificate']).to eq(pages_domain.certificate) - # expect(json_response['key']).to eq(pages_domain.key) - # - # expect(json_response['lookup_paths']).to eq( - # [ - # { - # 'source' => { - # 'type' => 'serverless', - # 'service' => "test-function.#{project.name}-#{project.id}-#{environment.slug}.#{serverless_domain_cluster.knative.hostname}", - # 'cluster' => { - # 'hostname' => serverless_domain_cluster.knative.hostname, - # 'address' => serverless_domain_cluster.knative.external_ip, - # 'port' => 443, - # 'cert' => serverless_domain_cluster.certificate, - # 'key' => serverless_domain_cluster.key - # } - # } - # } - # ] - # ) + context 'when there are no pages deployed for the related project' do + before do + project.mark_pages_as_not_deployed end - end - end - context 'custom domain' do - let(:namespace) { create(:namespace, name: 'gitlab-org') } - let(:project) { create(:project, namespace: namespace, name: 'gitlab-ce') } - let!(:pages_domain) { create(:pages_domain, domain: 'pages.io', project: project) } - - context 'when there are no pages deployed for the related project' do it 'responds with 204 No Content' do - query_host('pages.io') + get api('/internal/pages'), headers: auth_header, params: { host: 'pages.io' } expect(response).to have_gitlab_http_status(:no_content) end end context 'when there are pages deployed for the related project' do - it 'domain lookup is case insensitive' do - deploy_pages(project) + before do + project.mark_pages_as_deployed + end - query_host('Pages.IO') + it 'domain lookup is case insensitive' do + get api('/internal/pages'), headers: auth_header, params: { host: 'Pages.IO' } expect(response).to have_gitlab_http_status(:ok) end it 'responds with the correct domain configuration' do - deploy_pages(project) - - query_host('pages.io') + get api('/internal/pages'), headers: auth_header, params: { host: 'pages.io' } expect(response).to have_gitlab_http_status(:ok) expect(response).to match_response_schema('internal/pages/virtual_domain') @@ -212,7 +116,9 @@ RSpec.describe API::Internal::Pages, feature_category: :pages do 'sha256' => deployment.file_sha256, 'file_size' => deployment.size, 'file_count' => deployment.file_count - } + }, + 'unique_host' => nil, + 'root_directory' => deployment.root_directory } ] ) @@ -220,20 +126,67 @@ RSpec.describe API::Internal::Pages, feature_category: :pages do end end - context 'namespaced domain' do - let(:group) { create(:group, name: 'mygroup') } + context 'when querying a unique domain' do + before_all do + project.project_setting.update!( + pages_unique_domain: 'unique-domain', + pages_unique_domain_enabled: true + ) + end - before do - allow(Settings.pages).to receive(:host).and_return('gitlab-pages.io') - allow(Gitlab.config.pages).to receive(:url).and_return("http://gitlab-pages.io") + context 'when there are no pages deployed for the related project' do + before do + project.mark_pages_as_not_deployed + end + + it 'responds with 204 No Content' do + get api('/internal/pages'), headers: auth_header, params: { host: 'unique-domain.example.com' } + + expect(response).to have_gitlab_http_status(:no_content) + end end - context 'regular project' do - it 'responds with the correct domain configuration' do - project = create(:project, group: group, name: 'myproject') - deploy_pages(project) + context 'when there are pages deployed for the related project' do + before do + project.mark_pages_as_deployed + end + + context 'when the feature flag is disabled' do + before do + stub_feature_flags(pages_unique_domain: false) + end - query_host('mygroup.gitlab-pages.io') + context 'when there are no pages deployed for the related project' do + it 'responds with 204 No Content' do + get api('/internal/pages'), headers: auth_header, params: { host: 'unique-domain.example.com' } + + expect(response).to have_gitlab_http_status(:no_content) + end + end + end + + context 'when the unique domain is disabled' do + before do + project.project_setting.update!(pages_unique_domain_enabled: false) + end + + context 'when there are no pages deployed for the related project' do + it 'responds with 204 No Content' do + get api('/internal/pages'), headers: auth_header, params: { host: 'unique-domain.example.com' } + + expect(response).to have_gitlab_http_status(:no_content) + end + end + end + + it 'domain lookup is case insensitive' do + get api('/internal/pages'), headers: auth_header, params: { host: 'Unique-Domain.example.com' } + + expect(response).to have_gitlab_http_status(:ok) + end + + it 'responds with the correct domain configuration' do + get api('/internal/pages'), headers: auth_header, params: { host: 'unique-domain.example.com' } expect(response).to have_gitlab_http_status(:ok) expect(response).to match_response_schema('internal/pages/virtual_domain') @@ -245,7 +198,7 @@ RSpec.describe API::Internal::Pages, feature_category: :pages do 'project_id' => project.id, 'access_control' => false, 'https_only' => false, - 'prefix' => '/myproject/', + 'prefix' => '/', 'source' => { 'type' => 'zip', 'path' => deployment.file.url(expire_at: 1.day.from_now), @@ -253,56 +206,119 @@ RSpec.describe API::Internal::Pages, feature_category: :pages do 'sha256' => deployment.file_sha256, 'file_size' => deployment.size, 'file_count' => deployment.file_count - } + }, + 'unique_host' => 'unique-domain.example.com', + 'root_directory' => 'public' } ] ) end end + end - it 'avoids N+1 queries' do - project = create(:project, group: group) - deploy_pages(project) - - control = ActiveRecord::QueryRecorder.new { query_host('mygroup.gitlab-pages.io') } + context 'when querying a namespaced domain' do + before do + allow(Settings.pages).to receive(:host).and_return('gitlab-pages.io') + allow(Gitlab.config.pages).to receive(:url).and_return("http://gitlab-pages.io") + end - 3.times do - project = create(:project, group: group) - deploy_pages(project) + context 'when there are no pages deployed for the related project' do + before do + project.mark_pages_as_not_deployed end - expect { query_host('mygroup.gitlab-pages.io') }.not_to exceed_query_limit(control) + it 'responds with 204 No Content' do + get api('/internal/pages'), headers: auth_header, params: { host: "#{group.path}.gitlab-pages.io" } + + expect(response).to have_gitlab_http_status(:ok) + expect(response).to match_response_schema('internal/pages/virtual_domain') + expect(json_response['lookup_paths']).to eq([]) + end end - context 'group root project' do - it 'responds with the correct domain configuration' do - project = create(:project, group: group, name: 'mygroup.gitlab-pages.io') - deploy_pages(project) + context 'when there are pages deployed for the related project' do + before do + project.mark_pages_as_deployed + end - query_host('mygroup.gitlab-pages.io') + context 'with a regular project' do + it 'responds with the correct domain configuration' do + get api('/internal/pages'), headers: auth_header, params: { host: "#{group.path}.gitlab-pages.io" } + + expect(response).to have_gitlab_http_status(:ok) + expect(response).to match_response_schema('internal/pages/virtual_domain') + + deployment = project.pages_metadatum.pages_deployment + expect(json_response['lookup_paths']).to eq( + [ + { + 'project_id' => project.id, + 'access_control' => false, + 'https_only' => false, + 'prefix' => "/#{project.path}/", + 'source' => { + 'type' => 'zip', + 'path' => deployment.file.url(expire_at: 1.day.from_now), + 'global_id' => "gid://gitlab/PagesDeployment/#{deployment.id}", + 'sha256' => deployment.file_sha256, + 'file_size' => deployment.size, + 'file_count' => deployment.file_count + }, + 'unique_host' => nil, + 'root_directory' => 'public' + } + ] + ) + end + end - expect(response).to have_gitlab_http_status(:ok) - expect(response).to match_response_schema('internal/pages/virtual_domain') + it 'avoids N+1 queries' do + control = ActiveRecord::QueryRecorder.new do + get api('/internal/pages'), headers: auth_header, params: { host: "#{group.path}.gitlab-pages.io" } + end - deployment = project.pages_metadatum.pages_deployment - expect(json_response['lookup_paths']).to eq( - [ - { - 'project_id' => project.id, - 'access_control' => false, - 'https_only' => false, - 'prefix' => '/', - 'source' => { - 'type' => 'zip', - 'path' => deployment.file.url(expire_at: 1.day.from_now), - 'global_id' => "gid://gitlab/PagesDeployment/#{deployment.id}", - 'sha256' => deployment.file_sha256, - 'file_size' => deployment.size, - 'file_count' => deployment.file_count + 3.times do + project = create(:project, group: group) + project.mark_pages_as_deployed + end + + expect { get api('/internal/pages'), headers: auth_header, params: { host: "#{group.path}.gitlab-pages.io" } } + .not_to exceed_query_limit(control) + end + + context 'with a group root project' do + before do + project.update!(path: "#{group.path}.gitlab-pages.io") + end + + it 'responds with the correct domain configuration' do + get api('/internal/pages'), headers: auth_header, params: { host: "#{group.path}.gitlab-pages.io" } + + expect(response).to have_gitlab_http_status(:ok) + expect(response).to match_response_schema('internal/pages/virtual_domain') + + deployment = project.pages_metadatum.pages_deployment + expect(json_response['lookup_paths']).to eq( + [ + { + 'project_id' => project.id, + 'access_control' => false, + 'https_only' => false, + 'prefix' => '/', + 'source' => { + 'type' => 'zip', + 'path' => deployment.file.url(expire_at: 1.day.from_now), + 'global_id' => "gid://gitlab/PagesDeployment/#{deployment.id}", + 'sha256' => deployment.file_sha256, + 'file_size' => deployment.size, + 'file_count' => deployment.file_count + }, + 'unique_host' => nil, + 'root_directory' => 'public' } - } - ] - ) + ] + ) + end end end end |