diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-05-13 13:21:06 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-05-13 13:21:06 +0000 |
commit | 6e0790501a8cd39791191de6312c0387d4a0ed3f (patch) | |
tree | b988c8fd0c042de231b7221d500972bf51202be0 /spec/lib | |
parent | 91866438d75c3ee05b1a40b30f2b62e111a00fde (diff) | |
download | gitlab-ce-6e0790501a8cd39791191de6312c0387d4a0ed3f.tar.gz |
Add latest changes from gitlab-org/gitlab@13-0-stable-ee
Diffstat (limited to 'spec/lib')
26 files changed, 910 insertions, 42 deletions
diff --git a/spec/lib/api/entities/design_management/design_spec.rb b/spec/lib/api/entities/design_management/design_spec.rb new file mode 100644 index 00000000000..50ca3b43c6a --- /dev/null +++ b/spec/lib/api/entities/design_management/design_spec.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe API::Entities::DesignManagement::Design do + let_it_be(:design) { create(:design) } + let(:entity) { described_class.new(design, request: double) } + + subject { entity.as_json } + + it 'has the correct attributes' do + expect(subject).to eq({ + id: design.id, + project_id: design.project_id, + filename: design.filename, + image_url: ::Gitlab::UrlBuilder.build(design) + }) + end +end diff --git a/spec/lib/banzai/filter/issue_reference_filter_spec.rb b/spec/lib/banzai/filter/issue_reference_filter_spec.rb index 4a412da27a7..61c59162a30 100644 --- a/spec/lib/banzai/filter/issue_reference_filter_spec.rb +++ b/spec/lib/banzai/filter/issue_reference_filter_spec.rb @@ -4,6 +4,7 @@ require 'spec_helper' describe Banzai::Filter::IssueReferenceFilter do include FilterSpecHelper + include DesignManagementTestHelpers def helper IssuesHelper @@ -358,6 +359,23 @@ describe Banzai::Filter::IssueReferenceFilter do end end + context 'when processing a link to the designs tab' do + let(:designs_tab_url) { url_for_designs(issue) } + let(:input_text) { "See #{designs_tab_url}" } + + subject(:link) { reference_filter(input_text).css('a').first } + + before do + enable_design_management + end + + it 'includes the word "designs" after the reference in the text content', :aggregate_failures do + expect(link.attr('title')).to eq(issue.title) + expect(link.attr('href')).to eq(designs_tab_url) + expect(link.text).to eq("#{issue.to_reference} (designs)") + end + end + context 'group context' do let(:group) { create(:group) } let(:context) { { project: nil, group: group } } @@ -467,4 +485,41 @@ describe Banzai::Filter::IssueReferenceFilter do end.not_to yield_control end end + + describe '#object_link_text_extras' do + before do + enable_design_management(enabled) + end + + let(:current_user) { project.owner } + let(:enabled) { true } + let(:matches) { Issue.link_reference_pattern.match(input_text) } + let(:extras) { subject.object_link_text_extras(issue, matches) } + + subject { filter_instance } + + context 'the link does not go to the designs tab' do + let(:input_text) { Gitlab::Routing.url_helpers.project_issue_url(issue.project, issue) } + + it 'does not include designs' do + expect(extras).not_to include('designs') + end + end + + context 'the link goes to the designs tab' do + let(:input_text) { url_for_designs(issue) } + + it 'includes designs' do + expect(extras).to include('designs') + end + + context 'design management is disabled' do + let(:enabled) { false } + + it 'does not include designs in the extras' do + expect(extras).not_to include('designs') + end + end + end + end end diff --git a/spec/lib/banzai/reference_parser/design_parser_spec.rb b/spec/lib/banzai/reference_parser/design_parser_spec.rb new file mode 100644 index 00000000000..76708acf887 --- /dev/null +++ b/spec/lib/banzai/reference_parser/design_parser_spec.rb @@ -0,0 +1,91 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Banzai::ReferenceParser::DesignParser do + include ReferenceParserHelpers + include DesignManagementTestHelpers + + let_it_be(:issue) { create(:issue) } + let_it_be(:design) { create(:design, :with_versions, issue: issue) } + let_it_be(:user) { create(:user, developer_projects: [issue.project]) } + + subject(:instance) { described_class.new(Banzai::RenderContext.new(issue.project, user)) } + + let(:link) { design_link(design) } + + before do + enable_design_management + end + + describe '#nodes_visible_to_user' do + it_behaves_like 'referenced feature visibility', 'issues' do + let(:project) { issue.project } + end + + describe 'specific states' do + let_it_be(:public_project) { create(:project, :public) } + + let_it_be(:other_project_link) do + design_link(create(:design, :with_versions)) + end + let_it_be(:public_link) do + design_link(create(:design, :with_versions, issue: create(:issue, project: public_project))) + end + let_it_be(:public_but_confidential_link) do + design_link(create(:design, :with_versions, issue: create(:issue, :confidential, project: public_project))) + end + + subject(:visible_nodes) do + nodes = [link, + other_project_link, + public_link, + public_but_confidential_link] + + instance.nodes_visible_to_user(user, nodes) + end + + it 'redacts links we should not have access to' do + expect(visible_nodes).to contain_exactly(link, public_link) + end + + context 'design management is not available' do + before do + enable_design_management(false) + end + + it 'redacts all nodes' do + expect(visible_nodes).to be_empty + end + end + end + end + + describe '#process' do + it 'returns the correct designs' do + frag = document([design, create(:design, :with_versions)]) + + expect(subject.process([frag])[:visible]).to contain_exactly(design) + end + end + + def design_link(design) + node = empty_html_link + node['class'] = 'gfm' + node['data-reference-type'] = 'design' + node['data-project'] = design.project.id.to_s + node['data-issue'] = design.issue.id.to_s + node['data-design'] = design.id.to_s + + node + end + + def document(designs) + frag = Nokogiri::HTML.fragment('') + designs.each do |design| + frag.add_child(design_link(design)) + end + + frag + end +end diff --git a/spec/lib/gitlab/analytics/cycle_analytics/median_spec.rb b/spec/lib/gitlab/analytics/cycle_analytics/median_spec.rb new file mode 100644 index 00000000000..92ecec350ae --- /dev/null +++ b/spec/lib/gitlab/analytics/cycle_analytics/median_spec.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Gitlab::Analytics::CycleAnalytics::Median do + let_it_be(:project) { create(:project, :repository) } + let(:query) { Project.joins(merge_requests: :metrics) } + + let(:stage) do + build( + :cycle_analytics_project_stage, + start_event_identifier: Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestCreated.identifier, + end_event_identifier: Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestMerged.identifier, + project: project + ) + end + + subject { described_class.new(stage: stage, query: query).seconds } + + around do |example| + Timecop.freeze { example.run } + end + + it 'retruns nil when no results' do + expect(subject).to eq(nil) + end + + it 'returns median duration seconds as float' do + merge_request1 = create(:merge_request, source_branch: '1', target_project: project, source_project: project) + merge_request2 = create(:merge_request, source_branch: '2', target_project: project, source_project: project) + + Timecop.travel(5.minutes.from_now) do + merge_request1.metrics.update!(merged_at: Time.zone.now) + end + + Timecop.travel(10.minutes.from_now) do + merge_request2.metrics.update!(merged_at: Time.zone.now) + end + + expect(subject).to be_within(0.5).of(7.5.minutes.seconds) + end +end diff --git a/spec/lib/gitlab/background_migration/backfill_environment_id_deployment_merge_requests_spec.rb b/spec/lib/gitlab/background_migration/backfill_environment_id_deployment_merge_requests_spec.rb index c3bb975727b..34ac70071bb 100644 --- a/spec/lib/gitlab/background_migration/backfill_environment_id_deployment_merge_requests_spec.rb +++ b/spec/lib/gitlab/background_migration/backfill_environment_id_deployment_merge_requests_spec.rb @@ -32,7 +32,7 @@ describe Gitlab::BackgroundMigration::BackfillEnvironmentIdDeploymentMergeReques expect(deployment_merge_requests.where(environment_id: nil).count).to eq(3) - migration.perform(1, mr.id) + migration.backfill_range(1, mr.id) expect(deployment_merge_requests.where(environment_id: nil).count).to be_zero expect(deployment_merge_requests.count).to eq(2) diff --git a/spec/lib/gitlab/background_migration/backfill_snippet_repositories_spec.rb b/spec/lib/gitlab/background_migration/backfill_snippet_repositories_spec.rb index dcbf8d12f35..27ae60eb278 100644 --- a/spec/lib/gitlab/background_migration/backfill_snippet_repositories_spec.rb +++ b/spec/lib/gitlab/background_migration/backfill_snippet_repositories_spec.rb @@ -11,13 +11,14 @@ describe Gitlab::BackgroundMigration::BackfillSnippetRepositories, :migration, s let(:user_state) { 'active' } let(:ghost) { false } let(:user_type) { nil } + let(:user_name) { 'Test' } let!(:user) do users.create(id: 1, email: 'user@example.com', projects_limit: 10, username: 'test', - name: 'Test', + name: user_name, state: user_state, ghost: ghost, last_activity_on: 1.minute.ago, @@ -70,6 +71,17 @@ describe Gitlab::BackgroundMigration::BackfillSnippetRepositories, :migration, s end end + shared_examples 'migration_bot user commits files' do + it do + subject + + last_commit = raw_repository(snippet).commit + + expect(last_commit.author_name).to eq migration_bot.name + expect(last_commit.author_email).to eq migration_bot.email + end + end + shared_examples 'commits the file to the repository' do context 'when author can update snippet and use git' do it 'creates the repository and commit the file' do @@ -88,17 +100,6 @@ describe Gitlab::BackgroundMigration::BackfillSnippetRepositories, :migration, s end context 'when author cannot update snippet or use git' do - shared_examples 'migration_bot user commits files' do - it do - subject - - last_commit = raw_repository(snippet).commit - - expect(last_commit.author_name).to eq migration_bot.name - expect(last_commit.author_email).to eq migration_bot.email - end - end - context 'when user is blocked' do let(:user_state) { 'blocked' } @@ -219,6 +220,82 @@ describe Gitlab::BackgroundMigration::BackfillSnippetRepositories, :migration, s end end end + + context 'when snippet content size is higher than the existing limit' do + let(:limit) { 15 } + let(:content) { 'a' * (limit + 1) } + let(:snippet) { snippet_without_repo } + let(:ids) { [snippet.id, snippet.id] } + + before do + allow(Gitlab::CurrentSettings).to receive(:snippet_size_limit).and_return(limit) + end + + it_behaves_like 'migration_bot user commits files' + end + + context 'when user name is invalid' do + let(:user_name) { '.' } + let!(:snippet) { snippets.create(id: 4, type: 'PersonalSnippet', author_id: user.id, file_name: file_name, content: content) } + let(:ids) { [4, 4] } + + after do + raw_repository(snippet).remove + end + + it_behaves_like 'migration_bot user commits files' + end + + context 'when both user name and snippet file_name are invalid' do + let(:user_name) { '.' } + let!(:other_user) do + users.create(id: 2, + email: 'user2@example.com', + projects_limit: 10, + username: 'test2', + name: 'Test2', + state: user_state, + ghost: ghost, + last_activity_on: 1.minute.ago, + user_type: user_type, + confirmed_at: 1.day.ago) + end + let!(:invalid_snippet) { snippets.create(id: 4, type: 'PersonalSnippet', author_id: user.id, file_name: '.', content: content) } + let!(:snippet) { snippets.create(id: 5, type: 'PersonalSnippet', author_id: other_user.id, file_name: file_name, content: content) } + let(:ids) { [4, 5] } + + after do + raw_repository(snippet).remove + raw_repository(invalid_snippet).remove + end + + it 'updates the file_name only when it is invalid' do + subject + + expect(blob_at(invalid_snippet, 'snippetfile1.txt')).to be + expect(blob_at(snippet, file_name)).to be + end + + it_behaves_like 'migration_bot user commits files' do + let(:snippet) { invalid_snippet } + end + + it 'does not alter the commit author in subsequent migrations' do + subject + + last_commit = raw_repository(snippet).commit + + expect(last_commit.author_name).to eq other_user.name + expect(last_commit.author_email).to eq other_user.email + end + + it "increases the number of retries temporarily from #{described_class::MAX_RETRIES} to #{described_class::MAX_RETRIES + 1}" do + expect(service).to receive(:create_commit).with(Snippet.find(invalid_snippet.id)).exactly(described_class::MAX_RETRIES + 1).times.and_call_original + expect(service).to receive(:create_commit).with(Snippet.find(snippet.id)).once.and_call_original + + subject + end + end end def blob_at(snippet, path) diff --git a/spec/lib/gitlab/ci/config/entry/reports_spec.rb b/spec/lib/gitlab/ci/config/entry/reports_spec.rb index b2dbbbf59ac..8c6c91d919e 100644 --- a/spec/lib/gitlab/ci/config/entry/reports_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/reports_spec.rb @@ -48,6 +48,7 @@ describe Gitlab::Ci::Config::Entry::Reports do :cobertura | 'cobertura-coverage.xml' :terraform | 'tfplan.json' :accessibility | 'gl-accessibility.json' + :cluster_applications | 'gl-cluster-applications.json' end with_them do diff --git a/spec/lib/gitlab/git/attributes_parser_spec.rb b/spec/lib/gitlab/git/attributes_parser_spec.rb index 94b7a086e59..45db4acd3ac 100644 --- a/spec/lib/gitlab/git/attributes_parser_spec.rb +++ b/spec/lib/gitlab/git/attributes_parser_spec.rb @@ -75,6 +75,14 @@ describe Gitlab::Git::AttributesParser, :seed_helper do expect(subject.attributes('test.foo')).to eq({}) end end + + context 'when attributes data has binary data' do + let(:data) { "\xFF\xFE*\u0000.\u0000c\u0000s".b } + + it 'returns an empty Hash' do + expect(subject.attributes('test.foo')).to eq({}) + end + end end describe '#patterns' do diff --git a/spec/lib/gitlab/git_access_snippet_spec.rb b/spec/lib/gitlab/git_access_snippet_spec.rb index fb2a7d16665..7ecfa4e519d 100644 --- a/spec/lib/gitlab/git_access_snippet_spec.rb +++ b/spec/lib/gitlab/git_access_snippet_spec.rb @@ -298,6 +298,16 @@ describe Gitlab::GitAccessSnippet do let(:ref) { "refs/heads/snippet/edit-file" } let(:changes) { "#{oldrev} #{newrev} #{ref}" } + shared_examples 'migration bot does not err' do + let(:actor) { migration_bot } + + it 'does not err' do + expect(snippet.repository_size_checker).not_to receive(:above_size_limit?) + + expect { push_access_check }.not_to raise_error + end + end + shared_examples_for 'a push to repository already over the limit' do it 'errs' do expect(snippet.repository_size_checker).to receive(:above_size_limit?).and_return(true) @@ -306,6 +316,8 @@ describe Gitlab::GitAccessSnippet do push_access_check end.to raise_error(described_class::ForbiddenError, /Your push has been rejected/) end + + it_behaves_like 'migration bot does not err' end shared_examples_for 'a push to repository below the limit' do @@ -318,6 +330,8 @@ describe Gitlab::GitAccessSnippet do expect { push_access_check }.not_to raise_error end + + it_behaves_like 'migration bot does not err' end shared_examples_for 'a push to repository to make it over the limit' do @@ -332,6 +346,8 @@ describe Gitlab::GitAccessSnippet do push_access_check end.to raise_error(described_class::ForbiddenError, /Your push to this repository would cause it to exceed the size limit/) end + + it_behaves_like 'migration bot does not err' end context 'when GIT_OBJECT_DIRECTORY_RELATIVE env var is set' do @@ -350,14 +366,6 @@ describe Gitlab::GitAccessSnippet do it_behaves_like 'a push to repository already over the limit' it_behaves_like 'a push to repository below the limit' it_behaves_like 'a push to repository to make it over the limit' - - context 'when user is migration bot' do - let(:actor) { migration_bot } - - it_behaves_like 'a push to repository already over the limit' - it_behaves_like 'a push to repository below the limit' - it_behaves_like 'a push to repository to make it over the limit' - end end context 'when GIT_OBJECT_DIRECTORY_RELATIVE env var is not set' do @@ -372,14 +380,6 @@ describe Gitlab::GitAccessSnippet do it_behaves_like 'a push to repository already over the limit' it_behaves_like 'a push to repository below the limit' it_behaves_like 'a push to repository to make it over the limit' - - context 'when user is migration bot' do - let(:actor) { migration_bot } - - it_behaves_like 'a push to repository already over the limit' - it_behaves_like 'a push to repository below the limit' - it_behaves_like 'a push to repository to make it over the limit' - end end end diff --git a/spec/lib/gitlab/grape_logging/loggers/cloudflare_logger_spec.rb b/spec/lib/gitlab/grape_logging/loggers/cloudflare_logger_spec.rb new file mode 100644 index 00000000000..922a433d7ac --- /dev/null +++ b/spec/lib/gitlab/grape_logging/loggers/cloudflare_logger_spec.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Gitlab::GrapeLogging::Loggers::CloudflareLogger do + subject { described_class.new } + + describe "#parameters" do + let(:mock_request) { ActionDispatch::Request.new({}) } + let(:start_time) { Time.new(2018, 01, 01) } + + describe 'with no Cloudflare headers' do + it 'returns an empty hash' do + expect(subject.parameters(mock_request, nil)).to eq({}) + end + end + + describe 'with Cloudflare headers' do + before do + mock_request.headers['Cf-Ray'] = SecureRandom.hex + mock_request.headers['Cf-Request-Id'] = SecureRandom.hex + end + + it 'returns the correct duration in seconds' do + data = subject.parameters(mock_request, nil) + + expect(data.keys).to contain_exactly(:cf_ray, :cf_request_id) + end + end + end +end diff --git a/spec/lib/gitlab/graphql/pagination/externally_paginated_array_connection_spec.rb b/spec/lib/gitlab/graphql/pagination/externally_paginated_array_connection_spec.rb index 85a5b1dacc7..11cf14523c2 100644 --- a/spec/lib/gitlab/graphql/pagination/externally_paginated_array_connection_spec.rb +++ b/spec/lib/gitlab/graphql/pagination/externally_paginated_array_connection_spec.rb @@ -19,6 +19,20 @@ describe Gitlab::Graphql::Pagination::ExternallyPaginatedArrayConnection do it_behaves_like 'connection with paged nodes' do let(:paged_nodes_size) { values.size } end + + context 'when after or before is specified, they are ignored' do + # after and before are not used to filter the array, as they + # were already used to directly fetch the external array + it_behaves_like 'connection with paged nodes' do + let(:arguments) { { after: next_cursor } } + let(:paged_nodes_size) { values.size } + end + + it_behaves_like 'connection with paged nodes' do + let(:arguments) { { before: prev_cursor } } + let(:paged_nodes_size) { values.size } + end + end end describe '#start_cursor' do diff --git a/spec/lib/gitlab/import_export/all_models.yml b/spec/lib/gitlab/import_export/all_models.yml index ead71631e33..9e822ad51c2 100644 --- a/spec/lib/gitlab/import_export/all_models.yml +++ b/spec/lib/gitlab/import_export/all_models.yml @@ -11,6 +11,7 @@ issues: - resource_label_events - resource_weight_events - resource_milestone_events +- resource_state_events - sent_notifications - sentry_issue - label_links @@ -119,6 +120,7 @@ merge_requests: - notes - resource_label_events - resource_milestone_events +- resource_state_events - label_links - labels - last_edited_by diff --git a/spec/lib/gitlab/import_export/design_repo_restorer_spec.rb b/spec/lib/gitlab/import_export/design_repo_restorer_spec.rb new file mode 100644 index 00000000000..5662b8af280 --- /dev/null +++ b/spec/lib/gitlab/import_export/design_repo_restorer_spec.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Gitlab::ImportExport::DesignRepoRestorer do + include GitHelpers + + describe 'bundle a design Git repo' do + let(:user) { create(:user) } + let!(:project_with_design_repo) { create(:project, :design_repo) } + let!(:project) { create(:project) } + let(:export_path) { "#{Dir.tmpdir}/project_tree_saver_spec" } + let(:shared) { project.import_export_shared } + let(:bundler) { Gitlab::ImportExport::DesignRepoSaver.new(project: project_with_design_repo, shared: shared) } + let(:bundle_path) { File.join(shared.export_path, Gitlab::ImportExport.design_repo_bundle_filename) } + let(:restorer) do + described_class.new(path_to_bundle: bundle_path, + shared: shared, + project: project) + end + + before do + allow_next_instance_of(Gitlab::ImportExport) do |instance| + allow(instance).to receive(:storage_path).and_return(export_path) + end + + bundler.save + end + + after do + FileUtils.rm_rf(export_path) + Gitlab::GitalyClient::StorageSettings.allow_disk_access do + FileUtils.rm_rf(project_with_design_repo.design_repository.path_to_repo) + FileUtils.rm_rf(project.design_repository.path_to_repo) + end + end + + it 'restores the repo successfully' do + expect(restorer.restore).to eq(true) + end + end +end diff --git a/spec/lib/gitlab/import_export/design_repo_saver_spec.rb b/spec/lib/gitlab/import_export/design_repo_saver_spec.rb new file mode 100644 index 00000000000..bff48e8b52a --- /dev/null +++ b/spec/lib/gitlab/import_export/design_repo_saver_spec.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Gitlab::ImportExport::DesignRepoSaver do + describe 'bundle a design Git repo' do + let_it_be(:user) { create(:user) } + let_it_be(:design) { create(:design, :with_file, versions_count: 1) } + let!(:project) { create(:project, :design_repo) } + let(:export_path) { "#{Dir.tmpdir}/project_tree_saver_spec" } + let(:shared) { project.import_export_shared } + let(:design_bundler) { described_class.new(project: project, shared: shared) } + + before do + project.add_maintainer(user) + allow_next_instance_of(Gitlab::ImportExport) do |instance| + allow(instance).to receive(:storage_path).and_return(export_path) + end + end + + after do + FileUtils.rm_rf(export_path) + end + + it 'bundles the repo successfully' do + expect(design_bundler.save).to be true + end + + context 'when the repo is empty' do + let!(:project) { create(:project) } + + it 'bundles the repo successfully' do + expect(design_bundler.save).to be true + end + end + end +end diff --git a/spec/lib/gitlab/import_export/import_test_coverage_spec.rb b/spec/lib/gitlab/import_export/import_test_coverage_spec.rb index 335b0031147..038b95809b4 100644 --- a/spec/lib/gitlab/import_export/import_test_coverage_spec.rb +++ b/spec/lib/gitlab/import_export/import_test_coverage_spec.rb @@ -53,22 +53,15 @@ describe 'Test coverage of the Project Import' do ].freeze # A list of JSON fixture files we use to test Import. - # Note that we use separate fixture to test ee-only features. # Most of the relations are present in `complex/project.json` # which is our main fixture. - PROJECT_JSON_FIXTURES_EE = - if Gitlab.ee? - ['ee/spec/fixtures/lib/gitlab/import_export/designs/project.json'].freeze - else - [] - end - PROJECT_JSON_FIXTURES = [ 'spec/fixtures/lib/gitlab/import_export/complex/project.json', 'spec/fixtures/lib/gitlab/import_export/group/project.json', 'spec/fixtures/lib/gitlab/import_export/light/project.json', - 'spec/fixtures/lib/gitlab/import_export/milestone-iid/project.json' - ].freeze + PROJECT_JSON_FIXTURES_EE + 'spec/fixtures/lib/gitlab/import_export/milestone-iid/project.json', + 'spec/fixtures/lib/gitlab/import_export/designs/project.json' + ].freeze it 'ensures that all imported/exported relations are present in test JSONs' do not_tested_relations = (relations_from_config - tested_relations) - MUTED_RELATIONS diff --git a/spec/lib/gitlab/import_export/importer_spec.rb b/spec/lib/gitlab/import_export/importer_spec.rb index 14e643f86c0..60179146416 100644 --- a/spec/lib/gitlab/import_export/importer_spec.rb +++ b/spec/lib/gitlab/import_export/importer_spec.rb @@ -51,7 +51,8 @@ describe Gitlab::ImportExport::Importer do Gitlab::ImportExport::UploadsRestorer, Gitlab::ImportExport::LfsRestorer, Gitlab::ImportExport::StatisticsRestorer, - Gitlab::ImportExport::SnippetsRepoRestorer + Gitlab::ImportExport::SnippetsRepoRestorer, + Gitlab::ImportExport::DesignRepoRestorer ].each do |restorer| it "calls the #{restorer}" do fake_restorer = double(restorer.to_s) diff --git a/spec/lib/gitlab/import_export/project/tree_restorer_spec.rb b/spec/lib/gitlab/import_export/project/tree_restorer_spec.rb index ecb1ed08260..58589a7bbbe 100644 --- a/spec/lib/gitlab/import_export/project/tree_restorer_spec.rb +++ b/spec/lib/gitlab/import_export/project/tree_restorer_spec.rb @@ -8,6 +8,7 @@ end describe Gitlab::ImportExport::Project::TreeRestorer do include ImportExport::CommonUtil + using RSpec::Parameterized::TableSyntax let(:shared) { project.import_export_shared } @@ -987,6 +988,69 @@ describe Gitlab::ImportExport::Project::TreeRestorer do end end end + + context 'JSON with design management data' do + let_it_be(:user) { create(:admin, email: 'user_1@gitlabexample.com') } + let_it_be(:second_user) { create(:user, email: 'user_2@gitlabexample.com') } + let_it_be(:project) do + create(:project, :builds_disabled, :issues_disabled, + { name: 'project', path: 'project' }) + end + let(:shared) { project.import_export_shared } + let(:project_tree_restorer) { described_class.new(user: user, shared: shared, project: project) } + + subject(:restored_project_json) { project_tree_restorer.restore } + + before do + setup_import_export_config('designs') + restored_project_json + end + + it_behaves_like 'restores project successfully', issues: 2 + + it 'restores project associations correctly' do + expect(project.designs.size).to eq(7) + end + + describe 'restores issue associations correctly' do + let(:issue) { project.issues.offset(index).first } + + where(:index, :design_filenames, :version_shas, :events, :author_emails) do + 0 | %w[chirrido3.jpg jonathan_richman.jpg mariavontrap.jpeg] | %w[27702d08f5ee021ae938737f84e8fe7c38599e85 9358d1bac8ff300d3d2597adaa2572a20f7f8703 e1a4a501bcb42f291f84e5d04c8f927821542fb6] | %w[creation creation creation modification modification deletion] | %w[user_1@gitlabexample.com user_1@gitlabexample.com user_2@gitlabexample.com] + 1 | ['1 (1).jpeg', '2099743.jpg', 'a screenshot (1).jpg', 'chirrido3.jpg'] | %w[73f871b4c8c1d65c62c460635e023179fb53abc4 8587e78ab6bda3bc820a9f014c3be4a21ad4fcc8 c9b5f067f3e892122a4b12b0a25a8089192f3ac8] | %w[creation creation creation creation modification] | %w[user_1@gitlabexample.com user_2@gitlabexample.com user_2@gitlabexample.com] + end + + with_them do + it do + expect(issue.designs.pluck(:filename)).to contain_exactly(*design_filenames) + expect(issue.design_versions.pluck(:sha)).to contain_exactly(*version_shas) + expect(issue.design_versions.flat_map(&:actions).map(&:event)).to contain_exactly(*events) + expect(issue.design_versions.map(&:author).map(&:email)).to contain_exactly(*author_emails) + end + end + end + + describe 'restores design version associations correctly' do + let(:project_designs) { project.designs.reorder(:filename, :issue_id) } + let(:design) { project_designs.offset(index).first } + + where(:index, :version_shas) do + 0 | %w[73f871b4c8c1d65c62c460635e023179fb53abc4 c9b5f067f3e892122a4b12b0a25a8089192f3ac8] + 1 | %w[73f871b4c8c1d65c62c460635e023179fb53abc4] + 2 | %w[c9b5f067f3e892122a4b12b0a25a8089192f3ac8] + 3 | %w[27702d08f5ee021ae938737f84e8fe7c38599e85 9358d1bac8ff300d3d2597adaa2572a20f7f8703 e1a4a501bcb42f291f84e5d04c8f927821542fb6] + 4 | %w[8587e78ab6bda3bc820a9f014c3be4a21ad4fcc8] + 5 | %w[27702d08f5ee021ae938737f84e8fe7c38599e85 e1a4a501bcb42f291f84e5d04c8f927821542fb6] + 6 | %w[27702d08f5ee021ae938737f84e8fe7c38599e85] + end + + with_them do + it do + expect(design.versions.pluck(:sha)).to contain_exactly(*version_shas) + end + end + end + end end context 'enable ndjson import' do diff --git a/spec/lib/gitlab/import_export/project/tree_saver_spec.rb b/spec/lib/gitlab/import_export/project/tree_saver_spec.rb index 8adc360026d..b9bfe253f10 100644 --- a/spec/lib/gitlab/import_export/project/tree_saver_spec.rb +++ b/spec/lib/gitlab/import_export/project/tree_saver_spec.rb @@ -168,6 +168,28 @@ describe Gitlab::ImportExport::Project::TreeSaver do it 'has issue resource label events' do expect(subject.first['resource_label_events']).not_to be_empty end + + it 'saves the issue designs correctly' do + expect(subject.first['designs'].size).to eq(1) + end + + it 'saves the issue design notes correctly' do + expect(subject.first['designs'].first['notes']).not_to be_empty + end + + it 'saves the issue design versions correctly' do + issue_json = subject.first + actions = issue_json['design_versions'].flat_map { |v| v['actions'] } + + expect(issue_json['design_versions'].size).to eq(2) + issue_json['design_versions'].each do |version| + expect(version['author_id']).to be_kind_of(Integer) + end + expect(actions.size).to eq(2) + actions.each do |action| + expect(action['design']).to be_present + end + end end context 'with ci_pipelines' do @@ -442,6 +464,9 @@ describe Gitlab::ImportExport::Project::TreeSaver do board = create(:board, project: project, name: 'TestBoard') create(:list, board: board, position: 0, label: project_label) + design = create(:design, :with_file, versions_count: 2, issue: issue) + create(:diff_note_on_design, noteable: design, project: project, author: user) + project end end diff --git a/spec/lib/gitlab/kubernetes/network_policy_spec.rb b/spec/lib/gitlab/kubernetes/network_policy_spec.rb new file mode 100644 index 00000000000..87ed922e099 --- /dev/null +++ b/spec/lib/gitlab/kubernetes/network_policy_spec.rb @@ -0,0 +1,224 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Gitlab::Kubernetes::NetworkPolicy do + let(:policy) do + described_class.new( + name: name, + namespace: namespace, + creation_timestamp: '2020-04-14T00:08:30Z', + pod_selector: pod_selector, + policy_types: %w(Ingress Egress), + ingress: ingress, + egress: egress + ) + end + + let(:name) { 'example-name' } + let(:namespace) { 'example-namespace' } + let(:pod_selector) { { matchLabels: { role: 'db' } } } + + let(:ingress) do + [ + { + from: [ + { namespaceSelector: { matchLabels: { project: 'myproject' } } } + ] + } + ] + end + + let(:egress) do + [ + { + ports: [{ port: 5978 }] + } + ] + end + + describe '.from_yaml' do + let(:manifest) do + <<-POLICY +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: example-name + namespace: example-namespace +spec: + podSelector: + matchLabels: + role: db + policyTypes: + - Ingress + ingress: + - from: + - namespaceSelector: + matchLabels: + project: myproject + POLICY + end + let(:resource) do + ::Kubeclient::Resource.new( + metadata: { name: name, namespace: namespace }, + spec: { podSelector: pod_selector, policyTypes: %w(Ingress), ingress: ingress, egress: nil } + ) + end + + subject { Gitlab::Kubernetes::NetworkPolicy.from_yaml(manifest)&.generate } + + it { is_expected.to eq(resource) } + + context 'with nil manifest' do + let(:manifest) { nil } + + it { is_expected.to be_nil } + end + + context 'with invalid manifest' do + let(:manifest) { "\tfoo: bar" } + + it { is_expected.to be_nil } + end + + context 'with manifest without metadata' do + let(:manifest) do + <<-POLICY +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +spec: + podSelector: + matchLabels: + role: db + policyTypes: + - Ingress + ingress: + - from: + - namespaceSelector: + matchLabels: + project: myproject + POLICY + end + + it { is_expected.to be_nil } + end + + context 'with manifest without spec' do + let(:manifest) do + <<-POLICY +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: example-name + namespace: example-namespace + POLICY + end + + it { is_expected.to be_nil } + end + + context 'with disallowed class' do + let(:manifest) do + <<-POLICY +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: example-name + namespace: example-namespace + creationTimestamp: 2020-04-14T00:08:30Z +spec: + podSelector: + matchLabels: + role: db + policyTypes: + - Ingress + ingress: + - from: + - namespaceSelector: + matchLabels: + project: myproject + POLICY + end + + it { is_expected.to be_nil } + end + end + + describe '.from_resource' do + let(:resource) do + ::Kubeclient::Resource.new( + metadata: { name: name, namespace: namespace, creationTimestamp: '2020-04-14T00:08:30Z', resourceVersion: '4990' }, + spec: { podSelector: pod_selector, policyTypes: %w(Ingress), ingress: ingress, egress: nil } + ) + end + let(:generated_resource) do + ::Kubeclient::Resource.new( + metadata: { name: name, namespace: namespace }, + spec: { podSelector: pod_selector, policyTypes: %w(Ingress), ingress: ingress, egress: nil } + ) + end + + subject { Gitlab::Kubernetes::NetworkPolicy.from_resource(resource)&.generate } + + it { is_expected.to eq(generated_resource) } + + context 'with nil resource' do + let(:resource) { nil } + + it { is_expected.to be_nil } + end + + context 'with resource without metadata' do + let(:resource) do + ::Kubeclient::Resource.new( + spec: { podSelector: pod_selector, policyTypes: %w(Ingress), ingress: ingress, egress: nil } + ) + end + + it { is_expected.to be_nil } + end + + context 'with resource without spec' do + let(:resource) do + ::Kubeclient::Resource.new( + metadata: { name: name, namespace: namespace, uid: '128cf288-7de4-11ea-aceb-42010a800089', resourceVersion: '4990' } + ) + end + + it { is_expected.to be_nil } + end + end + + describe '#generate' do + let(:resource) do + ::Kubeclient::Resource.new( + metadata: { name: name, namespace: namespace }, + spec: { podSelector: pod_selector, policyTypes: %w(Ingress Egress), ingress: ingress, egress: egress } + ) + end + + subject { policy.generate } + + it { is_expected.to eq(resource) } + end + + describe '#as_json' do + let(:json_policy) do + { + name: name, + namespace: namespace, + creation_timestamp: '2020-04-14T00:08:30Z', + manifest: YAML.dump( + { + metadata: { name: name, namespace: namespace }, + spec: { podSelector: pod_selector, policyTypes: %w(Ingress Egress), ingress: ingress, egress: egress } + } + ) + } + end + + subject { policy.as_json } + + it { is_expected.to eq(json_policy) } + end +end diff --git a/spec/lib/gitlab/logging/cloudflare_helper_spec.rb b/spec/lib/gitlab/logging/cloudflare_helper_spec.rb new file mode 100644 index 00000000000..8585943be3a --- /dev/null +++ b/spec/lib/gitlab/logging/cloudflare_helper_spec.rb @@ -0,0 +1,52 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Gitlab::Logging::CloudflareHelper do + let(:helper) do + Class.new do + include Gitlab::Logging::CloudflareHelper + end.new + end + + describe '#store_cloudflare_headers!' do + let(:payload) { {} } + let(:env) { {} } + let(:request) { ActionDispatch::Request.new(env) } + + before do + request.headers.merge!(headers) + end + + context 'with normal headers' do + let(:headers) { { 'Cf-Ray' => SecureRandom.hex, 'Cf-Request-Id' => SecureRandom.hex } } + + it 'adds Cf-Ray-Id and Cf-Request-Id' do + helper.store_cloudflare_headers!(payload, request) + + expect(payload[:cf_ray]).to eq(headers['Cf-Ray']) + expect(payload[:cf_request_id]).to eq(headers['Cf-Request-Id']) + end + end + + context 'with header values with long strings' do + let(:headers) { { 'Cf-Ray' => SecureRandom.hex(33), 'Cf-Request-Id' => SecureRandom.hex(33) } } + + it 'filters invalid header values' do + helper.store_cloudflare_headers!(payload, request) + + expect(payload.keys).not_to include(:cf_ray, :cf_request_id) + end + end + + context 'with header values with non-alphanumeric characters' do + let(:headers) { { 'Cf-Ray' => "Bad\u0000ray", 'Cf-Request-Id' => "Bad\u0000req" } } + + it 'filters invalid header values' do + helper.store_cloudflare_headers!(payload, request) + + expect(payload.keys).not_to include(:cf_ray, :cf_request_id) + end + end + end +end diff --git a/spec/lib/gitlab/lograge/custom_options_spec.rb b/spec/lib/gitlab/lograge/custom_options_spec.rb index 48d06283b7a..3c014ae618b 100644 --- a/spec/lib/gitlab/lograge/custom_options_spec.rb +++ b/spec/lib/gitlab/lograge/custom_options_spec.rb @@ -19,7 +19,12 @@ describe Gitlab::Lograge::CustomOptions do 1, 2, 'transaction_id', - { params: params, user_id: 'test' } + { + params: params, + user_id: 'test', + cf_ray: SecureRandom.hex, + cf_request_id: SecureRandom.hex + } ) end @@ -46,5 +51,10 @@ describe Gitlab::Lograge::CustomOptions do it 'adds the user id' do expect(subject[:user_id]).to eq('test') end + + it 'adds Cloudflare headers' do + expect(subject[:cf_ray]).to eq(event.payload[:cf_ray]) + expect(subject[:cf_request_id]).to eq(event.payload[:cf_request_id]) + end end end diff --git a/spec/lib/gitlab/url_builder_spec.rb b/spec/lib/gitlab/url_builder_spec.rb index 71ffa4a00a1..66826bcb3b1 100644 --- a/spec/lib/gitlab/url_builder_spec.rb +++ b/spec/lib/gitlab/url_builder_spec.rb @@ -25,6 +25,7 @@ describe Gitlab::UrlBuilder do :project_snippet | ->(snippet) { "/#{snippet.project.full_path}/snippets/#{snippet.id}" } :project_wiki | ->(wiki) { "/#{wiki.container.full_path}/-/wikis/home" } :ci_build | ->(build) { "/#{build.project.full_path}/-/jobs/#{build.id}" } + :design | ->(design) { "/#{design.project.full_path}/-/design_management/designs/#{design.id}/raw_image" } :group | ->(group) { "/groups/#{group.full_path}" } :group_milestone | ->(milestone) { "/groups/#{milestone.group.full_path}/-/milestones/#{milestone.iid}" } @@ -95,6 +96,16 @@ describe Gitlab::UrlBuilder do end end + context 'when passing a DesignManagement::Design' do + let(:design) { build_stubbed(:design) } + + it 'uses the given ref and size in the URL' do + url = subject.build(design, ref: 'feature', size: 'small') + + expect(url).to eq "#{Settings.gitlab['url']}/#{design.project.full_path}/-/design_management/designs/#{design.id}/feature/resized_image/small" + end + end + context 'when passing an unsupported class' do let(:object) { Object.new } diff --git a/spec/lib/gitlab/usage_data_counters/designs_counter_spec.rb b/spec/lib/gitlab/usage_data_counters/designs_counter_spec.rb new file mode 100644 index 00000000000..deaf7ebc7f3 --- /dev/null +++ b/spec/lib/gitlab/usage_data_counters/designs_counter_spec.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Gitlab::UsageDataCounters::DesignsCounter do + it_behaves_like 'a redis usage counter', 'Designs', :create + it_behaves_like 'a redis usage counter', 'Designs', :update + it_behaves_like 'a redis usage counter', 'Designs', :delete + + it_behaves_like 'a redis usage counter with totals', :design_management_designs, + create: 5, + update: 3, + delete: 2 +end diff --git a/spec/lib/gitlab/usage_data_counters/web_ide_counter_spec.rb b/spec/lib/gitlab/usage_data_counters/web_ide_counter_spec.rb index 920d1d23567..ee6224eca68 100644 --- a/spec/lib/gitlab/usage_data_counters/web_ide_counter_spec.rb +++ b/spec/lib/gitlab/usage_data_counters/web_ide_counter_spec.rb @@ -26,6 +26,10 @@ describe Gitlab::UsageDataCounters::WebIdeCounter, :clean_gitlab_redis_shared_st it_behaves_like 'counter examples', 'views' end + describe 'terminals counter' do + it_behaves_like 'counter examples', 'terminals' + end + describe 'previews counter' do let(:setting_enabled) { true } @@ -56,6 +60,7 @@ describe Gitlab::UsageDataCounters::WebIdeCounter, :clean_gitlab_redis_shared_st merge_requests = 3 views = 2 previews = 4 + terminals = 1 before do stub_application_setting(web_ide_clientside_preview_enabled: true) @@ -64,6 +69,7 @@ describe Gitlab::UsageDataCounters::WebIdeCounter, :clean_gitlab_redis_shared_st merge_requests.times { described_class.increment_merge_requests_count } views.times { described_class.increment_views_count } previews.times { described_class.increment_previews_count } + terminals.times { described_class.increment_terminals_count } end it 'can report all totals' do @@ -71,7 +77,8 @@ describe Gitlab::UsageDataCounters::WebIdeCounter, :clean_gitlab_redis_shared_st web_ide_commits: commits, web_ide_views: views, web_ide_merge_requests: merge_requests, - web_ide_previews: previews + web_ide_previews: previews, + web_ide_terminals: terminals ) end end diff --git a/spec/lib/system_check/app/hashed_storage_all_projects_check_spec.rb b/spec/lib/system_check/app/hashed_storage_all_projects_check_spec.rb new file mode 100644 index 00000000000..e5e7f6a4450 --- /dev/null +++ b/spec/lib/system_check/app/hashed_storage_all_projects_check_spec.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +require 'spec_helper' +require 'rake_helper' + +describe SystemCheck::App::HashedStorageAllProjectsCheck do + before do + silence_output + end + + describe '#check?' do + it 'fails when at least one project is in legacy storage' do + create(:project, :legacy_storage) + + expect(subject.check?).to be_falsey + end + + it 'succeeds when all projects are in hashed storage' do + create(:project) + + expect(subject.check?).to be_truthy + end + end +end diff --git a/spec/lib/system_check/app/hashed_storage_enabled_check_spec.rb b/spec/lib/system_check/app/hashed_storage_enabled_check_spec.rb new file mode 100644 index 00000000000..d5a0014b791 --- /dev/null +++ b/spec/lib/system_check/app/hashed_storage_enabled_check_spec.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +require 'spec_helper' +require 'rake_helper' + +describe SystemCheck::App::HashedStorageEnabledCheck do + before do + silence_output + end + + describe '#check?' do + it 'fails when hashed storage is disabled' do + stub_application_setting(hashed_storage_enabled: false) + + expect(subject.check?).to be_falsey + end + + it 'succeeds when hashed storage is enabled' do + stub_application_setting(hashed_storage_enabled: true) + + expect(subject.check?).to be_truthy + end + end +end |