Skip to content
Snippets Groups Projects
Commit 219eead2 authored by GitLab Bot's avatar GitLab Bot
Browse files

Add latest changes from gitlab-org/gitlab@master

parent 7c38405b
No related branches found
No related tags found
No related merge requests found
Showing
with 234 additions and 37 deletions
Loading
Loading
@@ -74,6 +74,8 @@ You can view the exact JSON payload in the administration panel. To view the pay
 
You can see how [the usage ping data maps to different stages of the product](https://gitlab.com/gitlab-data/analytics/blob/master/transform/snowflake-dbt/data/version_usage_stats_to_stage_mappings.csv).
 
Usage ping is important to GitLab as we use it to calculate our [Action Monthly Active Users (AMAU)](https://about.gitlab.com/handbook/product/metrics/#action-monthly-active-users-amau) which helps us measure the success of our features.
### Request flow example
 
The following example shows a basic request/response flow between the self-managed GitLab instance, GitLab Version Application,
Loading
Loading
Loading
Loading
@@ -131,7 +131,7 @@ module Banzai
path = cleaned_file_path(uri)
nested_path = relative_file_path(uri)
 
file_exists?(nested_path) ? nested_path : path
path_exists?(nested_path) ? nested_path : path
end
 
def cleaned_file_path(uri)
Loading
Loading
@@ -190,12 +190,12 @@ module Banzai
parts.push(path).join('/')
end
 
def file_exists?(path)
path.present? && uri_type(path).present?
def path_exists?(path)
path.present? && @uri_types[path] != :unknown
end
 
def uri_type(path)
@uri_types[path] == :unknown ? "" : @uri_types[path]
@uri_types[path] == :unknown ? :blob : @uri_types[path]
end
 
def current_commit
Loading
Loading
Loading
Loading
@@ -5609,6 +5609,9 @@ msgstr ""
msgid "Could not connect to FogBugz, check your URL"
msgstr ""
 
msgid "Could not connect to Sentry. Refresh the page to try again."
msgstr ""
msgid "Could not connect to Web IDE file mirror service."
msgstr ""
 
Loading
Loading
@@ -13697,6 +13700,18 @@ msgstr ""
msgid "Outbound requests"
msgstr ""
 
msgid "OutdatedBrowser|From May 2020 GitLab no longer supports Internet Explorer 11."
msgstr ""
msgid "OutdatedBrowser|GitLab may not work properly, because you are using an outdated web browser."
msgstr ""
msgid "OutdatedBrowser|Please install a %{browser_link_start}supported web browser%{browser_link_end} for a better experience."
msgstr ""
msgid "OutdatedBrowser|You can provide feedback %{feedback_link_start}on this issue%{feedback_link_end} or via your usual support channels."
msgstr ""
msgid "Overview"
msgstr ""
 
Loading
Loading
Loading
Loading
@@ -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
Loading
Loading
@@ -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)
 
Loading
Loading
Loading
Loading
@@ -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)
 
Loading
Loading
Loading
Loading
@@ -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)
Loading
Loading
Loading
Loading
@@ -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();
 
Loading
Loading
import { createLocalVue, shallowMount } from '@vue/test-utils';
import Vuex from 'vuex';
import { __ } from '~/locale';
import createFlash from '~/flash';
import {
GlButton,
GlLoadingIcon,
Loading
Loading
@@ -18,6 +19,8 @@ import {
errorStatus,
} from '~/error_tracking/components/constants';
 
jest.mock('~/flash');
const localVue = createLocalVue();
localVue.use(Vuex);
 
Loading
Loading
@@ -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(() => {
Loading
Loading
@@ -78,6 +69,7 @@ describe('ErrorDetails', () => {
const state = {
stacktraceData: {},
loadingStacktrace: true,
errorStatus: '',
};
 
store = new Vuex.Store({
Loading
Loading
@@ -99,6 +91,7 @@ describe('ErrorDetails', () => {
error: {
loading: true,
stopPolling: jest.fn(),
setOptions: jest.fn(),
},
},
},
Loading
Loading
@@ -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', () => {
Loading
Loading
@@ -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]',
Loading
Loading
@@ -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', () => {
Loading
Loading
@@ -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', () => {
Loading
Loading
@@ -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', () => {
Loading
Loading
Loading
Loading
@@ -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
Loading
Loading
Loading
Loading
@@ -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
Loading
Loading
@@ -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'])
Loading
Loading
Loading
Loading
@@ -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)
Loading
Loading
@@ -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
 
Loading
Loading
Loading
Loading
@@ -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)`
Loading
Loading
@@ -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
Loading
Loading
@@ -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
Loading
Loading
Loading
Loading
@@ -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
 
Loading
Loading
@@ -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)
Loading
Loading
@@ -347,6 +396,8 @@ module TestEnv
gitlab-test_bare
gitlab-test-fork
gitlab-test-fork_bare
gitlab-workhorse
gitlab_workhorse_secret
]
end
 
Loading
Loading
Loading
Loading
@@ -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
Loading
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment