diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-03-10 21:08:17 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-03-10 21:08:17 +0300 |
commit | 219eead23f9feb5da9ec378c451d773aea2dfe61 (patch) | |
tree | eec14421a05ca8eb79f3cc782abe99532bb6070c /spec | |
parent | 7c38405be9e79099f399aa429503ea7b463bbf5a (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
12 files changed, 213 insertions, 33 deletions
diff --git a/spec/controllers/import/gitlab_projects_controller_spec.rb b/spec/controllers/import/gitlab_projects_controller_spec.rb index a9aaefda0f6..0b74e2bbcbf 100644 --- a/spec/controllers/import/gitlab_projects_controller_spec.rb +++ b/spec/controllers/import/gitlab_projects_controller_spec.rb @@ -39,4 +39,62 @@ describe Import::GitlabProjectsController do it_behaves_like 'project import rate limiter' end + + describe 'POST authorize' do + let(:workhorse_token) { JWT.encode({ 'iss' => 'gitlab-workhorse' }, Gitlab::Workhorse.secret, 'HS256') } + + before do + request.headers['GitLab-Workhorse'] = '1.0' + request.headers[Gitlab::Workhorse::INTERNAL_API_REQUEST_HEADER] = workhorse_token + end + + it 'authorizes importing project with workhorse header' do + post :authorize, format: :json + + expect(response).to have_gitlab_http_status(:ok) + expect(response.content_type.to_s).to eq(Gitlab::Workhorse::INTERNAL_API_CONTENT_TYPE) + end + + it 'rejects requests that bypassed gitlab-workhorse or have invalid header' do + request.headers[Gitlab::Workhorse::INTERNAL_API_REQUEST_HEADER] = 'INVALID_HEADER' + + expect { post :authorize, format: :json }.to raise_error(JWT::DecodeError) + end + + context 'when using remote storage' do + context 'when direct upload is enabled' do + before do + stub_uploads_object_storage(ImportExportUploader, enabled: true, direct_upload: true) + end + + it 'responds with status 200, location of file remote store and object details' do + post :authorize, format: :json + + expect(response).to have_gitlab_http_status(:ok) + expect(response.content_type.to_s).to eq(Gitlab::Workhorse::INTERNAL_API_CONTENT_TYPE) + expect(json_response).not_to have_key('TempPath') + expect(json_response['RemoteObject']).to have_key('ID') + expect(json_response['RemoteObject']).to have_key('GetURL') + expect(json_response['RemoteObject']).to have_key('StoreURL') + expect(json_response['RemoteObject']).to have_key('DeleteURL') + expect(json_response['RemoteObject']).to have_key('MultipartUpload') + end + end + + context 'when direct upload is disabled' do + before do + stub_uploads_object_storage(ImportExportUploader, enabled: true, direct_upload: false) + end + + it 'handles as a local file' do + post :authorize, format: :json + + expect(response).to have_gitlab_http_status(:ok) + expect(response.content_type.to_s).to eq(Gitlab::Workhorse::INTERNAL_API_CONTENT_TYPE) + expect(json_response['TempPath']).to eq(ImportExportUploader.workhorse_local_upload_path) + expect(json_response['RemoteObject']).to be_nil + end + end + end + end end diff --git a/spec/features/issues/user_creates_issue_spec.rb b/spec/features/issues/user_creates_issue_spec.rb index b0a2a734877..efcaa8247df 100644 --- a/spec/features/issues/user_creates_issue_spec.rb +++ b/spec/features/issues/user_creates_issue_spec.rb @@ -156,7 +156,7 @@ describe "User creates issue" do expect(page.find_field("issue_description").value).not_to match /\n\n$/ end - it "cancels a file upload correctly" do + it "cancels a file upload correctly", :capybara_ignore_server_errors do slow_requests do dropzone_file([Rails.root.join('spec', 'fixtures', 'dk.png')], 0, false) diff --git a/spec/features/projects/tags/user_edits_tags_spec.rb b/spec/features/projects/tags/user_edits_tags_spec.rb index b1cb7685f63..6388875a619 100644 --- a/spec/features/projects/tags/user_edits_tags_spec.rb +++ b/spec/features/projects/tags/user_edits_tags_spec.rb @@ -68,7 +68,7 @@ describe 'Project > Tags', :js do end end - it 'shows "Attaching a file" message on uploading 1 file', :js do + it 'shows "Attaching a file" message on uploading 1 file', :js, :capybara_ignore_server_errors do slow_requests do dropzone_file([Rails.root.join('spec', 'fixtures', 'dk.png')], 0, false) diff --git a/spec/features/uploads/user_uploads_file_to_note_spec.rb b/spec/features/uploads/user_uploads_file_to_note_spec.rb index 30b5cf267ae..570ecad41fa 100644 --- a/spec/features/uploads/user_uploads_file_to_note_spec.rb +++ b/spec/features/uploads/user_uploads_file_to_note_spec.rb @@ -22,7 +22,7 @@ describe 'User uploads file to note' do end end - context 'uploading is in progress' do + context 'uploading is in progress', :capybara_ignore_server_errors do it 'cancels uploading on clicking to "Cancel" button', :js do slow_requests do dropzone_file([Rails.root.join('spec', 'fixtures', 'dk.png')], 0, false) diff --git a/spec/frontend/diffs/components/commit_item_spec.js b/spec/frontend/diffs/components/commit_item_spec.js index ecc28c78fb7..61bab77964e 100644 --- a/spec/frontend/diffs/components/commit_item_spec.js +++ b/spec/frontend/diffs/components/commit_item_spec.js @@ -59,7 +59,9 @@ describe('diffs/components/commit_item', () => { expect(titleElement.text()).toBe(commit.title_html); }); - it('renders commit description', () => { + // https://gitlab.com/gitlab-org/gitlab/-/issues/209776 + // eslint-disable-next-line jest/no-disabled-tests + it.skip('renders commit description', () => { const descElement = getDescElement(); const descExpandElement = getDescExpandElement(); diff --git a/spec/frontend/error_tracking/components/error_details_spec.js b/spec/frontend/error_tracking/components/error_details_spec.js index 2baec5f37fb..72b0466a1f0 100644 --- a/spec/frontend/error_tracking/components/error_details_spec.js +++ b/spec/frontend/error_tracking/components/error_details_spec.js @@ -1,6 +1,7 @@ import { createLocalVue, shallowMount } from '@vue/test-utils'; import Vuex from 'vuex'; import { __ } from '~/locale'; +import createFlash from '~/flash'; import { GlButton, GlLoadingIcon, @@ -18,6 +19,8 @@ import { errorStatus, } from '~/error_tracking/components/constants'; +jest.mock('~/flash'); + const localVue = createLocalVue(); localVue.use(Vuex); @@ -49,18 +52,6 @@ describe('ErrorDetails', () => { csrfToken: 'fakeToken', }, }); - wrapper.setData({ - error: { - id: 'gid://gitlab/Gitlab::ErrorTracking::DetailedError/129381', - sentryId: 129381, - title: 'Issue title', - externalUrl: 'http://sentry.gitlab.net/gitlab', - firstSeen: '2017-05-26T13:32:48Z', - lastSeen: '2018-05-26T13:32:48Z', - count: 12, - userCount: 2, - }, - }); } beforeEach(() => { @@ -78,6 +69,7 @@ describe('ErrorDetails', () => { const state = { stacktraceData: {}, loadingStacktrace: true, + errorStatus: '', }; store = new Vuex.Store({ @@ -99,6 +91,7 @@ describe('ErrorDetails', () => { error: { loading: true, stopPolling: jest.fn(), + setOptions: jest.fn(), }, }, }, @@ -123,10 +116,61 @@ describe('ErrorDetails', () => { }); }); + describe('sentry response timeout', () => { + const initTime = 300000; + const endTime = initTime + 10000; + + beforeEach(() => { + mocks.$apollo.queries.error.loading = false; + jest.spyOn(Date, 'now').mockReturnValue(initTime); + mountComponent(); + }); + + it('when before timeout, still shows loading', () => { + Date.now.mockReturnValue(endTime - 1); + + wrapper.vm.onNoApolloResult(); + + return wrapper.vm.$nextTick().then(() => { + expect(wrapper.find(GlLoadingIcon).exists()).toBe(true); + expect(createFlash).not.toHaveBeenCalled(); + expect(mocks.$apollo.queries.error.stopPolling).not.toHaveBeenCalled(); + }); + }); + + it('when timeout is hit and no apollo result, stops loading and shows flash', () => { + Date.now.mockReturnValue(endTime + 1); + + wrapper.vm.onNoApolloResult(); + + return wrapper.vm.$nextTick().then(() => { + expect(wrapper.find(GlLoadingIcon).exists()).toBe(false); + expect(wrapper.find(GlLink).exists()).toBe(false); + expect(createFlash).toHaveBeenCalledWith( + 'Could not connect to Sentry. Refresh the page to try again.', + 'warning', + ); + expect(mocks.$apollo.queries.error.stopPolling).toHaveBeenCalled(); + }); + }); + }); + describe('Error details', () => { beforeEach(() => { mocks.$apollo.queries.error.loading = false; mountComponent(); + wrapper.setData({ + error: { + id: 'gid://gitlab/Gitlab::ErrorTracking::DetailedError/129381', + sentryId: 129381, + title: 'Issue title', + externalUrl: 'http://sentry.gitlab.net/gitlab', + firstSeen: '2017-05-26T13:32:48Z', + lastSeen: '2018-05-26T13:32:48Z', + count: 12, + userCount: 2, + }, + }); }); it('should show Sentry error details without stacktrace', () => { @@ -232,10 +276,6 @@ describe('ErrorDetails', () => { }); describe('When a user clicks the create issue button', () => { - beforeEach(() => { - mountComponent(); - }); - it('should send sentry_issue_identifier', () => { const sentryErrorIdInput = findInput( 'issue[sentry_issue_attributes][sentry_issue_identifier]', @@ -275,7 +315,8 @@ describe('ErrorDetails', () => { describe('when error is unresolved', () => { beforeEach(() => { store.state.details.errorStatus = errorStatus.UNRESOLVED; - mountComponent(); + + return wrapper.vm.$nextTick(); }); it('displays Ignore and Resolve buttons', () => { @@ -301,7 +342,8 @@ describe('ErrorDetails', () => { describe('when error is ignored', () => { beforeEach(() => { store.state.details.errorStatus = errorStatus.IGNORED; - mountComponent(); + + return wrapper.vm.$nextTick(); }); it('displays Undo Ignore and Resolve buttons', () => { @@ -327,7 +369,8 @@ describe('ErrorDetails', () => { describe('when error is resolved', () => { beforeEach(() => { store.state.details.errorStatus = errorStatus.RESOLVED; - mountComponent(); + + return wrapper.vm.$nextTick(); }); it('displays Ignore and Unresolve buttons', () => { diff --git a/spec/helpers/markup_helper_spec.rb b/spec/helpers/markup_helper_spec.rb index 96c8b557625..33347f20de8 100644 --- a/spec/helpers/markup_helper_spec.rb +++ b/spec/helpers/markup_helper_spec.rb @@ -114,7 +114,7 @@ describe MarkupHelper do let(:requested_path) { nil } it 'returns the link to the image path as a relative path' do - expanded_path = "/#{project.full_path}/master/./#{image_file}" + expanded_path = "/#{project.full_path}/-/blob/master/./#{image_file}" expect(subject.css('a')[0].attr('href')).to eq(expanded_path) end diff --git a/spec/lib/banzai/filter/repository_link_filter_spec.rb b/spec/lib/banzai/filter/repository_link_filter_spec.rb index f093a5b0a79..460c76acd78 100644 --- a/spec/lib/banzai/filter/repository_link_filter_spec.rb +++ b/spec/lib/banzai/filter/repository_link_filter_spec.rb @@ -145,7 +145,7 @@ describe Banzai::Filter::RepositoryLinkFilter do it 'ignores ref if commit is passed' do doc = filter(link('non/existent.file'), commit: project.commit('empty-branch') ) expect(doc.at_css('a')['href']) - .to eq "/#{project_path}/#{ref}/non/existent.file" # non-existent files have no leading blob/raw/tree + .to eq "/#{project_path}/-/blob/#{ref}/non/existent.file" end shared_examples :valid_repository do @@ -201,6 +201,12 @@ describe Banzai::Filter::RepositoryLinkFilter do .to eq "/#{project_path}/-/blob/#{ref}/doc/api/README.md" end + it 'rebuilds relative URL for a missing file in the repo' do + doc = filter(link('missing-file')) + expect(doc.at_css('a')['href']) + .to eq "/#{project_path}/-/blob/#{ref}/missing-file" + end + it 'rebuilds relative URL for a file in the repo with leading ./' do doc = filter(link('./doc/api/README.md')) expect(doc.at_css('a')['href']) diff --git a/spec/models/concerns/bulk_insertable_associations_spec.rb b/spec/models/concerns/bulk_insertable_associations_spec.rb index 9e584417697..6359b2c57ef 100644 --- a/spec/models/concerns/bulk_insertable_associations_spec.rb +++ b/spec/models/concerns/bulk_insertable_associations_spec.rb @@ -57,16 +57,12 @@ describe BulkInsertableAssociations do end end - before do - ActiveRecord::Base.connection.execute('TRUNCATE bulk_foos RESTART IDENTITY') - end - context 'saving bulk insertable associations' do let(:parent) { BulkParent.new(name: 'parent') } context 'when items already have IDs' do it 'stores nothing and raises an error' do - build_items(parent: parent) { |n, item| item.id = 100 + n } + build_items(parent: parent) { |n, item| item.id = n } expect { save_with_bulk_inserts(parent) }.to raise_error(BulkInsertSafe::PrimaryKeySetError) expect(BulkFoo.count).to eq(0) @@ -79,7 +75,7 @@ describe BulkInsertableAssociations do expect(BulkFoo).to receive(:bulk_insert!).once.and_call_original expect { save_with_bulk_inserts(parent) }.to change { BulkFoo.count }.from(0).to(items.size) - expect(parent.bulk_foos.pluck(:id)).to contain_exactly(*(1..10)) + expect(parent.bulk_foos.pluck(:id)).to all(be_a Integer) end end diff --git a/spec/support/capybara.rb b/spec/support/capybara.rb index af179e81b08..ca4a81773aa 100644 --- a/spec/support/capybara.rb +++ b/spec/support/capybara.rb @@ -23,6 +23,18 @@ JS_CONSOLE_FILTER = Regexp.union([ CAPYBARA_WINDOW_SIZE = [1366, 768].freeze +# Run Workhorse on the given host and port, proxying to Puma on a UNIX socket, +# for a closer-to-production experience +Capybara.register_server :puma_via_workhorse do |app, port, host, **options| + file = Tempfile.new + socket_path = file.path + file.close! # We just want the filename + + TestEnv.with_workhorse(TestEnv.workhorse_dir, host, port, socket_path) do + Capybara.servers[:puma].call(app, nil, socket_path, **options) + end +end + Capybara.register_driver :chrome do |app| capabilities = Selenium::WebDriver::Remote::Capabilities.chrome( # This enables access to logs with `page.driver.manage.get_log(:browser)` @@ -60,7 +72,7 @@ Capybara.register_driver :chrome do |app| ) end -Capybara.server = :puma +Capybara.server = :puma_via_workhorse Capybara.javascript_driver = :chrome Capybara.default_max_wait_time = timeout Capybara.ignore_hidden_elements = true @@ -101,6 +113,18 @@ RSpec.configure do |config| end end + # The :capybara_ignore_server_errors metadata means unhandled exceptions raised + # by the application under test will not necessarily fail the server. This is + # useful when testing conditions that are expected to raise a 500 error in + # production; it should not be used on the happy path. + config.around(:each, :capybara_ignore_server_errors) do |example| + Capybara.raise_server_errors = false + + example.run + ensure + Capybara.raise_server_errors = true + end + config.after(:example, :js) do |example| # when a test fails, display any messages in the browser's console # but fail don't add the message if the failure is a pending test that got diff --git a/spec/support/helpers/test_env.rb b/spec/support/helpers/test_env.rb index bd945fe6409..0320f966c37 100644 --- a/spec/support/helpers/test_env.rb +++ b/spec/support/helpers/test_env.rb @@ -104,6 +104,9 @@ module TestEnv setup_gitaly + # Feature specs are run through Workhorse + setup_workhorse + # Create repository for FactoryBot.create(:project) setup_factory_repo @@ -218,6 +221,52 @@ module TestEnv ENV.fetch('GITALY_REPO_URL', nil) end + def setup_workhorse + install_workhorse_args = [workhorse_dir, workhorse_url].compact.join(',') + + component_timed_setup( + 'GitLab Workhorse', + install_dir: workhorse_dir, + version: Gitlab::Workhorse.version, + task: "gitlab:workhorse:install[#{install_workhorse_args}]" + ) + end + + def workhorse_dir + @workhorse_path ||= File.join('tmp', 'tests', 'gitlab-workhorse') + end + + def with_workhorse(workhorse_dir, host, port, upstream, &blk) + host = "[#{host}]" if host.include?(':') + listen_addr = [host, port].join(':') + + workhorse_pid = spawn( + File.join(workhorse_dir, 'gitlab-workhorse'), + '-authSocket', upstream, + '-documentRoot', Rails.root.join('public').to_s, + '-listenAddr', listen_addr, + '-secretPath', Gitlab::Workhorse.secret_path.to_s, + # TODO: Needed for workhorse + redis features. + # https://gitlab.com/gitlab-org/gitlab/-/issues/209245 + # + # '-config', '', + '-logFile', 'log/workhorse-test.log', + '-logFormat', 'structured', + '-developmentMode' # to serve assets and rich error messages + ) + + begin + yield + ensure + Process.kill('TERM', workhorse_pid) + Process.wait(workhorse_pid) + end + end + + def workhorse_url + ENV.fetch('GITLAB_WORKHORSE_URL', nil) + end + def setup_factory_repo setup_repo(factory_repo_path, factory_repo_path_bare, factory_repo_name, BRANCH_SHA) @@ -347,6 +396,8 @@ module TestEnv gitlab-test_bare gitlab-test-fork gitlab-test-fork_bare + gitlab-workhorse + gitlab_workhorse_secret ] end diff --git a/spec/support/shared_examples/features/wiki_file_attachments_shared_examples.rb b/spec/support/shared_examples/features/wiki_file_attachments_shared_examples.rb index 867290fb2d6..d30e8241da0 100644 --- a/spec/support/shared_examples/features/wiki_file_attachments_shared_examples.rb +++ b/spec/support/shared_examples/features/wiki_file_attachments_shared_examples.rb @@ -20,7 +20,7 @@ RSpec.shared_examples 'wiki file attachments' do end end - context 'uploading is in progress' do + context 'uploading is in progress', :capybara_ignore_server_errors do it 'cancels uploading on clicking to "Cancel" button' do slow_requests do attach_with_dropzone |