diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-09-09 15:09:09 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-09-09 15:09:09 +0300 |
commit | 7ce86c261b3f910cf17b0b47a4200847578947df (patch) | |
tree | 20665e6a2b836f9ab38ba86680fa39ba33a04f21 /spec | |
parent | 54573816ab79fac6716d1a1eae8c0da602765774 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r-- | spec/controllers/projects/jobs_controller_spec.rb | 33 | ||||
-rw-r--r-- | spec/frontend/dropzone_input_spec.js | 48 | ||||
-rw-r--r-- | spec/frontend/fixtures/static/pipeline_graph.html | 24 | ||||
-rw-r--r-- | spec/frontend/pipelines_spec.js | 17 | ||||
-rw-r--r-- | spec/lib/gitlab/rack_attack/request_spec.rb | 16 | ||||
-rw-r--r-- | spec/lib/gitlab/tracking_spec.rb | 6 | ||||
-rw-r--r-- | spec/requests/rack_attack_global_spec.rb | 212 | ||||
-rw-r--r-- | spec/support/shared_examples/requests/rack_attack_shared_examples.rb | 5 | ||||
-rw-r--r-- | spec/workers/background_migration_worker_spec.rb | 22 |
9 files changed, 322 insertions, 61 deletions
diff --git a/spec/controllers/projects/jobs_controller_spec.rb b/spec/controllers/projects/jobs_controller_spec.rb index e9e7c3c3bb3..06c29e767ad 100644 --- a/spec/controllers/projects/jobs_controller_spec.rb +++ b/spec/controllers/projects/jobs_controller_spec.rb @@ -755,23 +755,52 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state do before do project.add_developer(user) sign_in(user) - - post_retry end context 'when job is retryable' do let(:job) { create(:ci_build, :retryable, pipeline: pipeline) } it 'redirects to the retried job page' do + post_retry + expect(response).to have_gitlab_http_status(:found) expect(response).to redirect_to(namespace_project_job_path(id: Ci::Build.last.id)) end + + shared_examples_for 'retried job has the same attributes' do + it 'creates a new build has the same attributes from the previous build' do + expect { post_retry }.to change { Ci::Build.count }.by(1) + + retried_build = Ci::Build.last + + Ci::RetryBuildService.clone_accessors.each do |accessor| + expect(job.read_attribute(accessor)) + .to eq(retried_build.read_attribute(accessor)), + "Mismatched attribute on \"#{accessor}\". " \ + "It was \"#{job.read_attribute(accessor)}\" but changed to \"#{retried_build.read_attribute(accessor)}\"" + end + end + end + + context 'with branch pipeline' do + let!(:job) { create(:ci_build, :retryable, tag: true, when: 'on_success', pipeline: pipeline) } + + it_behaves_like 'retried job has the same attributes' + end + + context 'with tag pipeline' do + let!(:job) { create(:ci_build, :retryable, tag: false, when: 'on_success', pipeline: pipeline) } + + it_behaves_like 'retried job has the same attributes' + end end context 'when job is not retryable' do let(:job) { create(:ci_build, pipeline: pipeline) } it 'renders unprocessable_entity' do + post_retry + expect(response).to have_gitlab_http_status(:unprocessable_entity) end end diff --git a/spec/frontend/dropzone_input_spec.js b/spec/frontend/dropzone_input_spec.js index 5e6ccbd7cda..acf7d0780cd 100644 --- a/spec/frontend/dropzone_input_spec.js +++ b/spec/frontend/dropzone_input_spec.js @@ -1,9 +1,12 @@ +import MockAdapter from 'axios-mock-adapter'; import $ from 'jquery'; import mock from 'xhr-mock'; import waitForPromises from 'helpers/wait_for_promises'; import { TEST_HOST } from 'spec/test_constants'; import PasteMarkdownTable from '~/behaviors/markdown/paste_markdown_table'; import dropzoneInput from '~/dropzone_input'; +import axios from '~/lib/utils/axios_utils'; +import httpStatusCodes from '~/lib/utils/http_status'; const TEST_FILE = new File([], 'somefile.jpg'); TEST_FILE.upload = {}; @@ -29,6 +32,16 @@ describe('dropzone_input', () => { }); describe('handlePaste', () => { + const triggerPasteEvent = (clipboardData = {}) => { + const event = $.Event('paste'); + const origEvent = new Event('paste'); + + origEvent.clipboardData = clipboardData; + event.originalEvent = origEvent; + + $('.js-gfm-input').trigger(event); + }; + beforeEach(() => { loadFixtures('issues/new-issue.html'); @@ -38,24 +51,39 @@ describe('dropzone_input', () => { }); it('pastes Markdown tables', () => { - const event = $.Event('paste'); - const origEvent = new Event('paste'); + jest.spyOn(PasteMarkdownTable.prototype, 'isTable'); + jest.spyOn(PasteMarkdownTable.prototype, 'convertToTableMarkdown'); - origEvent.clipboardData = { + triggerPasteEvent({ types: ['text/plain', 'text/html'], getData: () => '<table><tr><td>Hello World</td></tr></table>', items: [], - }; - event.originalEvent = origEvent; - - jest.spyOn(PasteMarkdownTable.prototype, 'isTable'); - jest.spyOn(PasteMarkdownTable.prototype, 'convertToTableMarkdown'); - - $('.js-gfm-input').trigger(event); + }); expect(PasteMarkdownTable.prototype.isTable).toHaveBeenCalled(); expect(PasteMarkdownTable.prototype.convertToTableMarkdown).toHaveBeenCalled(); }); + + it('passes truncated long filename to post request', async () => { + const axiosMock = new MockAdapter(axios); + const longFileName = 'a'.repeat(300); + + triggerPasteEvent({ + types: ['text/plain', 'text/html', 'text/rtf', 'Files'], + getData: () => longFileName, + items: [ + { + kind: 'file', + type: 'image/png', + getAsFile: () => new Blob(), + }, + ], + }); + + axiosMock.onPost().reply(httpStatusCodes.OK, { link: { markdown: 'foo' } }); + await waitForPromises(); + expect(axiosMock.history.post[0].data.get('file').name).toHaveLength(246); + }); }); describe('shows error message', () => { diff --git a/spec/frontend/fixtures/static/pipeline_graph.html b/spec/frontend/fixtures/static/pipeline_graph.html deleted file mode 100644 index d2c30ff9211..00000000000 --- a/spec/frontend/fixtures/static/pipeline_graph.html +++ /dev/null @@ -1,24 +0,0 @@ -<div class="pipeline-visualization js-pipeline-graph"> -<ul class="stage-column-list"> -<li class="stage-column"> -<div class="stage-name"> -<a href="/"> -Test -<div class="builds-container"> -<ul> -<li class="build"> -<div class="curve"></div> -<a> -<svg></svg> -<div> -stop_review -</div> -</a> -</li> -</ul> -</div> -</a> -</div> -</li> -</ul> -</div> diff --git a/spec/frontend/pipelines_spec.js b/spec/frontend/pipelines_spec.js deleted file mode 100644 index add91fbcc23..00000000000 --- a/spec/frontend/pipelines_spec.js +++ /dev/null @@ -1,17 +0,0 @@ -import Pipelines from '~/pipelines'; - -describe('Pipelines', () => { - beforeEach(() => { - loadFixtures('static/pipeline_graph.html'); - }); - - it('should be defined', () => { - expect(Pipelines).toBeDefined(); - }); - - it('should create a `Pipelines` instance without options', () => { - expect(() => { - new Pipelines(); // eslint-disable-line no-new - }).not.toThrow(); - }); -}); diff --git a/spec/lib/gitlab/rack_attack/request_spec.rb b/spec/lib/gitlab/rack_attack/request_spec.rb new file mode 100644 index 00000000000..3be7ec17e45 --- /dev/null +++ b/spec/lib/gitlab/rack_attack/request_spec.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::RackAttack::Request do + describe 'FILES_PATH_REGEX' do + subject { described_class::FILES_PATH_REGEX } + + it { is_expected.to match('/api/v4/projects/1/repository/files/README') } + it { is_expected.to match('/api/v4/projects/1/repository/files/README?ref=master') } + it { is_expected.to match('/api/v4/projects/1/repository/files/README/blame') } + it { is_expected.to match('/api/v4/projects/1/repository/files/README/raw') } + it { is_expected.to match('/api/v4/projects/some%2Fnested%2Frepo/repository/files/README') } + it { is_expected.not_to match('/api/v4/projects/some/nested/repo/repository/files/README') } + end +end diff --git a/spec/lib/gitlab/tracking_spec.rb b/spec/lib/gitlab/tracking_spec.rb index 90109db6db2..02e66458f46 100644 --- a/spec/lib/gitlab/tracking_spec.rb +++ b/spec/lib/gitlab/tracking_spec.rb @@ -11,7 +11,7 @@ RSpec.describe Gitlab::Tracking do described_class.instance_variable_set("@snowplow", nil) end - describe '.snowplow_options' do + describe '.options' do it 'returns useful client options' do expected_fields = { namespace: 'gl', @@ -22,13 +22,13 @@ RSpec.describe Gitlab::Tracking do linkClickTracking: true } - expect(subject.snowplow_options(nil)).to match(expected_fields) + expect(subject.options(nil)).to match(expected_fields) end it 'when feature flag is disabled' do stub_feature_flags(additional_snowplow_tracking: false) - expect(subject.snowplow_options(nil)).to include( + expect(subject.options(nil)).to include( formTracking: false, linkClickTracking: false ) diff --git a/spec/requests/rack_attack_global_spec.rb b/spec/requests/rack_attack_global_spec.rb index 32fa1381869..046b0246636 100644 --- a/spec/requests/rack_attack_global_spec.rb +++ b/spec/requests/rack_attack_global_spec.rb @@ -24,7 +24,11 @@ RSpec.describe 'Rack Attack global throttles', :use_clean_rails_memory_store_cac throttle_authenticated_packages_api_requests_per_period: 100, throttle_authenticated_packages_api_period_in_seconds: 1, throttle_authenticated_git_lfs_requests_per_period: 100, - throttle_authenticated_git_lfs_period_in_seconds: 1 + throttle_authenticated_git_lfs_period_in_seconds: 1, + throttle_unauthenticated_files_api_requests_per_period: 100, + throttle_unauthenticated_files_api_period_in_seconds: 1, + throttle_authenticated_files_api_requests_per_period: 100, + throttle_authenticated_files_api_period_in_seconds: 1 } end @@ -711,6 +715,212 @@ RSpec.describe 'Rack Attack global throttles', :use_clean_rails_memory_store_cac end end + describe 'Files API' do + let(:request_method) { 'GET' } + + context 'unauthenticated' do + let_it_be(:project) { create(:project, :public, :custom_repo, files: { 'README' => 'foo' }) } + + let(:throttle_setting_prefix) { 'throttle_unauthenticated_files_api' } + let(:files_path_that_does_not_require_authentication) { "/api/v4/projects/#{project.id}/repository/files/README?ref=master" } + + def do_request + get files_path_that_does_not_require_authentication + end + + before do + settings_to_set[:throttle_unauthenticated_files_api_requests_per_period] = requests_per_period + settings_to_set[:throttle_unauthenticated_files_api_period_in_seconds] = period_in_seconds + end + + context 'when unauthenticated files api throttle is disabled' do + before do + settings_to_set[:throttle_unauthenticated_files_api_enabled] = false + stub_application_setting(settings_to_set) + end + + it 'allows requests over the rate limit' do + (1 + requests_per_period).times do + do_request + expect(response).to have_gitlab_http_status(:ok) + end + end + + context 'when unauthenticated api throttle is enabled' do + before do + settings_to_set[:throttle_unauthenticated_requests_per_period] = requests_per_period + settings_to_set[:throttle_unauthenticated_period_in_seconds] = period_in_seconds + settings_to_set[:throttle_unauthenticated_enabled] = true + stub_application_setting(settings_to_set) + end + + it 'rejects requests over the unauthenticated api rate limit' do + requests_per_period.times do + do_request + expect(response).to have_gitlab_http_status(:ok) + end + + expect_rejection { do_request } + end + end + end + + context 'when unauthenticated files api throttle is enabled' do + before do + settings_to_set[:throttle_unauthenticated_files_api_requests_per_period] = requests_per_period # 1 + settings_to_set[:throttle_unauthenticated_files_api_period_in_seconds] = period_in_seconds # 10_000 + settings_to_set[:throttle_unauthenticated_files_api_enabled] = true + stub_application_setting(settings_to_set) + end + + it 'rejects requests over the rate limit' do + requests_per_period.times do + do_request + expect(response).to have_gitlab_http_status(:ok) + end + + expect_rejection { do_request } + end + + context 'when feature flag is off' do + before do + stub_feature_flags(files_api_throttling: false) + end + + it 'allows requests over the rate limit' do + (1 + requests_per_period).times do + do_request + expect(response).to have_gitlab_http_status(:ok) + end + end + end + + context 'when unauthenticated api throttle is lower' do + before do + settings_to_set[:throttle_unauthenticated_requests_per_period] = 0 + settings_to_set[:throttle_unauthenticated_period_in_seconds] = period_in_seconds + settings_to_set[:throttle_unauthenticated_enabled] = true + stub_application_setting(settings_to_set) + end + + it 'ignores unauthenticated api throttle' do + requests_per_period.times do + do_request + expect(response).to have_gitlab_http_status(:ok) + end + + expect_rejection { do_request } + end + end + + it_behaves_like 'tracking when dry-run mode is set' do + let(:throttle_name) { 'throttle_unauthenticated_files_api' } + end + end + end + + context 'authenticated', :api do + let_it_be(:project) { create(:project, :internal, :custom_repo, files: { 'README' => 'foo' }) } + let_it_be(:user) { create(:user) } + let_it_be(:token) { create(:personal_access_token, user: user) } + let_it_be(:other_user) { create(:user) } + let_it_be(:other_user_token) { create(:personal_access_token, user: other_user) } + + let(:throttle_setting_prefix) { 'throttle_authenticated_files_api' } + let(:api_partial_url) { "/projects/#{project.id}/repository/files/README?ref=master" } + + before do + stub_application_setting(settings_to_set) + end + + context 'with the token in the query string' do + let(:request_args) { [api(api_partial_url, personal_access_token: token), {}] } + let(:other_user_request_args) { [api(api_partial_url, personal_access_token: other_user_token), {}] } + + it_behaves_like 'rate-limited token-authenticated requests' + end + + context 'with the token in the headers' do + let(:request_args) { api_get_args_with_token_headers(api_partial_url, personal_access_token_headers(token)) } + let(:other_user_request_args) { api_get_args_with_token_headers(api_partial_url, personal_access_token_headers(other_user_token)) } + + it_behaves_like 'rate-limited token-authenticated requests' + end + + context 'precedence over authenticated api throttle' do + before do + settings_to_set[:throttle_authenticated_files_api_requests_per_period] = requests_per_period + settings_to_set[:throttle_authenticated_files_api_period_in_seconds] = period_in_seconds + end + + def do_request + get api(api_partial_url, personal_access_token: token) + end + + context 'when authenticated files api throttle is enabled' do + before do + settings_to_set[:throttle_authenticated_files_api_enabled] = true + end + + context 'when authenticated api throttle is lower' do + before do + settings_to_set[:throttle_authenticated_api_requests_per_period] = 0 + settings_to_set[:throttle_authenticated_api_period_in_seconds] = period_in_seconds + settings_to_set[:throttle_authenticated_api_enabled] = true + stub_application_setting(settings_to_set) + end + + it 'ignores authenticated api throttle' do + requests_per_period.times do + do_request + expect(response).to have_gitlab_http_status(:ok) + end + + expect_rejection { do_request } + end + end + + context 'when feature flag is off' do + before do + stub_feature_flags(files_api_throttling: false) + end + + it 'allows requests over the rate limit' do + (1 + requests_per_period).times do + do_request + expect(response).to have_gitlab_http_status(:ok) + end + end + end + end + + context 'when authenticated files api throttle is disabled' do + before do + settings_to_set[:throttle_authenticated_files_api_enabled] = false + end + + context 'when authenticated api throttle is enabled' do + before do + settings_to_set[:throttle_authenticated_api_requests_per_period] = requests_per_period + settings_to_set[:throttle_authenticated_api_period_in_seconds] = period_in_seconds + settings_to_set[:throttle_authenticated_api_enabled] = true + stub_application_setting(settings_to_set) + end + + it 'rejects requests over the authenticated api rate limit' do + requests_per_period.times do + do_request + expect(response).to have_gitlab_http_status(:ok) + end + + expect_rejection { do_request } + end + end + end + end + end + end + describe 'throttle bypass header' do let(:headers) { {} } let(:bypass_header) { 'gitlab-bypass-rate-limiting' } diff --git a/spec/support/shared_examples/requests/rack_attack_shared_examples.rb b/spec/support/shared_examples/requests/rack_attack_shared_examples.rb index 9d87a231bfa..8ddd2d900de 100644 --- a/spec/support/shared_examples/requests/rack_attack_shared_examples.rb +++ b/spec/support/shared_examples/requests/rack_attack_shared_examples.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true # # Requires let variables: -# * throttle_setting_prefix: "throttle_authenticated_api", "throttle_authenticated_web", "throttle_protected_paths", "throttle_authenticated_packages_api", "throttle_authenticated_git_lfs" +# * throttle_setting_prefix: "throttle_authenticated_api", "throttle_authenticated_web", "throttle_protected_paths", "throttle_authenticated_packages_api", "throttle_authenticated_git_lfs", "throttle_authenticated_files_api" # * request_method # * request_args # * other_user_request_args @@ -15,7 +15,8 @@ RSpec.shared_examples 'rate-limited token-authenticated requests' do "throttle_authenticated_api" => "throttle_authenticated_api", "throttle_authenticated_web" => "throttle_authenticated_web", "throttle_authenticated_packages_api" => "throttle_authenticated_packages_api", - "throttle_authenticated_git_lfs" => "throttle_authenticated_git_lfs" + "throttle_authenticated_git_lfs" => "throttle_authenticated_git_lfs", + "throttle_authenticated_files_api" => "throttle_authenticated_files_api" } end diff --git a/spec/workers/background_migration_worker_spec.rb b/spec/workers/background_migration_worker_spec.rb index 4575c270042..7892eb89e80 100644 --- a/spec/workers/background_migration_worker_spec.rb +++ b/spec/workers/background_migration_worker_spec.rb @@ -14,7 +14,17 @@ RSpec.describe BackgroundMigrationWorker, :clean_gitlab_redis_shared_state do describe '#perform' do before do allow(worker).to receive(:jid).and_return(1) - expect(worker).to receive(:always_perform?).and_return(false) + allow(worker).to receive(:always_perform?).and_return(false) + end + + it 'can run scheduled job and retried job concurrently' do + expect(Gitlab::BackgroundMigration) + .to receive(:perform) + .with('Foo', [10, 20]) + .exactly(2).time + + worker.perform('Foo', [10, 20]) + worker.perform('Foo', [10, 20], described_class::MAX_LEASE_ATTEMPTS - 1) end context 'when lease can be obtained' do @@ -39,7 +49,7 @@ RSpec.describe BackgroundMigrationWorker, :clean_gitlab_redis_shared_state do before do expect(Gitlab::BackgroundMigration).not_to receive(:perform) - worker.lease_for('Foo').try_obtain + worker.lease_for('Foo', false).try_obtain end it 'reschedules the migration and decrements the lease_attempts' do @@ -51,6 +61,10 @@ RSpec.describe BackgroundMigrationWorker, :clean_gitlab_redis_shared_state do end context 'when lease_attempts is 1' do + before do + worker.lease_for('Foo', true).try_obtain + end + it 'reschedules the migration and decrements the lease_attempts' do expect(described_class) .to receive(:perform_in) @@ -61,6 +75,10 @@ RSpec.describe BackgroundMigrationWorker, :clean_gitlab_redis_shared_state do end context 'when lease_attempts is 0' do + before do + worker.lease_for('Foo', true).try_obtain + end + it 'gives up performing the migration' do expect(described_class).not_to receive(:perform_in) expect(Sidekiq.logger).to receive(:warn).with( |