Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2022-02-01 15:17:55 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2022-02-01 15:17:55 +0300
commit1ae73e5bfcb2dc4a49f40886f729fc4797ba2a65 (patch)
tree03cb6dac129fb29c9500651a051d1f61966d79b8 /spec
parent719524126026437133586ce042dfc48c0d166ecd (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r--spec/features/projects/blobs/blob_show_spec.rb1583
-rw-r--r--spec/frontend/__helpers__/matchers/to_match_interpolated_text.js15
-rw-r--r--spec/frontend/blob/components/__snapshots__/blob_header_spec.js.snap1
-rw-r--r--spec/frontend/environments/environment_pin_spec.js74
-rw-r--r--spec/frontend/environments/graphql/resolvers_spec.js4
-rw-r--r--spec/frontend/environments/new_environment_item_spec.js12
-rw-r--r--spec/frontend/repository/components/blob_content_viewer_spec.js2
-rw-r--r--spec/frontend/repository/components/blob_viewers/lfs_viewer_spec.js41
-rw-r--r--spec/frontend/repository/mock_data.js1
-rw-r--r--spec/helpers/projects_helper_spec.rb8
-rw-r--r--spec/lib/gitlab/rack_attack/request_spec.rb181
-rw-r--r--spec/lib/gitlab/usage_data_spec.rb4
-rw-r--r--spec/models/merge_request_spec.rb2
-rw-r--r--spec/requests/rack_attack_global_spec.rb15
-rw-r--r--spec/rubocop/cop/sidekiq_load_balancing/worker_data_consistency_with_deduplication_spec.rb166
-rw-r--r--spec/serializers/test_case_entity_spec.rb12
-rw-r--r--spec/services/environments/stop_service_spec.rb8
17 files changed, 1129 insertions, 1000 deletions
diff --git a/spec/features/projects/blobs/blob_show_spec.rb b/spec/features/projects/blobs/blob_show_spec.rb
index 988051bca40..c8cbf396098 100644
--- a/spec/features/projects/blobs/blob_show_spec.rb
+++ b/spec/features/projects/blobs/blob_show_spec.rb
@@ -29,443 +29,421 @@ RSpec.describe 'File blob', :js do
).execute
end
- before do
- stub_feature_flags(refactor_blob_viewer: false) # This stub will be removed in https://gitlab.com/gitlab-org/gitlab/-/issues/350455
- end
-
- context 'Ruby file' do
- before do
- visit_blob('files/ruby/popen.rb')
-
- wait_for_requests
- end
-
- it 'displays the blob' do
- aggregate_failures do
- # shows highlighted Ruby code
- expect(page).to have_css(".js-syntax-highlight")
- expect(page).to have_content("require 'fileutils'")
-
- # does not show a viewer switcher
- expect(page).not_to have_selector('.js-blob-viewer-switcher')
-
- # shows an enabled copy button
- expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)')
-
- # shows a raw button
- expect(page).to have_link('Open raw')
- end
- end
-
- it 'displays file actions on all screen sizes' do
- file_actions_selector = '.file-actions'
-
- resize_screen_sm
- expect(page).to have_selector(file_actions_selector, visible: true)
-
- resize_screen_xs
- expect(page).to have_selector(file_actions_selector, visible: true)
- end
- end
-
- context 'Markdown file' do
- context 'visiting directly' do
+ context 'with refactor_blob_viewer feature flag enabled' do
+ context 'Ruby file' do
before do
- visit_blob('files/markdown/ruby-style-guide.md')
+ visit_blob('files/ruby/popen.rb')
wait_for_requests
end
- it 'displays the blob using the rich viewer' do
+ it 'displays the blob' do
aggregate_failures do
- # hides the simple viewer
- expect(page).to have_selector('.blob-viewer[data-type="simple"]', visible: false)
- expect(page).to have_selector('.blob-viewer[data-type="rich"]')
-
- # shows rendered Markdown
- expect(page).to have_link("PEP-8")
+ # shows highlighted Ruby code
+ expect(page).to have_css(".js-syntax-highlight")
+ expect(page).to have_content("require 'fileutils'")
- # shows a viewer switcher
- expect(page).to have_selector('.js-blob-viewer-switcher')
+ # does not show a viewer switcher
+ expect(page).not_to have_selector('.js-blob-viewer-switcher')
- # shows a disabled copy button
- expect(page).to have_selector('.js-copy-blob-source-btn.disabled')
+ # shows an enabled copy button
+ expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)')
# shows a raw button
expect(page).to have_link('Open raw')
end
end
- context 'switching to the simple viewer' do
+ it 'displays file actions on all screen sizes' do
+ file_actions_selector = '.file-actions'
+
+ resize_screen_sm
+ expect(page).to have_selector(file_actions_selector, visible: true)
+
+ resize_screen_xs
+ expect(page).to have_selector(file_actions_selector, visible: true)
+ end
+ end
+
+ context 'Markdown file' do
+ context 'visiting directly' do
before do
- find('.js-blob-viewer-switch-btn[data-viewer=simple]').click
+ visit_blob('files/markdown/ruby-style-guide.md')
wait_for_requests
end
- it 'displays the blob using the simple viewer' do
+ it 'displays the blob using the rich viewer' do
aggregate_failures do
- # hides the rich viewer
- expect(page).to have_selector('.blob-viewer[data-type="simple"]')
- expect(page).to have_selector('.blob-viewer[data-type="rich"]', visible: false)
+ # hides the simple viewer
+ expect(page).not_to have_selector('.blob-viewer[data-type="simple"]')
+ expect(page).to have_selector('.blob-viewer[data-type="rich"]')
- # shows highlighted Markdown code
- expect(page).to have_css(".js-syntax-highlight")
- expect(page).to have_content("[PEP-8](http://www.python.org/dev/peps/pep-0008/)")
+ # shows rendered Markdown
+ expect(page).to have_link("PEP-8")
- # shows an enabled copy button
- expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)')
+ # shows a viewer switcher
+ expect(page).to have_selector('.js-blob-viewer-switcher')
+
+ # shows a disabled copy button
+ expect(page).to have_selector('.js-copy-blob-source-btn.disabled')
+
+ # shows a raw button
+ expect(page).to have_link('Open raw')
end
end
- context 'switching to the rich viewer again' do
+ context 'switching to the simple viewer' do
before do
- find('.js-blob-viewer-switch-btn[data-viewer=rich]').click
+ find('.js-blob-viewer-switch-btn[data-viewer=simple]').click
wait_for_requests
end
- it 'displays the blob using the rich viewer' do
+ it 'displays the blob using the simple viewer' do
aggregate_failures do
- # hides the simple viewer
- expect(page).to have_selector('.blob-viewer[data-type="simple"]', visible: false)
- expect(page).to have_selector('.blob-viewer[data-type="rich"]')
+ # hides the rich viewer
+ expect(page).to have_selector('.blob-viewer[data-type="simple"]')
+ expect(page).not_to have_selector('.blob-viewer[data-type="rich"]')
+
+ # shows highlighted Markdown code
+ expect(page).to have_css(".js-syntax-highlight")
+ expect(page).to have_content("[PEP-8](http://www.python.org/dev/peps/pep-0008/)")
# shows an enabled copy button
expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)')
end
end
- end
- end
- end
- context 'when ref switch' do
- def switch_ref_to(ref_name)
- first('.qa-branches-select').click # rubocop:disable QA/SelectorUsage
-
- page.within '.project-refs-form' do
- click_link ref_name
- wait_for_requests
- end
- end
+ context 'switching to the rich viewer again' do
+ before do
+ find('.js-blob-viewer-switch-btn[data-viewer=rich]').click
- it 'displays single highlighted line number of different ref' do
- visit_blob('files/js/application.js', anchor: 'L1')
+ wait_for_requests
+ end
- switch_ref_to('feature')
+ it 'displays the blob using the rich viewer' do
+ aggregate_failures do
+ # hides the simple viewer
+ expect(page).not_to have_selector('.blob-viewer[data-type="simple"]')
+ expect(page).to have_selector('.blob-viewer[data-type="rich"]')
- page.within '.blob-content' do
- expect(find_by_id('LC1')[:class]).to include("hll")
+ # shows a disabled copy button
+ expect(page).to have_selector('.js-copy-blob-source-btn.disabled')
+ end
+ end
+ end
end
end
- it 'displays multiple highlighted line numbers of different ref' do
- visit_blob('files/js/application.js', anchor: 'L1-3')
+ context 'when ref switch' do
+ def switch_ref_to(ref_name)
+ first('.qa-branches-select').click # rubocop:disable QA/SelectorUsage
- switch_ref_to('feature')
-
- page.within '.blob-content' do
- expect(find_by_id('LC1')[:class]).to include("hll")
- expect(find_by_id('LC2')[:class]).to include("hll")
- expect(find_by_id('LC3')[:class]).to include("hll")
+ page.within '.project-refs-form' do
+ click_link ref_name
+ wait_for_requests
+ end
end
- end
- it 'displays no highlighted number of different ref' do
- Files::UpdateService.new(
- project,
- project.first_owner,
- commit_message: 'Update',
- start_branch: 'feature',
- branch_name: 'feature',
- file_path: 'files/js/application.js',
- file_content: 'new content'
- ).execute
+ it 'displays no highlighted number of different ref' do
+ Files::UpdateService.new(
+ project,
+ project.first_owner,
+ commit_message: 'Update',
+ start_branch: 'feature',
+ branch_name: 'feature',
+ file_path: 'files/js/application.js',
+ file_content: 'new content'
+ ).execute
- project.commit('feature').diffs.diff_files.first
+ project.commit('feature').diffs.diff_files.first
- visit_blob('files/js/application.js', anchor: 'L3')
- switch_ref_to('feature')
+ visit_blob('files/js/application.js', anchor: 'L3')
+ switch_ref_to('feature')
- page.within '.blob-content' do
- expect(page).not_to have_css('.hll')
+ page.within '.blob-content' do
+ expect(page).not_to have_css('.hll')
+ end
end
- end
- context 'successfully change ref of similar name' do
- before do
- project.repository.create_branch('dev')
- project.repository.create_branch('development')
- end
+ context 'successfully change ref of similar name' do
+ before do
+ project.repository.create_branch('dev')
+ project.repository.create_branch('development')
+ end
- it 'switch ref from longer to shorter ref name' do
- visit_blob('files/js/application.js', ref: 'development')
- switch_ref_to('dev')
+ it 'switch ref from longer to shorter ref name' do
+ visit_blob('files/js/application.js', ref: 'development')
+ switch_ref_to('dev')
- aggregate_failures do
- expect(page.find('.file-title-name').text).to eq('application.js')
- expect(page).not_to have_css('flash-container')
+ aggregate_failures do
+ expect(page.find('.file-title-name').text).to eq('application.js')
+ expect(page).not_to have_css('flash-container')
+ end
end
- end
- it 'switch ref from shorter to longer ref name' do
- visit_blob('files/js/application.js', ref: 'dev')
- switch_ref_to('development')
+ it 'switch ref from shorter to longer ref name' do
+ visit_blob('files/js/application.js', ref: 'dev')
+ switch_ref_to('development')
- aggregate_failures do
- expect(page.find('.file-title-name').text).to eq('application.js')
- expect(page).not_to have_css('flash-container')
+ aggregate_failures do
+ expect(page.find('.file-title-name').text).to eq('application.js')
+ expect(page).not_to have_css('flash-container')
+ end
end
end
- end
- it 'successfully changes ref when the ref name matches the project name' do
- project.repository.create_branch(project.name)
+ it 'successfully changes ref when the ref name matches the project name' do
+ project.repository.create_branch(project.name)
- visit_blob('files/js/application.js', ref: project.name)
- switch_ref_to('master')
+ visit_blob('files/js/application.js', ref: project.name)
+ switch_ref_to('master')
- aggregate_failures do
- expect(page.find('.file-title-name').text).to eq('application.js')
- expect(page).not_to have_css('flash-container')
+ aggregate_failures do
+ expect(page.find('.file-title-name').text).to eq('application.js')
+ expect(page).not_to have_css('flash-container')
+ end
end
end
end
- context 'visiting with a line number anchor' do
+ context 'Markdown rendering' do
before do
- visit_blob('files/markdown/ruby-style-guide.md', anchor: 'L1')
- end
+ project.add_maintainer(project.creator)
- it 'displays the blob using the simple viewer' do
- aggregate_failures do
- # hides the rich viewer
- expect(page).to have_selector('.blob-viewer[data-type="simple"]')
- expect(page).to have_selector('.blob-viewer[data-type="rich"]', visible: false)
+ Files::CreateService.new(
+ project,
+ project.creator,
+ start_branch: 'master',
+ branch_name: 'master',
+ commit_message: "Add RedCarpet and CommonMark Markdown ",
+ file_path: 'files/commonmark/file.md',
+ file_content: "1. one\n - sublist\n"
+ ).execute
+ end
- # highlights the line in question
- expect(page).to have_selector('#LC1.hll')
+ context 'when rendering default markdown' do
+ before do
+ visit_blob('files/commonmark/file.md')
- # shows highlighted Markdown code
- expect(page).to have_css(".js-syntax-highlight")
- expect(page).to have_content("[PEP-8](http://www.python.org/dev/peps/pep-0008/)")
+ wait_for_requests
+ end
- # shows an enabled copy button
- expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)')
+ it 'renders using CommonMark' do
+ aggregate_failures do
+ expect(page).to have_content("sublist")
+ expect(page).not_to have_xpath("//ol//li//ul")
+ end
end
end
end
- end
-
- context 'Markdown rendering' do
- before do
- project.add_maintainer(project.creator)
-
- Files::CreateService.new(
- project,
- project.creator,
- start_branch: 'master',
- branch_name: 'master',
- commit_message: "Add RedCarpet and CommonMark Markdown ",
- file_path: 'files/commonmark/file.md',
- file_content: "1. one\n - sublist\n"
- ).execute
- end
- context 'when rendering default markdown' do
+ context 'Markdown file (stored in LFS)' do
before do
- visit_blob('files/commonmark/file.md')
-
- wait_for_requests
- end
+ project.add_maintainer(project.creator)
- it 'renders using CommonMark' do
- aggregate_failures do
- expect(page).to have_content("sublist")
- expect(page).not_to have_xpath("//ol//li//ul")
- end
+ Files::CreateService.new(
+ project,
+ project.creator,
+ start_branch: 'master',
+ branch_name: 'master',
+ commit_message: "Add Markdown in LFS",
+ file_path: 'files/lfs/file.md',
+ file_content: project.repository.blob_at('master', 'files/lfs/lfs_object.iso').data
+ ).execute
end
- end
- end
- context 'Markdown file (stored in LFS)' do
- before do
- project.add_maintainer(project.creator)
-
- Files::CreateService.new(
- project,
- project.creator,
- start_branch: 'master',
- branch_name: 'master',
- commit_message: "Add Markdown in LFS",
- file_path: 'files/lfs/file.md',
- file_content: project.repository.blob_at('master', 'files/lfs/lfs_object.iso').data
- ).execute
- end
-
- context 'when LFS is enabled on the project' do
- before do
- allow(Gitlab.config.lfs).to receive(:enabled).and_return(true)
- project.update_attribute(:lfs_enabled, true)
+ context 'when LFS is enabled on the project' do
+ before do
+ allow(Gitlab.config.lfs).to receive(:enabled).and_return(true)
+ project.update_attribute(:lfs_enabled, true)
- visit_blob('files/lfs/file.md')
+ visit_blob('files/lfs/file.md')
- wait_for_requests
- end
+ wait_for_requests
+ end
- it 'displays an error' do
- aggregate_failures do
- # hides the simple viewer
- expect(page).to have_selector('.blob-viewer[data-type="simple"]', visible: false)
- expect(page).to have_selector('.blob-viewer[data-type="rich"]')
+ it 'displays an error' do
+ aggregate_failures do
+ # hides the simple viewer
+ expect(page).not_to have_selector('.blob-viewer[data-type="simple"]')
+ expect(page).not_to have_selector('.blob-viewer[data-type="rich"]')
- # shows an error message
- expect(page).to have_content('The rendered file could not be displayed because it is stored in LFS. You can download it instead.')
+ # shows an error message
+ expect(page).to have_content('This content could not be displayed because it is stored in LFS. You can download it instead.')
- # shows a viewer switcher
- expect(page).to have_selector('.js-blob-viewer-switcher')
+ # does not show a viewer switcher
+ expect(page).not_to have_selector('.js-blob-viewer-switcher')
- # does not show a copy button
- expect(page).not_to have_selector('.js-copy-blob-source-btn')
+ # does not show a copy button
+ expect(page).not_to have_selector('.js-copy-blob-source-btn')
- # shows a download button
- expect(page).to have_link('Download')
+ # shows a download button
+ expect(page).to have_link('Download')
+ end
end
end
- context 'switching to the simple viewer' do
+ context 'when LFS is disabled on the project' do
before do
- find('.js-blob-viewer-switcher .js-blob-viewer-switch-btn[data-viewer=simple]').click
+ visit_blob('files/lfs/file.md')
wait_for_requests
end
- it 'displays an error' do
+ it 'displays the blob' do
aggregate_failures do
- # hides the rich viewer
- expect(page).to have_selector('.blob-viewer[data-type="simple"]')
- expect(page).to have_selector('.blob-viewer[data-type="rich"]', visible: false)
+ # shows text
+ expect(page).to have_content('size 1575078')
- # shows an error message
- expect(page).to have_content('The source could not be displayed because it is stored in LFS. You can download it instead.')
+ # does not show a viewer switcher
+ expect(page).not_to have_selector('.js-blob-viewer-switcher')
- # does not show a copy button
- expect(page).not_to have_selector('.js-copy-blob-source-btn')
+ # shows an enabled copy button
+ expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)')
+
+ # shows a raw button
+ expect(page).to have_link('Open raw')
end
end
end
end
- context 'when LFS is disabled on the project' do
+ context 'PDF file' do
before do
- visit_blob('files/lfs/file.md')
+ project.add_maintainer(project.creator)
+
+ Files::CreateService.new(
+ project,
+ project.creator,
+ start_branch: 'master',
+ branch_name: 'master',
+ commit_message: "Add PDF",
+ file_path: 'files/test.pdf',
+ file_content: project.repository.blob_at('add-pdf-file', 'files/pdf/test.pdf').data
+ ).execute
+
+ visit_blob('files/test.pdf')
wait_for_requests
end
it 'displays the blob' do
aggregate_failures do
- # shows text
- expect(page).to have_content('size 1575078')
+ # shows rendered PDF
+ expect(page).to have_selector('.js-pdf-viewer')
# does not show a viewer switcher
expect(page).not_to have_selector('.js-blob-viewer-switcher')
- # shows an enabled copy button
- expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)')
+ # does not show a copy button
+ expect(page).not_to have_selector('.js-copy-blob-source-btn')
- # shows a raw button
- expect(page).to have_link('Open raw')
+ # shows a download button
+ expect(page).to have_link('Download')
end
end
end
- end
- context 'PDF file' do
- before do
- project.add_maintainer(project.creator)
+ context 'Jupiter Notebook file' do
+ before do
+ project.add_maintainer(project.creator)
- Files::CreateService.new(
- project,
- project.creator,
- start_branch: 'master',
- branch_name: 'master',
- commit_message: "Add PDF",
- file_path: 'files/test.pdf',
- file_content: project.repository.blob_at('add-pdf-file', 'files/pdf/test.pdf').data
- ).execute
+ Files::CreateService.new(
+ project,
+ project.creator,
+ start_branch: 'master',
+ branch_name: 'master',
+ commit_message: "Add Jupiter Notebook",
+ file_path: 'files/basic.ipynb',
+ file_content: project.repository.blob_at('add-ipython-files', 'files/ipython/basic.ipynb').data
+ ).execute
- visit_blob('files/test.pdf')
+ visit_blob('files/basic.ipynb')
- wait_for_requests
- end
+ wait_for_requests
+ end
- it 'displays the blob' do
- aggregate_failures do
- # shows rendered PDF
- expect(page).to have_selector('.js-pdf-viewer')
+ it 'displays the blob' do
+ aggregate_failures do
+ # shows rendered notebook
+ expect(page).to have_selector('.js-notebook-viewer-mounted')
+
+ # does show a viewer switcher
+ expect(page).to have_selector('.js-blob-viewer-switcher')
+
+ # show a disabled copy button
+ expect(page).to have_selector('.js-copy-blob-source-btn.disabled')
- # does not show a viewer switcher
- expect(page).not_to have_selector('.js-blob-viewer-switcher')
+ # shows a raw button
+ expect(page).to have_link('Open raw')
- # does not show a copy button
- expect(page).not_to have_selector('.js-copy-blob-source-btn')
+ # shows a download button
+ expect(page).to have_link('Download')
- # shows a download button
- expect(page).to have_link('Download')
+ # shows the rendered notebook
+ expect(page).to have_content('test')
+ end
end
end
- end
- context 'Jupiter Notebook file' do
- before do
- project.add_maintainer(project.creator)
+ context 'ISO file (stored in LFS)' do
+ context 'when LFS is enabled on the project' do
+ before do
+ allow(Gitlab.config.lfs).to receive(:enabled).and_return(true)
+ project.update_attribute(:lfs_enabled, true)
- Files::CreateService.new(
- project,
- project.creator,
- start_branch: 'master',
- branch_name: 'master',
- commit_message: "Add Jupiter Notebook",
- file_path: 'files/basic.ipynb',
- file_content: project.repository.blob_at('add-ipython-files', 'files/ipython/basic.ipynb').data
- ).execute
+ visit_blob('files/lfs/lfs_object.iso')
- visit_blob('files/basic.ipynb')
+ wait_for_requests
+ end
- wait_for_requests
- end
+ it 'displays the blob' do
+ aggregate_failures do
+ # shows a download link
+ expect(page).to have_link('Download (1.50 MiB)')
+
+ # does not show a viewer switcher
+ expect(page).not_to have_selector('.js-blob-viewer-switcher')
+
+ # does not show a copy button
+ expect(page).not_to have_selector('.js-copy-blob-source-btn')
+
+ # shows a download button
+ expect(page).to have_link('Download')
+ end
+ end
+ end
- it 'displays the blob' do
- aggregate_failures do
- # shows rendered notebook
- expect(page).to have_selector('.js-notebook-viewer-mounted')
+ context 'when LFS is disabled on the project' do
+ before do
+ visit_blob('files/lfs/lfs_object.iso')
- # does show a viewer switcher
- expect(page).to have_selector('.js-blob-viewer-switcher')
+ wait_for_requests
+ end
- # show a disabled copy button
- expect(page).to have_selector('.js-copy-blob-source-btn.disabled')
+ it 'displays the blob' do
+ aggregate_failures do
+ # shows text
+ expect(page).to have_content('size 1575078')
- # shows a raw button
- expect(page).to have_link('Open raw')
+ # does not show a viewer switcher
+ expect(page).not_to have_selector('.js-blob-viewer-switcher')
- # shows a download button
- expect(page).to have_link('Download')
+ # shows an enabled copy button
+ expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)')
- # shows the rendered notebook
- expect(page).to have_content('test')
+ # shows a raw button
+ expect(page).to have_link('Open raw')
+ end
+ end
end
end
- end
- context 'ISO file (stored in LFS)' do
- context 'when LFS is enabled on the project' do
+ context 'ZIP file' do
before do
- allow(Gitlab.config.lfs).to receive(:enabled).and_return(true)
- project.update_attribute(:lfs_enabled, true)
-
- visit_blob('files/lfs/lfs_object.iso')
+ visit_blob('Gemfile.zip')
wait_for_requests
end
@@ -473,7 +451,7 @@ RSpec.describe 'File blob', :js do
it 'displays the blob' do
aggregate_failures do
# shows a download link
- expect(page).to have_link('Download (1.5 MB)')
+ expect(page).to have_link('Download (2.11 KiB)')
# does not show a viewer switcher
expect(page).not_to have_selector('.js-blob-viewer-switcher')
@@ -487,578 +465,703 @@ RSpec.describe 'File blob', :js do
end
end
- context 'when LFS is disabled on the project' do
+ context 'empty file' do
before do
- visit_blob('files/lfs/lfs_object.iso')
+ project.add_maintainer(project.creator)
+
+ Files::CreateService.new(
+ project,
+ project.creator,
+ start_branch: 'master',
+ branch_name: 'master',
+ commit_message: "Add empty file",
+ file_path: 'files/empty.md',
+ file_content: ''
+ ).execute
+
+ visit_blob('files/empty.md')
wait_for_requests
end
- it 'displays the blob' do
+ it 'displays an error' do
aggregate_failures do
- # shows text
- expect(page).to have_content('size 1575078')
+ # shows an error message
+ expect(page).to have_content('Empty file')
# does not show a viewer switcher
expect(page).not_to have_selector('.js-blob-viewer-switcher')
- # shows an enabled copy button
- expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)')
+ # does not show a copy button
+ expect(page).not_to have_selector('.js-copy-blob-source-btn')
- # shows a raw button
- expect(page).to have_link('Open raw')
+ # does not show a download or raw button
+ expect(page).not_to have_link('Download')
+ expect(page).not_to have_link('Open raw')
end
end
end
- end
-
- context 'ZIP file' do
- before do
- visit_blob('Gemfile.zip')
- wait_for_requests
- end
+ context 'files with auxiliary viewers' do
+ describe '.gitlab-ci.yml' do
+ before do
+ project.add_maintainer(project.creator)
- it 'displays the blob' do
- aggregate_failures do
- # shows a download link
- expect(page).to have_link('Download (2.11 KB)')
+ Files::CreateService.new(
+ project,
+ project.creator,
+ start_branch: 'master',
+ branch_name: 'master',
+ commit_message: "Add .gitlab-ci.yml",
+ file_path: '.gitlab-ci.yml',
+ file_content: File.read(Rails.root.join('spec/support/gitlab_stubs/gitlab_ci.yml'))
+ ).execute
- # does not show a viewer switcher
- expect(page).not_to have_selector('.js-blob-viewer-switcher')
+ visit_blob('.gitlab-ci.yml')
+ end
- # does not show a copy button
- expect(page).not_to have_selector('.js-copy-blob-source-btn')
+ it 'displays an auxiliary viewer' do
+ aggregate_failures do
+ # shows that configuration is valid
+ expect(page).to have_content('This GitLab CI configuration is valid.')
- # shows a download button
- expect(page).to have_link('Download')
+ # shows a learn more link
+ expect(page).to have_link('Learn more')
+ end
+ end
end
- end
- end
- context 'empty file' do
- before do
- project.add_maintainer(project.creator)
+ describe '.gitlab/route-map.yml' do
+ before do
+ project.add_maintainer(project.creator)
+
+ Files::CreateService.new(
+ project,
+ project.creator,
+ start_branch: 'master',
+ branch_name: 'master',
+ commit_message: "Add .gitlab/route-map.yml",
+ file_path: '.gitlab/route-map.yml',
+ file_content: <<-MAP.strip_heredoc
+ # Team data
+ - source: 'data/team.yml'
+ public: 'team/'
+ MAP
+ ).execute
- Files::CreateService.new(
- project,
- project.creator,
- start_branch: 'master',
- branch_name: 'master',
- commit_message: "Add empty file",
- file_path: 'files/empty.md',
- file_content: ''
- ).execute
+ visit_blob('.gitlab/route-map.yml')
+ end
- visit_blob('files/empty.md')
+ it 'displays an auxiliary viewer' do
+ aggregate_failures do
+ # shows that map is valid
+ expect(page).to have_content('This Route Map is valid.')
- wait_for_requests
- end
+ # shows a learn more link
+ expect(page).to have_link('Learn more')
+ end
+ end
+ end
- it 'displays an error' do
- aggregate_failures do
- # shows an error message
- expect(page).to have_content('Empty file')
+ describe '.gitlab/dashboards/custom-dashboard.yml' do
+ before do
+ project.add_maintainer(project.creator)
- # does not show a viewer switcher
- expect(page).not_to have_selector('.js-blob-viewer-switcher')
+ Files::CreateService.new(
+ project,
+ project.creator,
+ start_branch: 'master',
+ branch_name: 'master',
+ commit_message: "Add .gitlab/dashboards/custom-dashboard.yml",
+ file_path: '.gitlab/dashboards/custom-dashboard.yml',
+ file_content: file_content
+ ).execute
+ end
- # does not show a copy button
- expect(page).not_to have_selector('.js-copy-blob-source-btn')
+ context 'with metrics_dashboard_exhaustive_validations feature flag off' do
+ before do
+ stub_feature_flags(metrics_dashboard_exhaustive_validations: false)
+ visit_blob('.gitlab/dashboards/custom-dashboard.yml')
+ end
- # does not show a download or raw button
- expect(page).not_to have_link('Download')
- expect(page).not_to have_link('Open raw')
- end
- end
- end
+ context 'valid dashboard file' do
+ let(:file_content) { File.read(Rails.root.join('config/prometheus/common_metrics.yml')) }
- context 'binary file that appears to be text in the first 1024 bytes' do
- before do
- visit_blob('encoding/binary-1.bin', ref: 'binary-encoding')
- end
+ it 'displays an auxiliary viewer' do
+ aggregate_failures do
+ # shows that dashboard yaml is valid
+ expect(page).to have_content('Metrics Dashboard YAML definition is valid.')
- it 'displays the blob' do
- aggregate_failures do
- # shows a download link
- expect(page).to have_link('Download (23.8 KB)')
+ # shows a learn more link
+ expect(page).to have_link('Learn more')
+ end
+ end
+ end
- # does not show a viewer switcher
- expect(page).not_to have_selector('.js-blob-viewer-switcher')
+ context 'invalid dashboard file' do
+ let(:file_content) { "dashboard: 'invalid'" }
- # The specs below verify an arguably incorrect result, but since we only
- # learn that the file is not actually text once the text viewer content
- # is loaded asynchronously, there is no straightforward way to get these
- # synchronously loaded elements to display correctly.
- #
- # Clicking the copy button will result in nothing being copied.
- # Clicking the raw button will result in the binary file being downloaded,
- # as expected.
+ it 'displays an auxiliary viewer' do
+ aggregate_failures do
+ # shows that dashboard yaml is invalid
+ expect(page).to have_content('Metrics Dashboard YAML definition is invalid:')
+ expect(page).to have_content("panel_groups: should be an array of panel_groups objects")
- # shows an enabled copy button, incorrectly
- expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)')
+ # shows a learn more link
+ expect(page).to have_link('Learn more')
+ end
+ end
+ end
+ end
- # shows a raw button, incorrectly
- expect(page).to have_link('Open raw')
- end
- end
- end
+ context 'with metrics_dashboard_exhaustive_validations feature flag on' do
+ before do
+ stub_feature_flags(metrics_dashboard_exhaustive_validations: true)
+ visit_blob('.gitlab/dashboards/custom-dashboard.yml')
+ end
- context 'files with auxiliary viewers' do
- before do
- stub_feature_flags(refactor_blob_viewer: true)
- end
+ context 'valid dashboard file' do
+ let(:file_content) { File.read(Rails.root.join('config/prometheus/common_metrics.yml')) }
- describe '.gitlab-ci.yml' do
- before do
- project.add_maintainer(project.creator)
+ it 'displays an auxiliary viewer' do
+ aggregate_failures do
+ # shows that dashboard yaml is valid
+ expect(page).to have_content('Metrics Dashboard YAML definition is valid.')
- Files::CreateService.new(
- project,
- project.creator,
- start_branch: 'master',
- branch_name: 'master',
- commit_message: "Add .gitlab-ci.yml",
- file_path: '.gitlab-ci.yml',
- file_content: File.read(Rails.root.join('spec/support/gitlab_stubs/gitlab_ci.yml'))
- ).execute
+ # shows a learn more link
+ expect(page).to have_link('Learn more')
+ end
+ end
+ end
- visit_blob('.gitlab-ci.yml')
- end
+ context 'invalid dashboard file' do
+ let(:file_content) { "dashboard: 'invalid'" }
- it 'displays an auxiliary viewer' do
- aggregate_failures do
- # shows that configuration is valid
- expect(page).to have_content('This GitLab CI configuration is valid.')
+ it 'displays an auxiliary viewer' do
+ aggregate_failures do
+ # shows that dashboard yaml is invalid
+ expect(page).to have_content('Metrics Dashboard YAML definition is invalid:')
+ expect(page).to have_content("root is missing required keys: panel_groups")
- # shows a learn more link
- expect(page).to have_link('Learn more')
+ # shows a learn more link
+ expect(page).to have_link('Learn more')
+ end
+ end
+ end
end
end
- end
- describe '.gitlab/route-map.yml' do
- before do
- project.add_maintainer(project.creator)
+ context 'LICENSE' do
+ before do
+ visit_blob('LICENSE')
+ end
- Files::CreateService.new(
- project,
- project.creator,
- start_branch: 'master',
- branch_name: 'master',
- commit_message: "Add .gitlab/route-map.yml",
- file_path: '.gitlab/route-map.yml',
- file_content: <<-MAP.strip_heredoc
- # Team data
- - source: 'data/team.yml'
- public: 'team/'
- MAP
- ).execute
+ it 'displays an auxiliary viewer' do
+ aggregate_failures do
+ # shows license
+ expect(page).to have_content('This project is licensed under the MIT License.')
- visit_blob('.gitlab/route-map.yml')
+ # shows a learn more link
+ expect(page).to have_link('Learn more', href: 'http://choosealicense.com/licenses/mit/')
+ end
+ end
end
- it 'displays an auxiliary viewer' do
- aggregate_failures do
- # shows that map is valid
- expect(page).to have_content('This Route Map is valid.')
+ context '*.gemspec' do
+ before do
+ project.add_maintainer(project.creator)
- # shows a learn more link
- expect(page).to have_link('Learn more')
+ Files::CreateService.new(
+ project,
+ project.creator,
+ start_branch: 'master',
+ branch_name: 'master',
+ commit_message: "Add activerecord.gemspec",
+ file_path: 'activerecord.gemspec',
+ file_content: <<-SPEC.strip_heredoc
+ Gem::Specification.new do |s|
+ s.platform = Gem::Platform::RUBY
+ s.name = "activerecord"
+ end
+ SPEC
+ ).execute
+
+ visit_blob('activerecord.gemspec')
end
- end
- end
- describe '.gitlab/dashboards/custom-dashboard.yml' do
- before do
- project.add_maintainer(project.creator)
+ it 'displays an auxiliary viewer' do
+ aggregate_failures do
+ # shows names of dependency manager and package
+ expect(page).to have_content('This project manages its dependencies using RubyGems.')
- Files::CreateService.new(
- project,
- project.creator,
- start_branch: 'master',
- branch_name: 'master',
- commit_message: "Add .gitlab/dashboards/custom-dashboard.yml",
- file_path: '.gitlab/dashboards/custom-dashboard.yml',
- file_content: file_content
- ).execute
+ # shows a learn more link
+ expect(page).to have_link('Learn more', href: 'https://rubygems.org/')
+ end
+ end
end
- context 'with metrics_dashboard_exhaustive_validations feature flag off' do
+ context 'CONTRIBUTING.md' do
before do
- stub_feature_flags(metrics_dashboard_exhaustive_validations: false)
- visit_blob('.gitlab/dashboards/custom-dashboard.yml')
+ file_name = 'CONTRIBUTING.md'
+
+ create_file(file_name, '## Contribution guidelines')
+ visit_blob(file_name)
end
- context 'valid dashboard file' do
- let(:file_content) { File.read(Rails.root.join('config/prometheus/common_metrics.yml')) }
+ it 'displays an auxiliary viewer' do
+ aggregate_failures do
+ expect(page).to have_content("After you've reviewed these contribution guidelines, you'll be all set to contribute to this project.")
+ end
+ end
+ end
- it 'displays an auxiliary viewer' do
- aggregate_failures do
- # shows that dashboard yaml is valid
- expect(page).to have_content('Metrics Dashboard YAML definition is valid.')
+ context 'CHANGELOG.md' do
+ before do
+ file_name = 'CHANGELOG.md'
- # shows a learn more link
- expect(page).to have_link('Learn more')
- end
+ create_file(file_name, '## Changelog for v1.0.0')
+ visit_blob(file_name)
+ end
+
+ it 'displays an auxiliary viewer' do
+ aggregate_failures do
+ expect(page).to have_content("To find the state of this project's repository at the time of any of these versions, check out the tags.")
end
end
+ end
- context 'invalid dashboard file' do
- let(:file_content) { "dashboard: 'invalid'" }
+ context 'Cargo.toml' do
+ before do
+ file_name = 'Cargo.toml'
- it 'displays an auxiliary viewer' do
- aggregate_failures do
- # shows that dashboard yaml is invalid
- expect(page).to have_content('Metrics Dashboard YAML definition is invalid:')
- expect(page).to have_content("panel_groups: should be an array of panel_groups objects")
+ create_file(file_name, '
+ [package]
+ name = "hello_world" # the name of the package
+ version = "0.1.0" # the current version, obeying semver
+ authors = ["Alice <a@example.com>", "Bob <b@example.com>"]
+ ')
+ visit_blob(file_name)
+ end
- # shows a learn more link
- expect(page).to have_link('Learn more')
- end
+ it 'displays an auxiliary viewer' do
+ aggregate_failures do
+ expect(page).to have_content("This project manages its dependencies using Cargo.")
end
end
end
- context 'with metrics_dashboard_exhaustive_validations feature flag on' do
+ context 'Cartfile' do
before do
- stub_feature_flags(metrics_dashboard_exhaustive_validations: true)
- visit_blob('.gitlab/dashboards/custom-dashboard.yml')
+ file_name = 'Cartfile'
+
+ create_file(file_name, '
+ gitlab "Alamofire/Alamofire" == 4.9.0
+ gitlab "Alamofire/AlamofireImage" ~> 3.4
+ ')
+ visit_blob(file_name)
+ end
+
+ it 'displays an auxiliary viewer' do
+ aggregate_failures do
+ expect(page).to have_content("This project manages its dependencies using Carthage.")
+ end
end
+ end
- context 'valid dashboard file' do
- let(:file_content) { File.read(Rails.root.join('config/prometheus/common_metrics.yml')) }
+ context 'composer.json' do
+ before do
+ file_name = 'composer.json'
- it 'displays an auxiliary viewer' do
- aggregate_failures do
- # shows that dashboard yaml is valid
- expect(page).to have_content('Metrics Dashboard YAML definition is valid.')
+ create_file(file_name, '
+ {
+ "license": "MIT"
+ }
+ ')
+ visit_blob(file_name)
+ end
- # shows a learn more link
- expect(page).to have_link('Learn more')
- end
+ it 'displays an auxiliary viewer' do
+ aggregate_failures do
+ expect(page).to have_content("This project manages its dependencies using Composer.")
end
end
+ end
- context 'invalid dashboard file' do
- let(:file_content) { "dashboard: 'invalid'" }
+ context 'Gemfile' do
+ before do
+ file_name = 'Gemfile'
- it 'displays an auxiliary viewer' do
- aggregate_failures do
- # shows that dashboard yaml is invalid
- expect(page).to have_content('Metrics Dashboard YAML definition is invalid:')
- expect(page).to have_content("root is missing required keys: panel_groups")
+ create_file(file_name, '
+ source "https://rubygems.org"
- # shows a learn more link
- expect(page).to have_link('Learn more')
- end
+ # Gems here
+ ')
+ visit_blob(file_name)
+ end
+
+ it 'displays an auxiliary viewer' do
+ aggregate_failures do
+ expect(page).to have_content("This project manages its dependencies using Bundler.")
end
end
end
- end
- context 'LICENSE' do
- before do
- visit_blob('LICENSE')
- end
+ context 'Godeps.json' do
+ before do
+ file_name = 'Godeps.json'
- it 'displays an auxiliary viewer' do
- aggregate_failures do
- # shows license
- expect(page).to have_content('This project is licensed under the MIT License.')
+ create_file(file_name, '
+ {
+ "GoVersion": "go1.6"
+ }
+ ')
+ visit_blob(file_name)
+ end
- # shows a learn more link
- expect(page).to have_link('Learn more', href: 'http://choosealicense.com/licenses/mit/')
+ it 'displays an auxiliary viewer' do
+ aggregate_failures do
+ expect(page).to have_content("This project manages its dependencies using godep.")
+ end
end
end
- end
- context '*.gemspec' do
- before do
- project.add_maintainer(project.creator)
+ context 'go.mod' do
+ before do
+ file_name = 'go.mod'
- Files::CreateService.new(
- project,
- project.creator,
- start_branch: 'master',
- branch_name: 'master',
- commit_message: "Add activerecord.gemspec",
- file_path: 'activerecord.gemspec',
- file_content: <<-SPEC.strip_heredoc
- Gem::Specification.new do |s|
- s.platform = Gem::Platform::RUBY
- s.name = "activerecord"
- end
- SPEC
- ).execute
+ create_file(file_name, '
+ module example.com/mymodule
+
+ go 1.14
+ ')
+ visit_blob(file_name)
+ end
- visit_blob('activerecord.gemspec')
+ it 'displays an auxiliary viewer' do
+ aggregate_failures do
+ expect(page).to have_content("This project manages its dependencies using Go Modules.")
+ end
+ end
end
- it 'displays an auxiliary viewer' do
- aggregate_failures do
- # shows names of dependency manager and package
- expect(page).to have_content('This project manages its dependencies using RubyGems.')
+ context 'package.json' do
+ before do
+ file_name = 'package.json'
- # shows a learn more link
- expect(page).to have_link('Learn more', href: 'https://rubygems.org/')
+ create_file(file_name, '
+ {
+ "name": "my-awesome-package",
+ "version": "1.0.0"
+ }
+ ')
+ visit_blob(file_name)
+ end
+
+ it 'displays an auxiliary viewer' do
+ aggregate_failures do
+ expect(page).to have_content("This project manages its dependencies using npm.")
+ end
end
end
- end
- context 'CONTRIBUTING.md' do
- before do
- file_name = 'CONTRIBUTING.md'
+ context 'podfile' do
+ before do
+ file_name = 'podfile'
- create_file(file_name, '## Contribution guidelines')
- visit_blob(file_name)
- end
+ create_file(file_name, 'platform :ios, "8.0"')
+ visit_blob(file_name)
+ end
- it 'displays an auxiliary viewer' do
- aggregate_failures do
- expect(page).to have_content("After you've reviewed these contribution guidelines, you'll be all set to contribute to this project.")
+ it 'displays an auxiliary viewer' do
+ aggregate_failures do
+ expect(page).to have_content("This project manages its dependencies using CocoaPods.")
+ end
end
end
- end
- context 'CHANGELOG.md' do
- before do
- file_name = 'CHANGELOG.md'
+ context 'test.podspec' do
+ before do
+ file_name = 'test.podspec'
- create_file(file_name, '## Changelog for v1.0.0')
- visit_blob(file_name)
- end
+ create_file(file_name, '
+ Pod::Spec.new do |s|
+ s.name = "TensorFlowLiteC"
+ ')
+ visit_blob(file_name)
+ end
- it 'displays an auxiliary viewer' do
- aggregate_failures do
- expect(page).to have_content("To find the state of this project's repository at the time of any of these versions, check out the tags.")
+ it 'displays an auxiliary viewer' do
+ aggregate_failures do
+ expect(page).to have_content("This project manages its dependencies using CocoaPods.")
+ end
end
end
- end
- context 'Cargo.toml' do
- before do
- file_name = 'Cargo.toml'
+ context 'JSON.podspec.json' do
+ before do
+ file_name = 'JSON.podspec.json'
- create_file(file_name, '
- [package]
- name = "hello_world" # the name of the package
- version = "0.1.0" # the current version, obeying semver
- authors = ["Alice <a@example.com>", "Bob <b@example.com>"]
- ')
- visit_blob(file_name)
- end
+ create_file(file_name, '
+ {
+ "name": "JSON"
+ }
+ ')
+ visit_blob(file_name)
+ end
- it 'displays an auxiliary viewer' do
- aggregate_failures do
- expect(page).to have_content("This project manages its dependencies using Cargo.")
+ it 'displays an auxiliary viewer' do
+ aggregate_failures do
+ expect(page).to have_content("This project manages its dependencies using CocoaPods.")
+ end
end
end
- end
- context 'Cartfile' do
- before do
- file_name = 'Cartfile'
+ context 'requirements.txt' do
+ before do
+ file_name = 'requirements.txt'
- create_file(file_name, '
- gitlab "Alamofire/Alamofire" == 4.9.0
- gitlab "Alamofire/AlamofireImage" ~> 3.4
- ')
- visit_blob(file_name)
+ create_file(file_name, 'Project requirements')
+ visit_blob(file_name)
+ end
+
+ it 'displays an auxiliary viewer' do
+ aggregate_failures do
+ expect(page).to have_content("This project manages its dependencies using pip.")
+ end
+ end
end
- it 'displays an auxiliary viewer' do
- aggregate_failures do
- expect(page).to have_content("This project manages its dependencies using Carthage.")
+ context 'yarn.lock' do
+ before do
+ file_name = 'yarn.lock'
+
+ create_file(file_name, '
+ # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+ # yarn lockfile v1
+ ')
+ visit_blob(file_name)
+ end
+
+ it 'displays an auxiliary viewer' do
+ aggregate_failures do
+ expect(page).to have_content("This project manages its dependencies using Yarn.")
+ end
end
end
end
- context 'composer.json' do
+ context 'realtime pipelines' do
before do
- file_name = 'composer.json'
+ Files::CreateService.new(
+ project,
+ project.creator,
+ start_branch: 'feature',
+ branch_name: 'feature',
+ commit_message: "Add ruby file",
+ file_path: 'files/ruby/test.rb',
+ file_content: "# Awesome content"
+ ).execute
- create_file(file_name, '
- {
- "license": "MIT"
- }
- ')
- visit_blob(file_name)
+ create(:ci_pipeline, status: 'running', project: project, ref: 'feature', sha: project.commit('feature').sha)
+ visit_blob('files/ruby/test.rb', ref: 'feature')
end
- it 'displays an auxiliary viewer' do
- aggregate_failures do
- expect(page).to have_content("This project manages its dependencies using Composer.")
+ it 'shows the realtime pipeline status' do
+ page.within('.commit-actions') do
+ expect(page).to have_css('.ci-status-icon')
+ expect(page).to have_css('.ci-status-icon-running')
+ expect(page).to have_css('.js-ci-status-icon-running')
end
end
end
- context 'Gemfile' do
- before do
- file_name = 'Gemfile'
+ context 'for subgroups' do
+ let(:group) { create(:group) }
+ let(:subgroup) { create(:group, parent: group) }
+ let(:project) { create(:project, :public, :repository, group: subgroup) }
- create_file(file_name, '
- source "https://rubygems.org"
+ it 'renders tree table without errors' do
+ visit_blob('README.md')
- # Gems here
- ')
- visit_blob(file_name)
+ expect(page).to have_selector('.file-content')
+ expect(page).not_to have_selector('.flash-alert')
end
- it 'displays an auxiliary viewer' do
- aggregate_failures do
- expect(page).to have_content("This project manages its dependencies using Bundler.")
- end
+ it 'displays a GPG badge' do
+ visit_blob('CONTRIBUTING.md', ref: '33f3729a45c02fc67d00adb1b8bca394b0e761d9')
+
+ expect(page).not_to have_selector '.gpg-status-box.js-loading-gpg-badge'
+ expect(page).to have_selector '.gpg-status-box.invalid'
end
end
- context 'Godeps.json' do
- before do
- file_name = 'Godeps.json'
+ context 'on signed merge commit' do
+ it 'displays a GPG badge' do
+ visit_blob('conflicting-file.md', ref: '6101e87e575de14b38b4e1ce180519a813671e10')
- create_file(file_name, '
- {
- "GoVersion": "go1.6"
- }
- ')
- visit_blob(file_name)
- end
-
- it 'displays an auxiliary viewer' do
- aggregate_failures do
- expect(page).to have_content("This project manages its dependencies using godep.")
- end
+ expect(page).not_to have_selector '.gpg-status-box.js-loading-gpg-badge'
+ expect(page).to have_selector '.gpg-status-box.invalid'
end
end
- context 'go.mod' do
+ context 'when static objects external storage is enabled' do
before do
- file_name = 'go.mod'
+ stub_application_setting(static_objects_external_storage_url: 'https://cdn.gitlab.com')
+ end
- create_file(file_name, '
- module example.com/mymodule
+ context 'public project' do
+ before do
+ visit_blob('README.md')
+ end
- go 1.14
- ')
- visit_blob(file_name)
- end
+ it 'shows open raw and download buttons with external storage URL prepended to their href' do
+ path = project_raw_path(project, 'master/README.md')
+ raw_uri = "https://cdn.gitlab.com#{path}"
+ download_uri = "https://cdn.gitlab.com#{path}?inline=false"
- it 'displays an auxiliary viewer' do
- aggregate_failures do
- expect(page).to have_content("This project manages its dependencies using Go Modules.")
+ aggregate_failures do
+ expect(page).to have_link 'Open raw', href: raw_uri
+ expect(page).to have_link 'Download', href: download_uri
+ end
end
end
end
+ end
- context 'package.json' do
- before do
- file_name = 'package.json'
+ context 'with refactor_blob_viewer feature flag disabled' do
+ before do
+ stub_feature_flags(refactor_blob_viewer: false)
+ end
- create_file(file_name, '
- {
- "name": "my-awesome-package",
- "version": "1.0.0"
- }
- ')
- visit_blob(file_name)
- end
+ context 'when ref switch' do
+ # We need to unsre that this test runs with the refactor_blob_viewer feature flag enabled
+ # This will be addressed in https://gitlab.com/gitlab-org/gitlab/-/issues/351558
- it 'displays an auxiliary viewer' do
- aggregate_failures do
- expect(page).to have_content("This project manages its dependencies using npm.")
+ def switch_ref_to(ref_name)
+ first('.qa-branches-select').click # rubocop:disable QA/SelectorUsage
+
+ page.within '.project-refs-form' do
+ click_link ref_name
+ wait_for_requests
end
end
- end
- context 'podfile' do
- before do
- file_name = 'podfile'
+ context 'when highlighting lines' do
+ it 'displays single highlighted line number of different ref' do
+ visit_blob('files/js/application.js', anchor: 'L1')
- create_file(file_name, 'platform :ios, "8.0"')
- visit_blob(file_name)
- end
+ switch_ref_to('feature')
- it 'displays an auxiliary viewer' do
- aggregate_failures do
- expect(page).to have_content("This project manages its dependencies using CocoaPods.")
+ page.within '.blob-content' do
+ expect(find_by_id('LC1')[:class]).to include("hll")
+ end
end
- end
- end
- context 'test.podspec' do
- before do
- file_name = 'test.podspec'
+ it 'displays multiple highlighted line numbers of different ref' do
+ visit_blob('files/js/application.js', anchor: 'L1-3')
- create_file(file_name, '
- Pod::Spec.new do |s|
- s.name = "TensorFlowLiteC"
- ')
- visit_blob(file_name)
- end
+ switch_ref_to('feature')
- it 'displays an auxiliary viewer' do
- aggregate_failures do
- expect(page).to have_content("This project manages its dependencies using CocoaPods.")
+ page.within '.blob-content' do
+ expect(find_by_id('LC1')[:class]).to include("hll")
+ expect(find_by_id('LC2')[:class]).to include("hll")
+ expect(find_by_id('LC3')[:class]).to include("hll")
+ end
end
end
end
- context 'JSON.podspec.json' do
- before do
- file_name = 'JSON.podspec.json'
+ context 'visiting with a line number anchor' do
+ # We need to unsre that this test runs with the refactor_blob_viewer feature flag enabled
+ # This will be addressed in https://gitlab.com/gitlab-org/gitlab/-/issues/351558
- create_file(file_name, '
- {
- "name": "JSON"
- }
- ')
- visit_blob(file_name)
+ before do
+ visit_blob('files/markdown/ruby-style-guide.md', anchor: 'L1')
end
- it 'displays an auxiliary viewer' do
+ it 'displays the blob using the simple viewer' do
aggregate_failures do
- expect(page).to have_content("This project manages its dependencies using CocoaPods.")
+ # hides the rich viewer
+ expect(page).to have_selector('.blob-viewer[data-type="simple"]')
+ expect(page).not_to have_selector('.blob-viewer[data-type="rich"]')
+
+ # highlights the line in question
+ expect(page).to have_selector('#LC1.hll')
+
+ # shows highlighted Markdown code
+ expect(page).to have_css(".js-syntax-highlight")
+ expect(page).to have_content("[PEP-8](http://www.python.org/dev/peps/pep-0008/)")
+
+ # shows an enabled copy button
+ expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)')
end
end
end
- context 'requirements.txt' do
- before do
- file_name = 'requirements.txt'
+ context 'binary file that appears to be text in the first 1024 bytes' do
+ # We need to unsre that this test runs with the refactor_blob_viewer feature flag enabled
+ # This will be addressed in https://gitlab.com/gitlab-org/gitlab/-/issues/351559
- create_file(file_name, 'Project requirements')
- visit_blob(file_name)
+ before do
+ visit_blob('encoding/binary-1.bin', ref: 'binary-encoding')
end
-
- it 'displays an auxiliary viewer' do
+ it 'displays the blob' do
aggregate_failures do
- expect(page).to have_content("This project manages its dependencies using pip.")
+ # shows a download link
+ expect(page).to have_link('Download (23.8 KB)')
+ # does not show a viewer switcher
+ expect(page).not_to have_selector('.js-blob-viewer-switcher')
+ # The specs below verify an arguably incorrect result, but since we only
+ # learn that the file is not actually text once the text viewer content
+ # is loaded asynchronously, there is no straightforward way to get these
+ # synchronously loaded elements to display correctly.
+ #
+ # Clicking the copy button will result in nothing being copied.
+ # Clicking the raw button will result in the binary file being downloaded,
+ # as expected.
+ # shows an enabled copy button, incorrectly
+ expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)')
+ # shows a raw button, incorrectly
+ expect(page).to have_link('Open raw')
end
end
end
- context 'yarn.lock' do
- before do
- file_name = 'yarn.lock'
+ context 'when static objects external storage is enabled' do
+ # We need to unsre that this test runs with the refactor_blob_viewer feature flag enabled
+ # This will be addressed in https://gitlab.com/gitlab-org/gitlab/-/issues/351555
- create_file(file_name, '
- # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
- # yarn lockfile v1
- ')
- visit_blob(file_name)
+ before do
+ stub_application_setting(static_objects_external_storage_url: 'https://cdn.gitlab.com')
end
- it 'displays an auxiliary viewer' do
- aggregate_failures do
- expect(page).to have_content("This project manages its dependencies using Yarn.")
+ context 'private project' do
+ let_it_be(:project) { create(:project, :repository, :private) }
+ let_it_be(:user) { create(:user) }
+
+ before do
+ project.add_developer(user)
+
+ sign_in(user)
+ visit_blob('README.md')
+ end
+
+ it 'shows open raw and download buttons with external storage URL prepended and user token appended to their href' do
+ path = project_raw_path(project, 'master/README.md')
+ raw_uri = "https://cdn.gitlab.com#{path}?token=#{user.static_object_token}"
+ download_uri = "https://cdn.gitlab.com#{path}?inline=false&token=#{user.static_object_token}"
+
+ aggregate_failures do
+ expect(page).to have_link 'Open raw', href: raw_uri
+ expect(page).to have_link 'Download', href: download_uri
+ end
end
end
end
- context 'when refactor_blob_viewer is disabled' do
- before do
- stub_feature_flags(refactor_blob_viewer: false)
- end
+ context 'files with auxiliary viewers' do
+ # This context is the same as the other 'files with auxiliary viewers' in this file, we just ensure that the auxiliary viewers still work this the refactor_blob_viewer disabled
+ # It should be safe to remove once we rollout the refactored blob viewer
describe '.gitlab-ci.yml' do
before do
@@ -1554,104 +1657,4 @@ RSpec.describe 'File blob', :js do
end
end
end
-
- context 'realtime pipelines' do
- before do
- Files::CreateService.new(
- project,
- project.creator,
- start_branch: 'feature',
- branch_name: 'feature',
- commit_message: "Add ruby file",
- file_path: 'files/ruby/test.rb',
- file_content: "# Awesome content"
- ).execute
-
- create(:ci_pipeline, status: 'running', project: project, ref: 'feature', sha: project.commit('feature').sha)
- visit_blob('files/ruby/test.rb', ref: 'feature')
- end
-
- it 'shows the realtime pipeline status' do
- page.within('.commit-actions') do
- expect(page).to have_css('.ci-status-icon')
- expect(page).to have_css('.ci-status-icon-running')
- expect(page).to have_css('.js-ci-status-icon-running')
- end
- end
- end
-
- context 'for subgroups' do
- let(:group) { create(:group) }
- let(:subgroup) { create(:group, parent: group) }
- let(:project) { create(:project, :public, :repository, group: subgroup) }
-
- it 'renders tree table without errors' do
- visit_blob('README.md')
-
- expect(page).to have_selector('.file-content')
- expect(page).not_to have_selector('.flash-alert')
- end
-
- it 'displays a GPG badge' do
- visit_blob('CONTRIBUTING.md', ref: '33f3729a45c02fc67d00adb1b8bca394b0e761d9')
-
- expect(page).not_to have_selector '.gpg-status-box.js-loading-gpg-badge'
- expect(page).to have_selector '.gpg-status-box.invalid'
- end
- end
-
- context 'on signed merge commit' do
- it 'displays a GPG badge' do
- visit_blob('conflicting-file.md', ref: '6101e87e575de14b38b4e1ce180519a813671e10')
-
- expect(page).not_to have_selector '.gpg-status-box.js-loading-gpg-badge'
- expect(page).to have_selector '.gpg-status-box.invalid'
- end
- end
-
- context 'when static objects external storage is enabled' do
- before do
- stub_application_setting(static_objects_external_storage_url: 'https://cdn.gitlab.com')
- end
-
- context 'private project' do
- let_it_be(:project) { create(:project, :repository, :private) }
- let_it_be(:user) { create(:user) }
-
- before do
- project.add_developer(user)
-
- sign_in(user)
- visit_blob('README.md')
- end
-
- it 'shows open raw and download buttons with external storage URL prepended and user token appended to their href' do
- path = project_raw_path(project, 'master/README.md')
- raw_uri = "https://cdn.gitlab.com#{path}?token=#{user.static_object_token}"
- download_uri = "https://cdn.gitlab.com#{path}?inline=false&token=#{user.static_object_token}"
-
- aggregate_failures do
- expect(page).to have_link 'Open raw', href: raw_uri
- expect(page).to have_link 'Download', href: download_uri
- end
- end
- end
-
- context 'public project' do
- before do
- visit_blob('README.md')
- end
-
- it 'shows open raw and download buttons with external storage URL prepended to their href' do
- path = project_raw_path(project, 'master/README.md')
- raw_uri = "https://cdn.gitlab.com#{path}"
- download_uri = "https://cdn.gitlab.com#{path}?inline=false"
-
- aggregate_failures do
- expect(page).to have_link 'Open raw', href: raw_uri
- expect(page).to have_link 'Download', href: download_uri
- end
- end
- end
- end
end
diff --git a/spec/frontend/__helpers__/matchers/to_match_interpolated_text.js b/spec/frontend/__helpers__/matchers/to_match_interpolated_text.js
index 4ce814a01b4..41e69bffd88 100644
--- a/spec/frontend/__helpers__/matchers/to_match_interpolated_text.js
+++ b/spec/frontend/__helpers__/matchers/to_match_interpolated_text.js
@@ -1,4 +1,5 @@
-export const toMatchInterpolatedText = (received, match) => {
+// Custom matchers are object methods and should be traditional functions to be able to access `utils` on `this`
+export function toMatchInterpolatedText(received, match) {
let clearReceived;
let clearMatch;
@@ -15,16 +16,14 @@ export const toMatchInterpolatedText = (received, match) => {
const pass = clearReceived === clearMatch;
const message = pass
? () => `
- \n\n
- Expected: ${this.utils.printExpected(clearReceived)}
- To not equal: ${this.utils.printReceived(clearMatch)}
+ Expected to not be: ${this.utils.printExpected(clearMatch)}
+ Received: ${this.utils.printReceived(clearReceived)}
`
: () =>
`
- \n\n
- Expected: ${this.utils.printExpected(clearReceived)}
- To equal: ${this.utils.printReceived(clearMatch)}
+ Expected to be: ${this.utils.printExpected(clearMatch)}
+ Received: ${this.utils.printReceived(clearReceived)}
`;
return { actual: received, message, pass };
-};
+}
diff --git a/spec/frontend/blob/components/__snapshots__/blob_header_spec.js.snap b/spec/frontend/blob/components/__snapshots__/blob_header_spec.js.snap
index 22bec77276b..b3d93906445 100644
--- a/spec/frontend/blob/components/__snapshots__/blob_header_spec.js.snap
+++ b/spec/frontend/blob/components/__snapshots__/blob_header_spec.js.snap
@@ -13,6 +13,7 @@ exports[`Blob Header Default Actions rendering matches the snapshot 1`] = `
<blob-filepath-stub
blob="[object Object]"
+ showpath="true"
/>
</div>
diff --git a/spec/frontend/environments/environment_pin_spec.js b/spec/frontend/environments/environment_pin_spec.js
index a9a58071e12..669c974ea4f 100644
--- a/spec/frontend/environments/environment_pin_spec.js
+++ b/spec/frontend/environments/environment_pin_spec.js
@@ -1,5 +1,9 @@
+import Vue from 'vue';
+import VueApollo from 'vue-apollo';
import { GlDropdownItem } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
+import cancelAutoStopMutation from '~/environments/graphql/mutations/cancel_auto_stop.mutation.graphql';
+import createMockApollo from 'helpers/mock_apollo_helper';
import PinComponent from '~/environments/components/environment_pin.vue';
import eventHub from '~/environments/event_hub';
@@ -18,28 +22,66 @@ describe('Pin Component', () => {
const autoStopUrl = '/root/auto-stop-env-test/-/environments/38/cancel_auto_stop';
- beforeEach(() => {
- factory({
- propsData: {
- autoStopUrl,
- },
+ describe('without graphql', () => {
+ beforeEach(() => {
+ factory({
+ propsData: {
+ autoStopUrl,
+ },
+ });
});
- });
- afterEach(() => {
- wrapper.destroy();
- });
+ afterEach(() => {
+ wrapper.destroy();
+ });
- it('should render the component with descriptive text', () => {
- expect(wrapper.text()).toBe('Prevent auto-stopping');
+ it('should render the component with descriptive text', () => {
+ expect(wrapper.text()).toBe('Prevent auto-stopping');
+ });
+
+ it('should emit onPinClick when clicked', () => {
+ const eventHubSpy = jest.spyOn(eventHub, '$emit');
+ const item = wrapper.find(GlDropdownItem);
+
+ item.vm.$emit('click');
+
+ expect(eventHubSpy).toHaveBeenCalledWith('cancelAutoStop', autoStopUrl);
+ });
});
- it('should emit onPinClick when clicked', () => {
- const eventHubSpy = jest.spyOn(eventHub, '$emit');
- const item = wrapper.find(GlDropdownItem);
+ describe('with graphql', () => {
+ Vue.use(VueApollo);
+ let mockApollo;
- item.vm.$emit('click');
+ beforeEach(() => {
+ mockApollo = createMockApollo();
+ factory({
+ propsData: {
+ autoStopUrl,
+ graphql: true,
+ },
+ apolloProvider: mockApollo,
+ });
+ });
- expect(eventHubSpy).toHaveBeenCalledWith('cancelAutoStop', autoStopUrl);
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('should render the component with descriptive text', () => {
+ expect(wrapper.text()).toBe('Prevent auto-stopping');
+ });
+
+ it('should emit onPinClick when clicked', () => {
+ jest.spyOn(mockApollo.defaultClient, 'mutate');
+ const item = wrapper.find(GlDropdownItem);
+
+ item.vm.$emit('click');
+
+ expect(mockApollo.defaultClient.mutate).toHaveBeenCalledWith({
+ mutation: cancelAutoStopMutation,
+ variables: { autoStopUrl },
+ });
+ });
});
});
diff --git a/spec/frontend/environments/graphql/resolvers_spec.js b/spec/frontend/environments/graphql/resolvers_spec.js
index 6b53dc24f0f..21d7e09bad5 100644
--- a/spec/frontend/environments/graphql/resolvers_spec.js
+++ b/spec/frontend/environments/graphql/resolvers_spec.js
@@ -173,9 +173,7 @@ describe('~/frontend/environments/graphql/resolvers', () => {
it('should post to the auto stop path', async () => {
mock.onPost(ENDPOINT).reply(200);
- await mockResolvers.Mutation.cancelAutoStop(null, {
- environment: { autoStopPath: ENDPOINT },
- });
+ await mockResolvers.Mutation.cancelAutoStop(null, { autoStopUrl: ENDPOINT });
expect(mock.history.post).toContainEqual(
expect.objectContaining({ url: ENDPOINT, method: 'post' }),
diff --git a/spec/frontend/environments/new_environment_item_spec.js b/spec/frontend/environments/new_environment_item_spec.js
index de36b701a16..0d5d216ba02 100644
--- a/spec/frontend/environments/new_environment_item_spec.js
+++ b/spec/frontend/environments/new_environment_item_spec.js
@@ -191,9 +191,9 @@ describe('~/environments/components/new_environment_item.vue', () => {
});
it('shows the option to pin the environment if there is an autostop date', () => {
- const rollback = wrapper.findByRole('menuitem', { name: __('Prevent auto-stopping') });
+ const pin = wrapper.findByRole('menuitem', { name: __('Prevent auto-stopping') });
- expect(rollback.exists()).toBe(true);
+ expect(pin.exists()).toBe(true);
});
it('shows when the environment auto stops', () => {
@@ -211,9 +211,9 @@ describe('~/environments/components/new_environment_item.vue', () => {
it('does not show the option to pin the environment if there is no autostop date', () => {
wrapper = createWrapper({ apolloProvider: createApolloProvider() });
- const rollback = wrapper.findByRole('menuitem', { name: __('Prevent auto-stopping') });
+ const pin = wrapper.findByRole('menuitem', { name: __('Prevent auto-stopping') });
- expect(rollback.exists()).toBe(false);
+ expect(pin.exists()).toBe(false);
});
it('does not show when the environment auto stops', () => {
@@ -246,9 +246,9 @@ describe('~/environments/components/new_environment_item.vue', () => {
it('does not show the option to pin the environment if there is no autostop date', () => {
wrapper = createWrapper({ apolloProvider: createApolloProvider() });
- const rollback = wrapper.findByRole('menuitem', { name: __('Prevent auto-stopping') });
+ const pin = wrapper.findByRole('menuitem', { name: __('Prevent auto-stopping') });
- expect(rollback.exists()).toBe(false);
+ expect(pin.exists()).toBe(false);
});
it('does not show when the environment auto stops', () => {
diff --git a/spec/frontend/repository/components/blob_content_viewer_spec.js b/spec/frontend/repository/components/blob_content_viewer_spec.js
index 70808a3c7b1..eb9b443c694 100644
--- a/spec/frontend/repository/components/blob_content_viewer_spec.js
+++ b/spec/frontend/repository/components/blob_content_viewer_spec.js
@@ -236,7 +236,7 @@ describe('Blob content viewer component', () => {
await waitForPromises();
- expect(loadViewer).toHaveBeenCalledWith(viewer);
+ expect(loadViewer).toHaveBeenCalledWith(viewer, false);
expect(wrapper.findComponent(loadViewerReturnValue).exists()).toBe(true);
},
);
diff --git a/spec/frontend/repository/components/blob_viewers/lfs_viewer_spec.js b/spec/frontend/repository/components/blob_viewers/lfs_viewer_spec.js
new file mode 100644
index 00000000000..59cca23ebfc
--- /dev/null
+++ b/spec/frontend/repository/components/blob_viewers/lfs_viewer_spec.js
@@ -0,0 +1,41 @@
+import { GlLink, GlSprintf } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import LfsViewer from '~/repository/components/blob_viewers/lfs_viewer.vue';
+
+describe('LFS Viewer', () => {
+ let wrapper;
+
+ const DEFAULT_PROPS = {
+ fileName: 'file_name.js',
+ filePath: '/some/file/path',
+ };
+
+ const createComponent = () => {
+ wrapper = shallowMount(LfsViewer, {
+ propsData: { ...DEFAULT_PROPS },
+ stubs: { GlSprintf },
+ });
+ };
+
+ const findLink = () => wrapper.findComponent(GlLink);
+
+ beforeEach(() => createComponent());
+
+ afterEach(() => wrapper.destroy());
+
+ it('renders the correct text', () => {
+ expect(wrapper.text()).toBe(
+ 'This content could not be displayed because it is stored in LFS. You can download it instead.',
+ );
+ });
+
+ it('renders download link', () => {
+ const { filePath, fileName } = DEFAULT_PROPS;
+
+ expect(findLink().attributes()).toMatchObject({
+ target: '_blank',
+ href: filePath,
+ download: fileName,
+ });
+ });
+});
diff --git a/spec/frontend/repository/mock_data.js b/spec/frontend/repository/mock_data.js
index b8ab5cfcef1..2df89965fbe 100644
--- a/spec/frontend/repository/mock_data.js
+++ b/spec/frontend/repository/mock_data.js
@@ -17,6 +17,7 @@ export const simpleViewerMock = {
canCurrentUserPushToBranch: true,
archived: false,
storedExternally: false,
+ externalStorageUrl: '',
externalStorage: 'lfs',
rawPath: 'some_file.js',
replacePath: 'some_file.js/replace',
diff --git a/spec/helpers/projects_helper_spec.rb b/spec/helpers/projects_helper_spec.rb
index cc443afee6e..1d78778c757 100644
--- a/spec/helpers/projects_helper_spec.rb
+++ b/spec/helpers/projects_helper_spec.rb
@@ -345,6 +345,14 @@ RSpec.describe ProjectsHelper do
expect(link).not_to include(user.name)
end
end
+
+ context 'when user is nil' do
+ it 'returns "(deleted)"' do
+ link = helper.link_to_member(project, nil)
+
+ expect(link).to eq("(deleted)")
+ end
+ end
end
describe 'default_clone_protocol' do
diff --git a/spec/lib/gitlab/rack_attack/request_spec.rb b/spec/lib/gitlab/rack_attack/request_spec.rb
index ecdcc23e588..37db588ce16 100644
--- a/spec/lib/gitlab/rack_attack/request_spec.rb
+++ b/spec/lib/gitlab/rack_attack/request_spec.rb
@@ -5,6 +5,20 @@ require 'spec_helper'
RSpec.describe Gitlab::RackAttack::Request do
using RSpec::Parameterized::TableSyntax
+ let(:path) { '/' }
+ let(:env) { {} }
+ let(:session) { {} }
+ let(:request) do
+ ::Rack::Attack::Request.new(
+ env.reverse_merge(
+ 'REQUEST_METHOD' => 'GET',
+ 'PATH_INFO' => path,
+ 'rack.input' => StringIO.new,
+ 'rack.session' => session
+ )
+ )
+ end
+
describe 'FILES_PATH_REGEX' do
subject { described_class::FILES_PATH_REGEX }
@@ -16,11 +30,172 @@ RSpec.describe Gitlab::RackAttack::Request do
it { is_expected.not_to match('/api/v4/projects/some/nested/repo/repository/files/README') }
end
+ describe '#api_request?' do
+ subject { request.api_request? }
+
+ where(:path, :expected) do
+ '/' | false
+ '/groups' | false
+ '/foo/api' | false
+
+ '/api' | true
+ '/api/v4/groups/1' | true
+ end
+
+ with_them do
+ it { is_expected.to eq(expected) }
+ end
+ end
+
+ describe '#api_internal_request?' do
+ subject { request.api_internal_request? }
+
+ where(:path, :expected) do
+ '/' | false
+ '/groups' | false
+ '/api' | false
+ '/api/v4/groups/1' | false
+ '/api/v4/internal' | false
+ '/foo/api/v4/internal' | false
+
+ '/api/v4/internal/' | true
+ '/api/v4/internal/foo' | true
+ '/api/v1/internal/foo' | true
+ end
+
+ with_them do
+ it { is_expected.to eq(expected) }
+ end
+ end
+
+ describe '#health_check_request?' do
+ subject { request.health_check_request? }
+
+ where(:path, :expected) do
+ '/' | false
+ '/groups' | false
+ '/foo/-/health' | false
+
+ '/-/health' | true
+ '/-/liveness' | true
+ '/-/readiness' | true
+ '/-/metrics' | true
+ '/-/health/foo' | true
+ '/-/liveness/foo' | true
+ '/-/readiness/foo' | true
+ '/-/metrics/foo' | true
+ end
+
+ with_them do
+ it { is_expected.to eq(expected) }
+ end
+ end
+
+ describe '#container_registry_event?' do
+ subject { request.container_registry_event? }
+
+ where(:path, :expected) do
+ '/' | false
+ '/groups' | false
+ '/api/v4/container_registry_event' | false
+ '/foo/api/v4/container_registry_event/' | false
+
+ '/api/v4/container_registry_event/' | true
+ '/api/v4/container_registry_event/foo' | true
+ '/api/v1/container_registry_event/foo' | true
+ end
+
+ with_them do
+ it { is_expected.to eq(expected) }
+ end
+ end
+
+ describe '#product_analytics_collector_request?' do
+ subject { request.product_analytics_collector_request? }
+
+ where(:path, :expected) do
+ '/' | false
+ '/groups' | false
+ '/-/collector' | false
+ '/-/collector/foo' | false
+ '/foo/-/collector/i' | false
+
+ '/-/collector/i' | true
+ '/-/collector/ifoo' | true
+ '/-/collector/i/foo' | true
+ end
+
+ with_them do
+ it { is_expected.to eq(expected) }
+ end
+ end
+
+ describe '#should_be_skipped?' do
+ where(
+ api_internal_request: [true, false],
+ health_check_request: [true, false],
+ container_registry_event: [true, false]
+ )
+
+ with_them do
+ it 'returns true if any condition is true' do
+ allow(request).to receive(:api_internal_request?).and_return(api_internal_request)
+ allow(request).to receive(:health_check_request?).and_return(health_check_request)
+ allow(request).to receive(:container_registry_event?).and_return(container_registry_event)
+
+ expect(request.should_be_skipped?).to be(api_internal_request || health_check_request || container_registry_event)
+ end
+ end
+ end
+
+ describe '#web_request?' do
+ subject { request.web_request? }
+
+ where(:path, :expected) do
+ '/' | true
+ '/groups' | true
+ '/foo/api' | true
+
+ '/api' | false
+ '/api/v4/groups/1' | false
+ end
+
+ with_them do
+ it { is_expected.to eq(expected) }
+ end
+ end
+
+ describe '#protected_path?' do
+ subject { request.protected_path? }
+
+ before do
+ stub_application_setting(protected_paths: [
+ '/protected',
+ '/secure'
+ ])
+ end
+
+ where(:path, :expected) do
+ '/' | false
+ '/groups' | false
+ '/foo/protected' | false
+ '/foo/secure' | false
+
+ '/protected' | true
+ '/secure' | true
+ '/secure/' | true
+ '/secure/foo' | true
+ end
+
+ with_them do
+ it { is_expected.to eq(expected) }
+ end
+ end
+
describe '#deprecated_api_request?' do
- let(:env) { { 'REQUEST_METHOD' => 'GET', 'rack.input' => StringIO.new, 'PATH_INFO' => path, 'QUERY_STRING' => query } }
- let(:request) { ::Rack::Attack::Request.new(env) }
+ subject { request.send(:deprecated_api_request?) }
- subject { !!request.__send__(:deprecated_api_request?) }
+ let(:env) { { 'QUERY_STRING' => query } }
where(:path, :query, :expected) do
'/' | '' | false
diff --git a/spec/lib/gitlab/usage_data_spec.rb b/spec/lib/gitlab/usage_data_spec.rb
index 725a571e385..3dc38b5bc1c 100644
--- a/spec/lib/gitlab/usage_data_spec.rb
+++ b/spec/lib/gitlab/usage_data_spec.rb
@@ -12,8 +12,8 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do
stub_database_flavor_check('Cloud SQL for PostgreSQL')
end
- describe '.uncached_data' do
- subject { described_class.uncached_data }
+ describe '.data' do
+ subject { described_class.data(force_refresh: true) }
it 'includes basic top and second level keys' do
is_expected.to include(:counts)
diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb
index 70dd1cbe240..9da22e15a12 100644
--- a/spec/models/merge_request_spec.rb
+++ b/spec/models/merge_request_spec.rb
@@ -3524,7 +3524,7 @@ RSpec.describe MergeRequest, factory_default: :keep do
let!(:job) { create(:ci_build, :with_deployment, :start_review_app, pipeline: pipeline, project: project) }
it 'returns environments' do
- is_expected.to eq(pipeline.environments)
+ is_expected.to eq(pipeline.environments_in_self_and_descendants.to_a)
expect(subject.count).to be(1)
end
diff --git a/spec/requests/rack_attack_global_spec.rb b/spec/requests/rack_attack_global_spec.rb
index 793438808a5..25eae57a134 100644
--- a/spec/requests/rack_attack_global_spec.rb
+++ b/spec/requests/rack_attack_global_spec.rb
@@ -184,6 +184,7 @@ RSpec.describe 'Rack Attack global throttles', :use_clean_rails_memory_store_cac
context 'unauthenticated requests' do
let(:protected_path_that_does_not_require_authentication) do
+ # This is one of the default values for `application_settings.protected_paths`
'/users/sign_in'
end
@@ -227,6 +228,20 @@ RSpec.describe 'Rack Attack global throttles', :use_clean_rails_memory_store_cac
expect_rejection { post protected_path_that_does_not_require_authentication, params: post_params }
end
+ it 'allows non-POST requests to protected paths over the rate limit' do
+ (1 + requests_per_period).times do
+ get protected_path_that_does_not_require_authentication
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+ end
+
+ it 'allows POST requests to unprotected paths over the rate limit' do
+ (1 + requests_per_period).times do
+ post '/api/graphql'
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+ end
+
it_behaves_like 'tracking when dry-run mode is set' do
let(:throttle_name) { 'throttle_unauthenticated_protected_paths' }
end
diff --git a/spec/rubocop/cop/sidekiq_load_balancing/worker_data_consistency_with_deduplication_spec.rb b/spec/rubocop/cop/sidekiq_load_balancing/worker_data_consistency_with_deduplication_spec.rb
deleted file mode 100644
index 6e7212b1002..00000000000
--- a/spec/rubocop/cop/sidekiq_load_balancing/worker_data_consistency_with_deduplication_spec.rb
+++ /dev/null
@@ -1,166 +0,0 @@
-# frozen_string_literal: true
-
-require 'fast_spec_helper'
-require 'rspec-parameterized'
-require_relative '../../../../rubocop/cop/sidekiq_load_balancing/worker_data_consistency_with_deduplication'
-
-RSpec.describe RuboCop::Cop::SidekiqLoadBalancing::WorkerDataConsistencyWithDeduplication do
- using RSpec::Parameterized::TableSyntax
-
- subject(:cop) { described_class.new }
-
- before do
- allow(cop)
- .to receive(:in_worker?)
- .and_return(true)
- end
-
- where(:data_consistency) { %i[delayed sticky] }
-
- with_them do
- let(:strategy) { described_class::DEFAULT_STRATEGY }
- let(:corrected) do
- <<~CORRECTED
- class SomeWorker
- include ApplicationWorker
-
- data_consistency :#{data_consistency}
-
- deduplicate #{strategy}, including_scheduled: true
- idempotent!
- end
- CORRECTED
- end
-
- context 'when deduplication strategy is not explicitly set' do
- it 'registers an offense and corrects using default strategy' do
- expect_offense(<<~CODE)
- class SomeWorker
- include ApplicationWorker
-
- data_consistency :#{data_consistency}
-
- idempotent!
- ^^^^^^^^^^^ Workers that declare either `:sticky` or `:delayed` data consistency [...]
- end
- CODE
-
- expect_correction(corrected)
- end
-
- context 'when identation is different' do
- let(:corrected) do
- <<~CORRECTED
- class SomeWorker
- include ApplicationWorker
-
- data_consistency :#{data_consistency}
-
- deduplicate #{strategy}, including_scheduled: true
- idempotent!
- end
- CORRECTED
- end
-
- it 'registers an offense and corrects with correct identation' do
- expect_offense(<<~CODE)
- class SomeWorker
- include ApplicationWorker
-
- data_consistency :#{data_consistency}
-
- idempotent!
- ^^^^^^^^^^^ Workers that declare either `:sticky` or `:delayed` data consistency [...]
- end
- CODE
-
- expect_correction(corrected)
- end
- end
- end
-
- context 'when deduplication strategy does not include including_scheduling option' do
- let(:strategy) { ':until_executed' }
-
- it 'registers an offense and corrects' do
- expect_offense(<<~CODE)
- class SomeWorker
- include ApplicationWorker
-
- data_consistency :#{data_consistency}
-
- deduplicate :until_executed
- ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Workers that declare either `:sticky` or `:delayed` data consistency [...]
- idempotent!
- end
- CODE
-
- expect_correction(corrected)
- end
- end
-
- context 'when deduplication strategy has including_scheduling option disabled' do
- let(:strategy) { ':until_executed' }
-
- it 'registers an offense and corrects' do
- expect_offense(<<~CODE)
- class SomeWorker
- include ApplicationWorker
-
- data_consistency :#{data_consistency}
-
- deduplicate :until_executed, including_scheduled: false
- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Workers that declare either `:sticky` or `:delayed` data consistency [...]
- idempotent!
- end
- CODE
-
- expect_correction(corrected)
- end
- end
-
- context "when deduplication strategy is :none" do
- it 'does not register an offense' do
- expect_no_offenses(<<~CODE)
- class SomeWorker
- include ApplicationWorker
-
- data_consistency :always
-
- deduplicate :none
- idempotent!
- end
- CODE
- end
- end
-
- context "when deduplication strategy has including_scheduling option enabled" do
- it 'does not register an offense' do
- expect_no_offenses(<<~CODE)
- class SomeWorker
- include ApplicationWorker
-
- data_consistency :always
-
- deduplicate :until_executing, including_scheduled: true
- idempotent!
- end
- CODE
- end
- end
- end
-
- context "data_consistency: :always" do
- it 'does not register an offense' do
- expect_no_offenses(<<~CODE)
- class SomeWorker
- include ApplicationWorker
-
- data_consistency :always
-
- idempotent!
- end
- CODE
- end
- end
-end
diff --git a/spec/serializers/test_case_entity_spec.rb b/spec/serializers/test_case_entity_spec.rb
index cdeefd2fec5..03fb88bc6c3 100644
--- a/spec/serializers/test_case_entity_spec.rb
+++ b/spec/serializers/test_case_entity_spec.rb
@@ -41,6 +41,18 @@ RSpec.describe TestCaseEntity do
end
end
+ context 'when no test name is entered' do
+ let(:test_case) { build(:report_test_case, name: "") }
+
+ it 'contains correct test case details' do
+ expect(subject[:status]).to eq('success')
+ expect(subject[:name]).to eq('(No name)')
+ expect(subject[:classname]).to eq('trace')
+ expect(subject[:file]).to eq('spec/trace_spec.rb')
+ expect(subject[:execution_time]).to eq(1.23)
+ end
+ end
+
context 'when attachment is present' do
let(:test_case) { build(:report_test_case, :failed_with_attachment, job: job) }
diff --git a/spec/services/environments/stop_service_spec.rb b/spec/services/environments/stop_service_spec.rb
index acc9869002f..362071c1c26 100644
--- a/spec/services/environments/stop_service_spec.rb
+++ b/spec/services/environments/stop_service_spec.rb
@@ -185,7 +185,7 @@ RSpec.describe Environments::StopService do
end
it 'has active environment at first' do
- expect(pipeline.environments.first).to be_available
+ expect(pipeline.environments_in_self_and_descendants.first).to be_available
end
context 'when user is a developer' do
@@ -196,7 +196,7 @@ RSpec.describe Environments::StopService do
it 'stops the active environment' do
subject
- expect(pipeline.environments.first).to be_stopped
+ expect(pipeline.environments_in_self_and_descendants.first).to be_stopped
end
end
@@ -208,7 +208,7 @@ RSpec.describe Environments::StopService do
it 'does not stop the active environment' do
subject
- expect(pipeline.environments.first).to be_available
+ expect(pipeline.environments_in_self_and_descendants.first).to be_available
end
end
@@ -232,7 +232,7 @@ RSpec.describe Environments::StopService do
it 'does not stop the active environment' do
subject
- expect(pipeline.environments.first).to be_available
+ expect(pipeline.environments_in_self_and_descendants.first).to be_available
end
end
end