From 221b529789f4090341a825695aeb49b8df6dd11d Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Wed, 15 Apr 2020 09:09:46 +0000 Subject: Add latest changes from gitlab-org/gitlab@master --- .../registry/repositories_controller_spec.rb | 119 +++++++++++++-------- .../projects/static_site_editor_controller_spec.rb | 16 ++- .../components/edit_header_spec.js | 38 +++++++ .../components/publish_toolbar_spec.js | 14 +++ .../components/static_site_editor_spec.js | 21 +++- spec/frontend/static_site_editor/mock_data.js | 2 +- spec/lib/container_registry/client_spec.rb | 67 +++++++++--- spec/lib/gitlab/static_site_editor/config_spec.rb | 35 +++++- spec/requests/api/users_spec.rb | 12 +++ .../requests/response_status_shared_examples.rb | 9 ++ spec/uploaders/object_storage_spec.rb | 24 ++--- 11 files changed, 277 insertions(+), 80 deletions(-) create mode 100644 spec/frontend/static_site_editor/components/edit_header_spec.js create mode 100644 spec/support/shared_examples/requests/response_status_shared_examples.rb (limited to 'spec') diff --git a/spec/controllers/groups/registry/repositories_controller_spec.rb b/spec/controllers/groups/registry/repositories_controller_spec.rb index eadc3a7f739..a84664c6c04 100644 --- a/spec/controllers/groups/registry/repositories_controller_spec.rb +++ b/spec/controllers/groups/registry/repositories_controller_spec.rb @@ -7,6 +7,13 @@ describe Groups::Registry::RepositoriesController do let_it_be(:guest) { create(:user) } let_it_be(:group, reload: true) { create(:group) } + subject do + get :index, params: { + group_id: group, + format: format + } + end + before do stub_container_registry_config(enabled: true) group.add_owner(user) @@ -15,51 +22,67 @@ describe Groups::Registry::RepositoriesController do end shared_examples 'renders a list of repositories' do + let_it_be(:repo) { create_project_with_repo(test_group) } + + it 'returns a list of projects for json format' do + subject + + expect(response).to have_gitlab_http_status(:ok) + expect(json_response).to be_kind_of(Array) + expect(json_response.first).to include( + 'id' => repo.id, + 'name' => repo.name + ) + end + end + + shared_examples 'renders correctly' do context 'when user has access to registry' do - it 'show index page' do - expect(Gitlab::Tracking).not_to receive(:event) + let_it_be(:test_group) { group } - get :index, params: { - group_id: group - } + context 'html format' do + let(:format) { :html } - expect(response).to have_gitlab_http_status(:ok) - end + it 'show index page' do + expect(Gitlab::Tracking).not_to receive(:event) - it 'has the correct response schema' do - get :index, params: { - group_id: group, - format: :json - } + subject - expect(response).to match_response_schema('registry/repositories') - expect(response).to include_pagination_headers + expect(response).to have_gitlab_http_status(:ok) + end end - it 'returns a list of projects for json format' do - project = create(:project, group: group) - repo = create(:container_repository, project: project) - - get :index, params: { - group_id: group, - format: :json - } - - expect(response).to have_gitlab_http_status(:ok) - expect(json_response).to be_kind_of(Array) - expect(json_response.first).to include( - 'id' => repo.id, - 'name' => repo.name - ) - end + context 'json format' do + let(:format) { :json } + + it 'has the correct response schema' do + subject + + expect(response).to match_response_schema('registry/repositories') + expect(response).to include_pagination_headers + end - it 'tracks the event' do - expect(Gitlab::Tracking).to receive(:event).with(anything, 'list_repositories', {}) + it_behaves_like 'renders a list of repositories' - get :index, params: { - group_id: group, - format: :json - } + it_behaves_like 'a gitlab tracking event', described_class.name, 'list_repositories' + + context 'with project in subgroup' do + let_it_be(:test_group) { create(:group, parent: group ) } + + it_behaves_like 'renders a list of repositories' + + context 'with project in subgroup and group' do + let_it_be(:repo_in_test_group) { create_project_with_repo(test_group) } + let_it_be(:repo_in_group) { create_project_with_repo(group) } + + it 'returns all the projects' do + subject + + expect(json_response).to be_kind_of(Array) + expect(json_response.length).to eq 2 + end + end + end end end @@ -69,20 +92,30 @@ describe Groups::Registry::RepositoriesController do sign_in(guest) end - it 'renders not found' do - get :index, params: { - group_id: group - } - expect(response).to have_gitlab_http_status(:not_found) + context 'json format' do + let(:format) { :json } + + it_behaves_like 'returning response status', :not_found + end + + context 'html format' do + let(:format) { :html } + + it_behaves_like 'returning response status', :not_found end end end context 'GET #index' do - it_behaves_like 'renders a list of repositories' + it_behaves_like 'renders correctly' end context 'GET #show' do - it_behaves_like 'renders a list of repositories' + it_behaves_like 'renders correctly' + end + + def create_project_with_repo(group) + project = create(:project, group: test_group) + create(:container_repository, project: project) end end diff --git a/spec/controllers/projects/static_site_editor_controller_spec.rb b/spec/controllers/projects/static_site_editor_controller_spec.rb index d1224bb75c0..f7c8848b8cf 100644 --- a/spec/controllers/projects/static_site_editor_controller_spec.rb +++ b/spec/controllers/projects/static_site_editor_controller_spec.rb @@ -26,7 +26,21 @@ describe Projects::StaticSiteEditorController do end end - %w[guest developer maintainer].each do |role| + context 'as guest' do + let(:user) { create(:user) } + + before do + project.add_guest(user) + sign_in(user) + get :show, params: default_params + end + + it 'responds with 404 page' do + expect(response).to have_gitlab_http_status(:not_found) + end + end + + %w[developer maintainer].each do |role| context "as #{role}" do let(:user) { create(:user) } diff --git a/spec/frontend/static_site_editor/components/edit_header_spec.js b/spec/frontend/static_site_editor/components/edit_header_spec.js new file mode 100644 index 00000000000..2b0fe226a0b --- /dev/null +++ b/spec/frontend/static_site_editor/components/edit_header_spec.js @@ -0,0 +1,38 @@ +import { shallowMount } from '@vue/test-utils'; + +import EditHeader from '~/static_site_editor/components/edit_header.vue'; +import { DEFAULT_HEADING } from '~/static_site_editor/constants'; + +import { sourceContentTitle } from '../mock_data'; + +describe('~/static_site_editor/components/edit_header.vue', () => { + let wrapper; + + const buildWrapper = (propsData = {}) => { + wrapper = shallowMount(EditHeader, { + propsData: { + ...propsData, + }, + }); + }; + + const findHeading = () => wrapper.find({ ref: 'sseHeading' }); + + beforeEach(() => { + buildWrapper(); + }); + + afterEach(() => { + wrapper.destroy(); + }); + + it('renders the default heading if there is no title prop', () => { + expect(findHeading().text()).toBe(DEFAULT_HEADING); + }); + + it('renders the title prop value in the heading', () => { + buildWrapper({ title: sourceContentTitle }); + + expect(findHeading().text()).toBe(sourceContentTitle); + }); +}); diff --git a/spec/frontend/static_site_editor/components/publish_toolbar_spec.js b/spec/frontend/static_site_editor/components/publish_toolbar_spec.js index 0edc3f4c920..f00fc38430f 100644 --- a/spec/frontend/static_site_editor/components/publish_toolbar_spec.js +++ b/spec/frontend/static_site_editor/components/publish_toolbar_spec.js @@ -3,6 +3,8 @@ import { GlNewButton, GlLoadingIcon } from '@gitlab/ui'; import PublishToolbar from '~/static_site_editor/components/publish_toolbar.vue'; +import { returnUrl } from '../mock_data'; + describe('Static Site Editor Toolbar', () => { let wrapper; @@ -15,6 +17,7 @@ describe('Static Site Editor Toolbar', () => { }); }; + const findReturnUrlLink = () => wrapper.find({ ref: 'returnUrlLink' }); const findSaveChangesButton = () => wrapper.find(GlNewButton); const findLoadingIndicator = () => wrapper.find(GlLoadingIcon); @@ -38,6 +41,17 @@ describe('Static Site Editor Toolbar', () => { expect(findLoadingIndicator().classes()).toContain('invisible'); }); + it('does not render returnUrl link', () => { + expect(findReturnUrlLink().exists()).toBe(false); + }); + + it('renders returnUrl link when returnUrl prop exists', () => { + buildWrapper({ returnUrl }); + + expect(findReturnUrlLink().exists()).toBe(true); + expect(findReturnUrlLink().attributes('href')).toBe(returnUrl); + }); + describe('when saveable', () => { it('enables Submit Changes button', () => { buildWrapper({ saveable: true }); diff --git a/spec/frontend/static_site_editor/components/static_site_editor_spec.js b/spec/frontend/static_site_editor/components/static_site_editor_spec.js index 2c4fa0e061a..d427df9bd4b 100644 --- a/spec/frontend/static_site_editor/components/static_site_editor_spec.js +++ b/spec/frontend/static_site_editor/components/static_site_editor_spec.js @@ -7,9 +7,10 @@ import createState from '~/static_site_editor/store/state'; import StaticSiteEditor from '~/static_site_editor/components/static_site_editor.vue'; import EditArea from '~/static_site_editor/components/edit_area.vue'; +import EditHeader from '~/static_site_editor/components/edit_header.vue'; import PublishToolbar from '~/static_site_editor/components/publish_toolbar.vue'; -import { sourceContent } from '../mock_data'; +import { sourceContent, sourceContentTitle } from '../mock_data'; const localVue = createLocalVue(); @@ -60,6 +61,7 @@ describe('StaticSiteEditor', () => { }; const findEditArea = () => wrapper.find(EditArea); + const findEditHeader = () => wrapper.find(EditHeader); const findPublishToolbar = () => wrapper.find(PublishToolbar); const findSkeletonLoader = () => wrapper.find(GlSkeletonLoader); @@ -77,16 +79,21 @@ describe('StaticSiteEditor', () => { expect(findEditArea().exists()).toBe(false); }); + it('does not render edit header', () => { + expect(findEditHeader().exists()).toBe(false); + }); + it('does not render toolbar', () => { expect(findPublishToolbar().exists()).toBe(false); }); }); describe('when content is loaded', () => { - const content = 'edit area content'; + const content = sourceContent; + const title = sourceContentTitle; beforeEach(() => { - buildContentLoadedStore({ initialState: { content } }); + buildContentLoadedStore({ initialState: { content, title } }); buildWrapper(); }); @@ -94,6 +101,10 @@ describe('StaticSiteEditor', () => { expect(findEditArea().exists()).toBe(true); }); + it('renders the edit header', () => { + expect(findEditHeader().exists()).toBe(true); + }); + it('does not render skeleton loader', () => { expect(findSkeletonLoader().exists()).toBe(false); }); @@ -102,6 +113,10 @@ describe('StaticSiteEditor', () => { expect(findEditArea().props('value')).toBe(content); }); + it('passes page title to edit header', () => { + expect(findEditHeader().props('title')).toBe(title); + }); + it('renders toolbar', () => { expect(findPublishToolbar().exists()).toBe(true); }); diff --git a/spec/frontend/static_site_editor/mock_data.js b/spec/frontend/static_site_editor/mock_data.js index 1993636ab12..345ae0ce6f6 100644 --- a/spec/frontend/static_site_editor/mock_data.js +++ b/spec/frontend/static_site_editor/mock_data.js @@ -11,11 +11,11 @@ twitter_image: '/images/tweets/handbook-gitlab.png' - TOC {:toc .hidden-md .hidden-lg} `; - export const sourceContentTitle = 'Handbook'; export const username = 'gitlabuser'; export const projectId = '123456'; +export const returnUrl = 'https://www.gitlab.com'; export const sourcePath = 'foobar.md.html'; export const savedContentMeta = { diff --git a/spec/lib/container_registry/client_spec.rb b/spec/lib/container_registry/client_spec.rb index 5d2334a6d8f..0aad6568793 100644 --- a/spec/lib/container_registry/client_spec.rb +++ b/spec/lib/container_registry/client_spec.rb @@ -6,6 +6,21 @@ describe ContainerRegistry::Client do let(:token) { '12345' } let(:options) { { token: token } } let(:client) { described_class.new("http://container-registry", options) } + let(:push_blob_headers) do + { + 'Accept' => 'application/vnd.docker.distribution.manifest.v2+json, application/vnd.oci.image.manifest.v1+json', + 'Authorization' => "bearer #{token}", + 'Content-Type' => 'application/octet-stream', + 'User-Agent' => "GitLab/#{Gitlab::VERSION}" + } + end + let(:headers_with_accept_types) do + { + 'Accept' => 'application/vnd.docker.distribution.manifest.v2+json, application/vnd.oci.image.manifest.v1+json', + 'Authorization' => "bearer #{token}", + 'User-Agent' => "GitLab/#{Gitlab::VERSION}" + } + end shared_examples '#repository_manifest' do |manifest_type| let(:manifest) do @@ -25,14 +40,15 @@ describe ContainerRegistry::Client do "size" => 2828661 } ] - } + } end it 'GET /v2/:name/manifests/mytag' do stub_request(:get, "http://container-registry/v2/group/test/manifests/mytag") .with(headers: { - 'Accept' => described_class::ACCEPTED_TYPES.join(', '), - 'Authorization' => "bearer #{token}" + 'Accept' => 'application/vnd.docker.distribution.manifest.v2+json, application/vnd.oci.image.manifest.v1+json', + 'Authorization' => "bearer #{token}", + 'User-Agent' => "GitLab/#{Gitlab::VERSION}" }) .to_return(status: 200, body: manifest.to_json, headers: { content_type: manifest_type }) @@ -44,12 +60,23 @@ describe ContainerRegistry::Client do it_behaves_like '#repository_manifest', described_class::OCI_MANIFEST_V1_TYPE describe '#blob' do + let(:blob_headers) do + { + 'Accept' => 'application/octet-stream', + 'Authorization' => "bearer #{token}", + 'User-Agent' => "GitLab/#{Gitlab::VERSION}" + } + end + + let(:redirect_header) do + { + 'User-Agent' => "GitLab/#{Gitlab::VERSION}" + } + end + it 'GET /v2/:name/blobs/:digest' do stub_request(:get, "http://container-registry/v2/group/test/blobs/sha256:0123456789012345") - .with(headers: { - 'Accept' => 'application/octet-stream', - 'Authorization' => "bearer #{token}" - }) + .with(headers: blob_headers) .to_return(status: 200, body: "Blob") expect(client.blob('group/test', 'sha256:0123456789012345')).to eq('Blob') @@ -57,15 +84,14 @@ describe ContainerRegistry::Client do it 'follows 307 redirect for GET /v2/:name/blobs/:digest' do stub_request(:get, "http://container-registry/v2/group/test/blobs/sha256:0123456789012345") - .with(headers: { - 'Accept' => 'application/octet-stream', - 'Authorization' => "bearer #{token}" - }) + .with(headers: blob_headers) .to_return(status: 307, body: "", headers: { Location: 'http://redirected' }) # We should probably use hash_excluding here, but that requires an update to WebMock: # https://github.com/bblimke/webmock/blob/master/lib/webmock/matchers/hash_excluding_matcher.rb stub_request(:get, "http://redirected/") - .with { |request| !request.headers.include?('Authorization') } + .with(headers: redirect_header) do |request| + !request.headers.include?('Authorization') + end .to_return(status: 200, body: "Successfully redirected") response = client.blob('group/test', 'sha256:0123456789012345') @@ -76,10 +102,11 @@ describe ContainerRegistry::Client do def stub_upload(path, content, digest, status = 200) stub_request(:post, "http://container-registry/v2/#{path}/blobs/uploads/") + .with(headers: headers_with_accept_types) .to_return(status: status, body: "", headers: { 'location' => 'http://container-registry/next_upload?id=someid' }) stub_request(:put, "http://container-registry/next_upload?digest=#{digest}&id=someid") - .with(body: content) + .with(body: content, headers: push_blob_headers) .to_return(status: status, body: "", headers: {}) end @@ -136,11 +163,20 @@ describe ContainerRegistry::Client do end describe '#put_tag' do + let(:manifest_headers) do + { + 'Accept' => 'application/vnd.docker.distribution.manifest.v2+json, application/vnd.oci.image.manifest.v1+json', + 'Authorization' => "bearer #{token}", + 'Content-Type' => 'application/vnd.docker.distribution.manifest.v2+json', + 'User-Agent' => "GitLab/#{Gitlab::VERSION}" + } + end + subject { client.put_tag('path', 'tagA', { foo: :bar }) } it 'uploads the manifest and returns the digest' do stub_request(:put, "http://container-registry/v2/path/manifests/tagA") - .with(body: "{\n \"foo\": \"bar\"\n}") + .with(body: "{\n \"foo\": \"bar\"\n}", headers: manifest_headers) .to_return(status: 200, body: "", headers: { 'docker-content-digest' => 'sha256:123' }) expect(subject).to eq 'sha256:123' @@ -153,6 +189,7 @@ describe ContainerRegistry::Client do context 'when the tag exists' do before do stub_request(:delete, "http://container-registry/v2/group/test/tags/reference/a") + .with(headers: headers_with_accept_types) .to_return(status: 200, body: "") end @@ -162,6 +199,7 @@ describe ContainerRegistry::Client do context 'when the tag does not exist' do before do stub_request(:delete, "http://container-registry/v2/group/test/tags/reference/a") + .with(headers: headers_with_accept_types) .to_return(status: 404, body: "") end @@ -171,6 +209,7 @@ describe ContainerRegistry::Client do context 'when an error occurs' do before do stub_request(:delete, "http://container-registry/v2/group/test/tags/reference/a") + .with(headers: headers_with_accept_types) .to_return(status: 500, body: "") end diff --git a/spec/lib/gitlab/static_site_editor/config_spec.rb b/spec/lib/gitlab/static_site_editor/config_spec.rb index dea79fb0e92..8f61476722d 100644 --- a/spec/lib/gitlab/static_site_editor/config_spec.rb +++ b/spec/lib/gitlab/static_site_editor/config_spec.rb @@ -18,13 +18,44 @@ describe Gitlab::StaticSiteEditor::Config do it 'returns data for the frontend component' do is_expected.to eq( branch: 'master', - commit: repository.commit.id, + commit_id: repository.commit.id, namespace: 'namespace', path: 'README.md', project: 'project', project_id: project.id, - return_url: 'http://example.com' + return_url: 'http://example.com', + is_supported_content: true ) end + + context 'when branch is not master' do + let(:ref) { 'my-branch' } + + it { is_expected.to include(is_supported_content: false) } + end + + context 'when file does not have a markdown extension' do + let(:file_path) { 'README.txt' } + + it { is_expected.to include(is_supported_content: false) } + end + + context 'when file does not have an extension' do + let(:file_path) { 'README' } + + it { is_expected.to include(is_supported_content: false) } + end + + context 'when file does not exist' do + let(:file_path) { 'UNKNOWN.md' } + + it { is_expected.to include(is_supported_content: false) } + end + + context 'when repository is empty' do + let(:project) { create(:project_empty_repo) } + + it { is_expected.to include(is_supported_content: false) } + end end end diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb index ee0f7545adc..864f6f77f39 100644 --- a/spec/requests/api/users_spec.rb +++ b/spec/requests/api/users_spec.rb @@ -280,6 +280,18 @@ describe API::Users, :do_not_mock_admin_mode do expect(json_response.first['id']).to eq(user_with_2fa.id) end + it "returns users without projects" do + user_without_projects = create(:user) + create(:project, namespace: user.namespace) + create(:project, namespace: admin.namespace) + + get api('/users', admin), params: { without_projects: true } + + expect(response).to match_response_schema('public_api/v4/user/admins') + expect(json_response.size).to eq(1) + expect(json_response.first['id']).to eq(user_without_projects.id) + end + it 'returns 400 when provided incorrect sort params' do get api('/users', admin), params: { order_by: 'magic', sort: 'asc' } diff --git a/spec/support/shared_examples/requests/response_status_shared_examples.rb b/spec/support/shared_examples/requests/response_status_shared_examples.rb new file mode 100644 index 00000000000..6c450881efe --- /dev/null +++ b/spec/support/shared_examples/requests/response_status_shared_examples.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +RSpec.shared_examples 'returning response status' do |status| + it "returns #{status}" do + subject + + expect(response).to have_gitlab_http_status(status) + end +end diff --git a/spec/uploaders/object_storage_spec.rb b/spec/uploaders/object_storage_spec.rb index e844b0ad799..f42d581ece4 100644 --- a/spec/uploaders/object_storage_spec.rb +++ b/spec/uploaders/object_storage_spec.rb @@ -596,22 +596,6 @@ describe ObjectStorage do uploader.cache!(uploaded_file) end - context 'when local file is used' do - context 'when valid file is used' do - let(:uploaded_file) do - fixture_file_upload('spec/fixtures/rails_sample.jpg', 'image/jpg') - end - - it "properly caches the file" do - subject - - expect(uploader).to be_exists - expect(uploader.path).to start_with(uploader_class.root) - expect(uploader.filename).to eq('rails_sample.jpg') - end - end - end - context 'when local file is used' do let(:temp_file) { Tempfile.new("test") } @@ -627,6 +611,14 @@ describe ObjectStorage do context 'when valid file is specified' do let(:uploaded_file) { temp_file } + it 'properly caches the file' do + subject + + expect(uploader).to be_exists + expect(uploader.path).to start_with(uploader_class.root) + expect(uploader.filename).to eq(File.basename(uploaded_file.path)) + end + context 'when object storage and direct upload is specified' do before do stub_uploads_object_storage(uploader_class, enabled: true, direct_upload: true) -- cgit v1.2.1