diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-05-17 19:05:49 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-05-17 19:05:49 +0300 |
commit | 43a25d93ebdabea52f99b05e15b06250cd8f07d7 (patch) | |
tree | dceebdc68925362117480a5d672bcff122fb625b /spec/serializers | |
parent | 20c84b99005abd1c82101dfeff264ac50d2df211 (diff) |
Add latest changes from gitlab-org/gitlab@16-0-stable-eev16.0.0-rc42
Diffstat (limited to 'spec/serializers')
44 files changed, 1135 insertions, 257 deletions
diff --git a/spec/serializers/access_token_entity_base_spec.rb b/spec/serializers/access_token_entity_base_spec.rb index e14a07a346a..8a92a53d0c1 100644 --- a/spec/serializers/access_token_entity_base_spec.rb +++ b/spec/serializers/access_token_entity_base_spec.rb @@ -16,7 +16,7 @@ RSpec.describe AccessTokenEntityBase do revoked: false, created_at: token.created_at, scopes: token.scopes, - expires_at: nil, + expires_at: token.expires_at.iso8601, expired: false, expires_soon: false )) diff --git a/spec/serializers/admin/abuse_report_details_entity_spec.rb b/spec/serializers/admin/abuse_report_details_entity_spec.rb new file mode 100644 index 00000000000..0e5e6a62ce1 --- /dev/null +++ b/spec/serializers/admin/abuse_report_details_entity_spec.rb @@ -0,0 +1,158 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Admin::AbuseReportDetailsEntity, feature_category: :insider_threat do + include Gitlab::Routing + + let(:report) { build_stubbed(:abuse_report) } + let(:user) { report.user } + let(:reporter) { report.reporter } + let!(:other_report) { create(:abuse_report, user: user) } # rubocop:disable RSpec/FactoryBot/AvoidCreate + + let(:entity) do + described_class.new(report) + end + + describe '#as_json' do + subject(:entity_hash) { entity.as_json } + + it 'exposes correct attributes' do + expect(entity_hash.keys).to include( + :user, + :reporter, + :report, + :actions + ) + end + + it 'correctly exposes `user`', :aggregate_failures do + user_hash = entity_hash[:user] + + expect(user_hash.keys).to match_array([ + :name, + :username, + :avatar_url, + :email, + :created_at, + :last_activity_on, + :path, + :admin_path, + :plan, + :verification_state, + :other_reports, + :most_used_ip, + :last_sign_in_ip, + :snippets_count, + :groups_count, + :notes_count + ]) + + expect(user_hash[:verification_state].keys).to match_array([ + :email, + :phone, + :credit_card + ]) + + expect(user_hash[:other_reports][0].keys).to match_array([ + :created_at, + :category, + :report_path + ]) + end + + describe 'users plan' do + it 'does not include the plan' do + expect(entity_hash[:user][:plan]).to be_nil + end + + context 'when on .com', :saas, if: Gitlab.ee? do + before do + stub_ee_application_setting(should_check_namespace_plan: true) + create(:namespace_with_plan, plan: :bronze_plan, owner: user) # rubocop:disable RSpec/FactoryBot/AvoidCreate + end + + it 'includes the plan' do + expect(entity_hash[:user][:plan]).to eq('Bronze') + end + end + end + + describe 'users credit card' do + let(:credit_card_hash) { entity_hash[:user][:credit_card] } + + context 'when the user has no verified credit card' do + it 'does not expose the credit card' do + expect(credit_card_hash).to be_nil + end + end + + context 'when the user does have a verified credit card' do + let!(:credit_card) { build_stubbed(:credit_card_validation, user: user) } + + it 'exposes the credit card' do + expect(credit_card_hash.keys).to match_array([ + :name, + :similar_records_count, + :card_matches_link + ]) + end + + context 'when not on ee', unless: Gitlab.ee? do + it 'does not include the path to the admin card matches page' do + expect(credit_card_hash[:card_matches_link]).to be_nil + end + end + + context 'when on ee', if: Gitlab.ee? do + it 'includes the path to the admin card matches page' do + expect(credit_card_hash[:card_matches_link]).not_to be_nil + end + end + end + end + + it 'correctly exposes `reporter`' do + reporter_hash = entity_hash[:reporter] + + expect(reporter_hash.keys).to match_array([ + :name, + :username, + :avatar_url, + :path + ]) + end + + it 'correctly exposes `report`' do + report_hash = entity_hash[:report] + + expect(report_hash.keys).to match_array([ + :message, + :reported_at, + :category, + :type, + :content, + :url, + :screenshot + ]) + end + + it 'correctly exposes `actions`', :aggregate_failures do + actions_hash = entity_hash[:actions] + + expect(actions_hash.keys).to match_array([ + :user_blocked, + :block_user_path, + :remove_user_and_report_path, + :remove_report_path, + :reported_user, + :redirect_path + ]) + + expect(actions_hash[:reported_user].keys).to match_array([ + :name, + :created_at + ]) + end + end +end diff --git a/spec/serializers/admin/abuse_report_details_serializer_spec.rb b/spec/serializers/admin/abuse_report_details_serializer_spec.rb new file mode 100644 index 00000000000..f22d92a1763 --- /dev/null +++ b/spec/serializers/admin/abuse_report_details_serializer_spec.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Admin::AbuseReportDetailsSerializer, feature_category: :insider_threat do + let_it_be(:resource) { build_stubbed(:abuse_report) } + + subject { described_class.new.represent(resource).keys } + + describe '#represent' do + it 'serializes an abuse report' do + is_expected.to include( + :user, + :reporter, + :report, + :actions + ) + end + end +end diff --git a/spec/serializers/admin/abuse_report_entity_spec.rb b/spec/serializers/admin/abuse_report_entity_spec.rb new file mode 100644 index 00000000000..003d76a172f --- /dev/null +++ b/spec/serializers/admin/abuse_report_entity_spec.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +require "spec_helper" + +RSpec.describe Admin::AbuseReportEntity, feature_category: :insider_threat do + include Gitlab::Routing + + let(:abuse_report) { build_stubbed(:abuse_report) } + + let(:entity) do + described_class.new(abuse_report) + end + + describe '#as_json' do + subject(:entity_hash) { entity.as_json } + + it 'exposes correct attributes' do + expect(entity_hash.keys).to include( + :category, + :created_at, + :updated_at, + :reported_user, + :reporter, + :report_path + ) + end + + it 'correctly exposes `reported user`' do + expect(entity_hash[:reported_user].keys).to match_array([:name]) + end + + it 'correctly exposes `reporter`' do + expect(entity_hash[:reporter].keys).to match_array([:name]) + end + + it 'correctly exposes :report_path' do + expect(entity_hash[:report_path]).to eq admin_abuse_report_path(abuse_report) + end + end +end diff --git a/spec/serializers/admin/abuse_report_serializer_spec.rb b/spec/serializers/admin/abuse_report_serializer_spec.rb new file mode 100644 index 00000000000..a56ef8816b1 --- /dev/null +++ b/spec/serializers/admin/abuse_report_serializer_spec.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +require "spec_helper" + +RSpec.describe Admin::AbuseReportSerializer, feature_category: :insider_threat do + let_it_be(:resource) { build_stubbed(:abuse_report) } + + subject { described_class.new.represent(resource) } + + describe '#represent' do + it 'serializes an abuse report' do + expect(subject[:updated_at]).to eq resource.updated_at + end + + context 'when multiple objects are being serialized' do + let_it_be(:resource) { create_list(:abuse_report, 2) } # rubocop:disable RSpec/FactoryBot/AvoidCreate + + it 'serializers the array of abuse reports' do + expect(subject).not_to be_empty + end + end + end +end diff --git a/spec/serializers/analytics_issue_entity_spec.rb b/spec/serializers/analytics_issue_entity_spec.rb index ca1e0705d77..e86c0d9d883 100644 --- a/spec/serializers/analytics_issue_entity_spec.rb +++ b/spec/serializers/analytics_issue_entity_spec.rb @@ -72,7 +72,7 @@ RSpec.describe AnalyticsIssueEntity do end context 'without subgroup' do - let_it_be(:project) { create(:project, name: 'my project') } + let_it_be(:project) { create(:project) } subject { entity.as_json } @@ -80,14 +80,14 @@ RSpec.describe AnalyticsIssueEntity do end context 'with subgroup' do - let_it_be(:project) { create(:project, :in_subgroup, name: 'my project') } + let_it_be(:project) { create(:project, :in_subgroup) } subject { entity.as_json } it_behaves_like 'generic entity' it 'has URL containing subgroup' do - expect(subject[:url]).to include("#{project.group.parent.name}/#{project.group.name}/my_project/") + expect(subject[:url]).to include("#{project.group.parent.name}/#{project.group.name}/#{project.path}/") end end end diff --git a/spec/serializers/build_details_entity_spec.rb b/spec/serializers/build_details_entity_spec.rb index 916798c669c..86eaf160b38 100644 --- a/spec/serializers/build_details_entity_spec.rb +++ b/spec/serializers/build_details_entity_spec.rb @@ -17,9 +17,7 @@ RSpec.describe BuildDetailsEntity do let(:request) { double('request', project: project) } let(:entity) do - described_class.new(build, request: request, - current_user: user, - project: project) + described_class.new(build, request: request, current_user: user, project: project) end subject { entity.as_json } @@ -69,9 +67,7 @@ RSpec.describe BuildDetailsEntity do end let(:merge_request) do - create(:merge_request, source_project: forked_project, - target_project: project, - source_branch: build.ref) + create(:merge_request, source_project: forked_project, target_project: project, source_branch: build.ref) end it 'contains the needed key value pairs' do @@ -285,7 +281,7 @@ RSpec.describe BuildDetailsEntity do end context 'when the build has non public archive type artifacts' do - let(:build) { create(:ci_build, :artifacts, :non_public_artifacts, pipeline: pipeline) } + let(:build) { create(:ci_build, :artifacts, :with_private_artifacts_config, pipeline: pipeline) } it 'does not expose non public artifacts' do expect(subject.keys).not_to include(:artifact) diff --git a/spec/serializers/ci/codequality_mr_diff_entity_spec.rb b/spec/serializers/ci/codequality_mr_diff_entity_spec.rb index 4f161c36b06..19b872b68db 100644 --- a/spec/serializers/ci/codequality_mr_diff_entity_spec.rb +++ b/spec/serializers/ci/codequality_mr_diff_entity_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Ci::CodequalityMrDiffEntity do +RSpec.describe Ci::CodequalityMrDiffEntity, feature_category: :code_quality do let(:entity) { described_class.new(mr_diff_report) } let(:mr_diff_report) { Gitlab::Ci::Reports::CodequalityMrDiff.new(codequality_report.all_degradations) } let(:codequality_report) { Gitlab::Ci::Reports::CodequalityReports.new } diff --git a/spec/serializers/ci/downloadable_artifact_entity_spec.rb b/spec/serializers/ci/downloadable_artifact_entity_spec.rb index 3142b03581d..66a975e54ab 100644 --- a/spec/serializers/ci/downloadable_artifact_entity_spec.rb +++ b/spec/serializers/ci/downloadable_artifact_entity_spec.rb @@ -18,8 +18,7 @@ RSpec.describe Ci::DownloadableArtifactEntity do context 'when user cannot read job artifact' do let!(:build) do - create(:ci_build, :success, :private_artifacts, - pipeline: pipeline) + create(:ci_build, :success, :private_artifacts, pipeline: pipeline) end it 'returns only artifacts readable by user', :aggregate_failures do diff --git a/spec/serializers/ci/job_entity_spec.rb b/spec/serializers/ci/job_entity_spec.rb index 174d9a0aadb..6dce87a1fc5 100644 --- a/spec/serializers/ci/job_entity_spec.rb +++ b/spec/serializers/ci/job_entity_spec.rb @@ -97,8 +97,7 @@ RSpec.describe Ci::JobEntity do before do project.add_developer(user) - create(:protected_branch, :developers_can_merge, - name: job.ref, project: job.project) + create(:protected_branch, :developers_can_merge, name: job.ref, project: job.project) end it 'contains path to play action' do @@ -114,8 +113,7 @@ RSpec.describe Ci::JobEntity do before do allow(job.project).to receive(:empty_repo?).and_return(false) - create(:protected_branch, :no_one_can_push, - name: job.ref, project: job.project) + create(:protected_branch, :no_one_can_push, name: job.ref, project: job.project) end it 'does not contain path to play action' do diff --git a/spec/serializers/ci/pipeline_entity_spec.rb b/spec/serializers/ci/pipeline_entity_spec.rb index 4df542e3c98..7f232a08622 100644 --- a/spec/serializers/ci/pipeline_entity_spec.rb +++ b/spec/serializers/ci/pipeline_entity_spec.rb @@ -43,10 +43,10 @@ RSpec.describe Ci::PipelineEntity do end it 'contains flags' do - expect(subject).to include :flags - expect(subject[:flags]) - .to include :stuck, :auto_devops, :yaml_errors, - :retryable, :cancelable, :merge_request + expect(subject).to include(:flags) + expect(subject[:flags]).to include( + :stuck, :auto_devops, :yaml_errors, :retryable, :cancelable, :merge_request + ) end end diff --git a/spec/serializers/cluster_application_entity_spec.rb b/spec/serializers/cluster_application_entity_spec.rb deleted file mode 100644 index 1e71e45948c..00000000000 --- a/spec/serializers/cluster_application_entity_spec.rb +++ /dev/null @@ -1,81 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe ClusterApplicationEntity do - describe '#as_json' do - let(:application) { build(:clusters_applications_helm, version: '0.1.1') } - - subject { described_class.new(application).as_json } - - it 'has name' do - expect(subject[:name]).to eq(application.name) - end - - it 'has status' do - expect(subject[:status]).to eq(:not_installable) - end - - it 'has version' do - expect(subject[:version]).to eq('0.1.1') - end - - it 'has no status_reason' do - expect(subject[:status_reason]).to be_nil - end - - it 'has can_uninstall' do - expect(subject[:can_uninstall]).to be_truthy - end - - context 'non-helm application' do - let(:application) { build(:clusters_applications_runner, version: '0.0.0') } - - it 'has update_available' do - expect(subject[:update_available]).to be_truthy - end - end - - context 'when application is errored' do - let(:application) { build(:clusters_applications_helm, :errored) } - - it 'has corresponded data' do - expect(subject[:status]).to eq(:errored) - expect(subject[:status_reason]).not_to be_nil - expect(subject[:status_reason]).to eq(application.status_reason) - end - end - - context 'for ingress application' do - let(:application) do - build( - :clusters_applications_ingress, - :installed, - external_ip: '111.222.111.222' - ) - end - - it 'includes external_ip' do - expect(subject[:external_ip]).to eq('111.222.111.222') - end - end - - context 'for knative application' do - let(:pages_domain) { create(:pages_domain, :instance_serverless) } - let(:application) { build(:clusters_applications_knative, :installed) } - - before do - create(:serverless_domain_cluster, knative: application, pages_domain: pages_domain) - end - - it 'includes available domains' do - expect(subject[:available_domains].length).to eq(1) - expect(subject[:available_domains].first).to eq(id: pages_domain.id, domain: pages_domain.domain) - end - - it 'includes pages_domain' do - expect(subject[:pages_domain]).to eq(id: pages_domain.id, domain: pages_domain.domain) - end - end - end -end diff --git a/spec/serializers/cluster_entity_spec.rb b/spec/serializers/cluster_entity_spec.rb index 2de27deeffe..ff1a9a4feac 100644 --- a/spec/serializers/cluster_entity_spec.rb +++ b/spec/serializers/cluster_entity_spec.rb @@ -41,19 +41,5 @@ RSpec.describe ClusterEntity do expect(subject[:status_reason]).to be_nil end end - - context 'when no application has been installed' do - let(:cluster) { create(:cluster, :instance) } - - subject { described_class.new(cluster, request: request).as_json[:applications] } - - it 'contains helm as not_installable' do - expect(subject).not_to be_empty - - helm = subject[0] - expect(helm[:name]).to eq('helm') - expect(helm[:status]).to eq(:not_installable) - end - end end end diff --git a/spec/serializers/cluster_serializer_spec.rb b/spec/serializers/cluster_serializer_spec.rb index 7ec6d3c8bb8..cf102e11b90 100644 --- a/spec/serializers/cluster_serializer_spec.rb +++ b/spec/serializers/cluster_serializer_spec.rb @@ -34,13 +34,13 @@ RSpec.describe ClusterSerializer do end it 'serializes attrs correctly' do - is_expected.to contain_exactly(:status, :status_reason, :applications) + is_expected.to contain_exactly(:status, :status_reason) end end context 'when provider type is user' do it 'serializes attrs correctly' do - is_expected.to contain_exactly(:status, :status_reason, :applications) + is_expected.to contain_exactly(:status, :status_reason) end end end diff --git a/spec/serializers/deploy_keys/basic_deploy_key_entity_spec.rb b/spec/serializers/deploy_keys/basic_deploy_key_entity_spec.rb index 7ea72351594..7df6413f416 100644 --- a/spec/serializers/deploy_keys/basic_deploy_key_entity_spec.rb +++ b/spec/serializers/deploy_keys/basic_deploy_key_entity_spec.rb @@ -29,6 +29,7 @@ RSpec.describe DeployKeys::BasicDeployKeyEntity do destroyed_when_orphaned: true, almost_orphaned: false, created_at: deploy_key.created_at, + expires_at: deploy_key.expires_at, updated_at: deploy_key.updated_at, can_edit: false } diff --git a/spec/serializers/deploy_keys/deploy_key_entity_spec.rb b/spec/serializers/deploy_keys/deploy_key_entity_spec.rb index 4302ed3a097..837e30e1343 100644 --- a/spec/serializers/deploy_keys/deploy_key_entity_spec.rb +++ b/spec/serializers/deploy_keys/deploy_key_entity_spec.rb @@ -29,6 +29,7 @@ RSpec.describe DeployKeys::DeployKeyEntity do destroyed_when_orphaned: true, almost_orphaned: false, created_at: deploy_key.created_at, + expires_at: deploy_key.expires_at, updated_at: deploy_key.updated_at, can_edit: false, deploy_keys_projects: [ diff --git a/spec/serializers/diff_file_entity_spec.rb b/spec/serializers/diff_file_entity_spec.rb index fbb45162136..5eee9c34e1e 100644 --- a/spec/serializers/diff_file_entity_spec.rb +++ b/spec/serializers/diff_file_entity_spec.rb @@ -84,8 +84,8 @@ RSpec.describe DiffFileEntity do let(:options) { { conflicts: {} } } it 'calls diff_lines_for_serializer on diff_file' do - # #diff_lines_for_serializer gets called in #fully_expanded? as well so we expect twice - expect(diff_file).to receive(:diff_lines_for_serializer).twice.and_return([]) + # #diff_lines_for_serializer gets called in #fully_expanded? and whitespace_only as well so we expect three calls + expect(diff_file).to receive(:diff_lines_for_serializer).exactly(3).times.and_return([]) expect(subject[:highlighted_diff_lines]).to eq([]) end end diff --git a/spec/serializers/diff_viewer_entity_spec.rb b/spec/serializers/diff_viewer_entity_spec.rb index 53601fcff61..84d2bdceb78 100644 --- a/spec/serializers/diff_viewer_entity_spec.rb +++ b/spec/serializers/diff_viewer_entity_spec.rb @@ -12,10 +12,51 @@ RSpec.describe DiffViewerEntity do let(:diff) { commit.raw_diffs.first } let(:diff_file) { Gitlab::Diff::File.new(diff, diff_refs: diff_refs, repository: repository) } let(:viewer) { diff_file.simple_viewer } + let(:options) { {} } - subject { described_class.new(viewer).as_json } + subject { described_class.new(viewer).as_json(options) } - it 'serializes diff file viewer' do - expect(subject.with_indifferent_access).to match_schema('entities/diff_viewer') + context 'when add_ignore_all_white_spaces is enabled' do + before do + stub_feature_flags(add_ignore_all_white_spaces: true) + end + + it 'serializes diff file viewer' do + expect(subject.with_indifferent_access).to match_schema('entities/diff_viewer') + end + + it 'contains whitespace_only attribute' do + expect(subject.with_indifferent_access).to include(:whitespace_only) + end + + context 'when whitespace_only option is true' do + let(:options) { { whitespace_only: true } } + + it 'returns the whitespace_only attribute true' do + expect(subject.with_indifferent_access[:whitespace_only]).to eq true + end + end + + context 'when whitespace_only option is false' do + let(:options) { { whitespace_only: false } } + + it 'returns the whitespace_only attribute false' do + expect(subject.with_indifferent_access[:whitespace_only]).to eq false + end + end + end + + context 'when add_ignore_all_white_spaces is disabled ' do + before do + stub_feature_flags(add_ignore_all_white_spaces: false) + end + + it 'serializes diff file viewer' do + expect(subject.with_indifferent_access).to match_schema('entities/diff_viewer') + end + + it 'does not contain whitespace_only attribute' do + expect(subject.with_indifferent_access).not_to include(:whitespace_only) + end end end diff --git a/spec/serializers/discussion_diff_file_entity_spec.rb b/spec/serializers/discussion_diff_file_entity_spec.rb index 05438450d78..33c3ebc506f 100644 --- a/spec/serializers/discussion_diff_file_entity_spec.rb +++ b/spec/serializers/discussion_diff_file_entity_spec.rb @@ -32,8 +32,7 @@ RSpec.describe DiscussionDiffFileEntity do end it 'exposes no diff lines' do - expect(subject).not_to include(:highlighted_diff_lines, - :parallel_diff_lines) + expect(subject).not_to include(:highlighted_diff_lines, :parallel_diff_lines) end end end diff --git a/spec/serializers/entity_date_helper_spec.rb b/spec/serializers/entity_date_helper_spec.rb index 5a4571339b3..70094991c09 100644 --- a/spec/serializers/entity_date_helper_spec.rb +++ b/spec/serializers/entity_date_helper_spec.rb @@ -47,8 +47,10 @@ RSpec.describe EntityDateHelper do end describe '#remaining_days_in_words' do + let(:current_time) { Time.utc(2017, 3, 17) } + around do |example| - travel_to(Time.utc(2017, 3, 17)) { example.run } + travel_to(current_time) { example.run } end context 'when less than 31 days remaining' do @@ -74,10 +76,10 @@ RSpec.describe EntityDateHelper do expect(milestone_remaining).to eq("<strong>1</strong> day remaining") end - it 'returns 1 day remaining when queried mid-day' do - travel_back + context 'when queried mid-day' do + let(:current_time) { Time.utc(2017, 3, 17, 13, 10) } - travel_to(Time.utc(2017, 3, 17, 13, 10)) do + it 'returns 1 day remaining' do expect(milestone_remaining).to eq("<strong>1</strong> day remaining") end end diff --git a/spec/serializers/environment_entity_spec.rb b/spec/serializers/environment_entity_spec.rb index cbe32600941..c60bead12c2 100644 --- a/spec/serializers/environment_entity_spec.rb +++ b/spec/serializers/environment_entity_spec.rb @@ -83,37 +83,49 @@ RSpec.describe EnvironmentEntity do end end - context 'metrics disabled' do + context 'when metrics dashboard feature is available' do before do - allow(environment).to receive(:has_metrics?).and_return(false) + stub_feature_flags(remove_monitor_metrics: false) end - it "doesn't expose metrics path" do - expect(subject).not_to include(:metrics_path) - end - end + context 'metrics disabled' do + before do + allow(environment).to receive(:has_metrics?).and_return(false) + end - context 'metrics enabled' do - before do - allow(environment).to receive(:has_metrics?).and_return(true) + it "doesn't expose metrics path" do + expect(subject).not_to include(:metrics_path) + end end - it 'exposes metrics path' do - expect(subject).to include(:metrics_path) + context 'metrics enabled' do + before do + allow(environment).to receive(:has_metrics?).and_return(true) + end + + it 'exposes metrics path' do + expect(subject).to include(:metrics_path) + end end end + it "doesn't expose metrics path" do + expect(subject).not_to include(:metrics_path) + end + context 'with deployment platform' do let(:project) { create(:project, :repository) } let(:environment) { create(:environment, project: project) } context 'when deployment platform is a cluster' do before do - create(:cluster, - :provided_by_gcp, - :project, - environment_scope: '*', - projects: [project]) + create( + :cluster, + :provided_by_gcp, + :project, + environment_scope: '*', + projects: [project] + ) end it 'includes cluster_type' do diff --git a/spec/serializers/environment_serializer_spec.rb b/spec/serializers/environment_serializer_spec.rb index 01d1e47b5bb..c85727a08d8 100644 --- a/spec/serializers/environment_serializer_spec.rb +++ b/spec/serializers/environment_serializer_spec.rb @@ -262,8 +262,9 @@ RSpec.describe EnvironmentSerializer do def create_environment_with_associations(project) create(:environment, project: project).tap do |environment| create(:ci_pipeline, project: project).tap do |pipeline| - create(:ci_build, :manual, project: project, pipeline: pipeline, name: 'stop-action', - environment: environment.name) + create( + :ci_build, :manual, project: project, pipeline: pipeline, name: 'stop-action', environment: environment.name + ) create(:ci_build, :scheduled, project: project, pipeline: pipeline, environment: environment.name).tap do |scheduled_build| diff --git a/spec/serializers/environment_status_entity_spec.rb b/spec/serializers/environment_status_entity_spec.rb index 2ee4e8ade8f..2289b41b828 100644 --- a/spec/serializers/environment_status_entity_spec.rb +++ b/spec/serializers/environment_status_entity_spec.rb @@ -36,7 +36,9 @@ RSpec.describe EnvironmentStatusEntity do it { is_expected.to include(:details) } it { is_expected.to include(:changes) } it { is_expected.to include(:status) } + it { is_expected.to include(:environment_available) } + it { is_expected.not_to include(:retry_url) } it { is_expected.not_to include(:stop_url) } it { is_expected.not_to include(:metrics_url) } it { is_expected.not_to include(:metrics_monitoring_url) } @@ -45,6 +47,7 @@ RSpec.describe EnvironmentStatusEntity do let(:user) { maintainer } it { is_expected.to include(:stop_url) } + it { is_expected.to include(:retry_url) } end context 'when deployment has metrics' do diff --git a/spec/serializers/group_child_entity_spec.rb b/spec/serializers/group_child_entity_spec.rb index 469189c0768..5af704a42da 100644 --- a/spec/serializers/group_child_entity_spec.rb +++ b/spec/serializers/group_child_entity_spec.rb @@ -43,8 +43,7 @@ RSpec.describe GroupChildEntity do describe 'for a project' do let(:object) do - create(:project, :with_avatar, - description: 'Awesomeness') + create(:project, :with_avatar, description: 'Awesomeness') end before do @@ -73,8 +72,7 @@ RSpec.describe GroupChildEntity do describe 'for a group' do let(:description) { 'Awesomeness' } let(:object) do - create(:group, :nested, :with_avatar, - description: description) + create(:group, :nested, :with_avatar, description: description) end before do @@ -171,8 +169,7 @@ RSpec.describe GroupChildEntity do describe 'for a project with external authorization enabled' do let(:object) do - create(:project, :with_avatar, - description: 'Awesomeness') + create(:project, :with_avatar, description: 'Awesomeness') end before do diff --git a/spec/serializers/group_deploy_key_entity_spec.rb b/spec/serializers/group_deploy_key_entity_spec.rb index e6cef2f10b3..c502923db6a 100644 --- a/spec/serializers/group_deploy_key_entity_spec.rb +++ b/spec/serializers/group_deploy_key_entity_spec.rb @@ -25,6 +25,7 @@ RSpec.describe GroupDeployKeyEntity do fingerprint: group_deploy_key.fingerprint, fingerprint_sha256: group_deploy_key.fingerprint_sha256, created_at: group_deploy_key.created_at, + expires_at: group_deploy_key.expires_at, updated_at: group_deploy_key.updated_at, can_edit: false, group_deploy_keys_groups: [ diff --git a/spec/serializers/group_issuable_autocomplete_entity_spec.rb b/spec/serializers/group_issuable_autocomplete_entity_spec.rb index 86ef9dea23b..977239c67da 100644 --- a/spec/serializers/group_issuable_autocomplete_entity_spec.rb +++ b/spec/serializers/group_issuable_autocomplete_entity_spec.rb @@ -4,7 +4,8 @@ require 'spec_helper' RSpec.describe GroupIssuableAutocompleteEntity do let(:group) { build_stubbed(:group) } - let(:project) { build_stubbed(:project, group: group) } + let(:project_namespace) { build_stubbed(:project_namespace) } + let(:project) { build_stubbed(:project, group: group, project_namespace: project_namespace) } let(:issue) { build_stubbed(:issue, project: project) } describe '#represent' do diff --git a/spec/serializers/import/bulk_import_entity_spec.rb b/spec/serializers/import/bulk_import_entity_spec.rb index 3dfc659daf7..f2f8854174a 100644 --- a/spec/serializers/import/bulk_import_entity_spec.rb +++ b/spec/serializers/import/bulk_import_entity_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Import::BulkImportEntity do +RSpec.describe Import::BulkImportEntity, feature_category: :importers do let(:importable_data) do { 'id' => 1, diff --git a/spec/serializers/import/github_failure_entity_spec.rb b/spec/serializers/import/github_failure_entity_spec.rb new file mode 100644 index 00000000000..0de710f22cc --- /dev/null +++ b/spec/serializers/import/github_failure_entity_spec.rb @@ -0,0 +1,319 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Import::GithubFailureEntity, feature_category: :importers do + let(:project) { instance_double(Project, id: 123456, import_url: 'https://github.com/example/repo.git', import_source: 'example/repo') } + let(:source) { 'Gitlab::GithubImport::Importer::PullRequestImporter' } + let(:github_identifiers) { { 'iid' => 2, 'object_type' => 'pull_request', 'title' => 'Implement cool feature' } } + let(:import_failure) do + instance_double( + ImportFailure, + project: project, + exception_class: 'Some class', + exception_message: 'Something went wrong', + source: source, + correlation_id_value: '2ea9c4b8587b6df49f35a3fb703688aa', + external_identifiers: github_identifiers, + created_at: Time.current + ) + end + + let(:failure_details) do + { + exception_class: import_failure.exception_class, + exception_message: import_failure.exception_message, + correlation_id_value: import_failure.correlation_id_value, + source: import_failure.source, + github_identifiers: github_identifiers, + created_at: import_failure.created_at + } + end + + subject(:entity) { described_class.new(import_failure).as_json.with_indifferent_access } + + shared_examples 'import failure entity' do + it 'exposes required fields for import entity' do + expect(entity).to eq( + { + type: import_failure.external_identifiers['object_type'], + title: title, + provider_url: provider_url, + details: failure_details + }.with_indifferent_access + ) + end + end + + it 'exposes correct attributes' do + expect(entity.keys).to match_array(%w[type title provider_url details]) + end + + context 'with `pull_request` failure' do + it_behaves_like 'import failure entity' do + let(:title) { 'Implement cool feature' } + let(:provider_url) { 'https://github.com/example/repo/pull/2' } + end + end + + context 'with `pull_request_merged_by` failure' do + before do + import_failure.external_identifiers.merge!({ 'object_type' => 'pull_request_merged_by' }) + end + + it_behaves_like 'import failure entity' do + let(:source) { 'Gitlab::GithubImport::Importer::PullRequests::MergedByImporter' } + let(:title) { 'Pull request 2 merger' } + let(:provider_url) { 'https://github.com/example/repo/pull/2' } + end + end + + context 'with `pull_request_review_request` failure' do + it_behaves_like 'import failure entity' do + let(:source) { 'Gitlab::GithubImport::Importer::PullRequests::ReviewRequestImporter' } + let(:title) { 'Pull request 2 review request' } + let(:provider_url) { 'https://github.com/example/repo/pull/2' } + let(:github_identifiers) do + { + 'merge_request_iid' => 2, + 'requested_reviewers' => %w[alice bob], + 'object_type' => 'pull_request_review_request' + } + end + end + end + + context 'with `pull_request_review` failure' do + it_behaves_like 'import failure entity' do + let(:source) { 'Gitlab::GithubImport::Importer::PullRequests::ReviewImporter' } + let(:title) { 'Pull request review 123456' } + let(:provider_url) { 'https://github.com/example/repo/pull/2#pullrequestreview-123456' } + let(:github_identifiers) do + { + 'merge_request_iid' => 2, + 'review_id' => 123456, + 'object_type' => 'pull_request_review' + } + end + end + end + + context 'with `issue` failure' do + before do + import_failure.external_identifiers.merge!({ 'object_type' => 'issue' }) + end + + it_behaves_like 'import failure entity' do + let(:source) { 'Gitlab::GithubImport::Importer::IssueAndLabelLinksImporter' } + let(:title) { 'Implement cool feature' } + let(:provider_url) { 'https://github.com/example/repo/issues/2' } + end + end + + context 'with `collaborator` failure' do + it_behaves_like 'import failure entity' do + let(:source) { 'Gitlab::GithubImport::Importer::CollaboratorImporter' } + let(:title) { 'alice' } + let(:provider_url) { 'https://github.com/alice' } + let(:github_identifiers) do + { + 'id' => 123456, + 'login' => 'alice', + 'object_type' => 'collaborator' + } + end + end + end + + context 'with `protected_branch` failure' do + it_behaves_like 'import failure entity' do + let(:source) { 'Gitlab::GithubImport::Importer::ProtectedBranchImporter' } + let(:title) { 'main' } + let(:provider_url) { 'https://github.com/example/repo/tree/main' } + let(:github_identifiers) do + { + 'id' => 'main', + 'object_type' => 'protected_branch' + } + end + end + end + + context 'with `issue_event` failure' do + it_behaves_like 'import failure entity' do + let(:source) { 'Gitlab::GithubImport::Importer::IssueEventImporter' } + let(:title) { 'closed' } + let(:provider_url) { 'https://github.com/example/repo/issues/2#event-123456' } + let(:github_identifiers) do + { + 'id' => 123456, + 'issuable_iid' => 2, + 'event' => 'closed', + 'object_type' => 'issue_event' + } + end + end + end + + context 'with `label` failure' do + it_behaves_like 'import failure entity' do + let(:source) { 'Gitlab::GithubImport::Importer::LabelsImporter' } + let(:title) { 'bug' } + let(:provider_url) { 'https://github.com/example/repo/labels/bug' } + let(:github_identifiers) { { 'title' => 'bug', 'object_type' => 'label' } } + end + end + + context 'with `milestone` failure' do + it_behaves_like 'import failure entity' do + let(:source) { 'Gitlab::GithubImport::Importer::MilestonesImporter' } + let(:title) { '1 release' } + let(:provider_url) { 'https://github.com/example/repo/milestone/1' } + let(:github_identifiers) { { 'iid' => 1, 'title' => '1 release', 'object_type' => 'milestone' } } + end + end + + context 'with `release` failure' do + it_behaves_like 'import failure entity' do + let(:source) { 'Gitlab::GithubImport::Importer::ReleasesImporter' } + let(:title) { 'v1.0' } + let(:provider_url) { 'https://github.com/example/repo/releases/tag/v1.0' } + let(:github_identifiers) do + { + 'tag' => 'v1.0', + 'object_type' => 'release' + } + end + end + end + + context 'with `note` failure' do + it_behaves_like 'import failure entity' do + let(:source) { 'Gitlab::GithubImport::Importer::NoteImporter' } + let(:title) { 'MergeRequest comment 123456' } + let(:provider_url) { 'https://github.com/example/repo/issues/2#issuecomment-123456' } + let(:github_identifiers) do + { + 'note_id' => 123456, + 'noteable_iid' => 2, + 'noteable_type' => 'MergeRequest', + 'object_type' => 'note' + } + end + end + end + + context 'with `diff_note` failure' do + it_behaves_like 'import failure entity' do + let(:source) { 'Gitlab::GithubImport::Importer::DiffNoteImporter' } + let(:title) { 'Pull request review comment 123456' } + let(:provider_url) { 'https://github.com/example/repo/pull/2#discussion_r123456' } + let(:github_identifiers) do + { + 'note_id' => 123456, + 'noteable_iid' => 2, + 'noteable_type' => 'MergeRequest', + 'object_type' => 'diff_note' + } + end + end + end + + context 'with `issue_attachment` failure' do + it_behaves_like 'import failure entity' do + let(:source) { 'Gitlab::GithubImport::Importer::NoteAttachmentsImporter' } + let(:title) { 'Issue 2 attachment' } + let(:provider_url) { 'https://github.com/example/repo/issues/2' } + let(:github_identifiers) do + { + 'db_id' => 123456, + 'noteable_iid' => 2, + 'object_type' => 'issue_attachment' + } + end + end + end + + context 'with `merge_request_attachment` failure' do + it_behaves_like 'import failure entity' do + let(:source) { 'Gitlab::GithubImport::Importer::NoteAttachmentsImporter' } + let(:title) { 'Merge request 2 attachment' } + let(:provider_url) { 'https://github.com/example/repo/pull/2' } + let(:github_identifiers) do + { + 'db_id' => 123456, + 'noteable_iid' => 2, + 'object_type' => 'merge_request_attachment' + } + end + end + end + + context 'with `release_attachment` failure' do + it_behaves_like 'import failure entity' do + let(:source) { 'Gitlab::GithubImport::Importer::NoteAttachmentsImporter' } + let(:title) { 'Release v1.0 attachment' } + let(:provider_url) { 'https://github.com/example/repo/releases/tag/v1.0' } + let(:github_identifiers) do + { + 'db_id' => 123456, + 'tag' => 'v1.0', + 'object_type' => 'release_attachment' + } + end + end + end + + context 'with `note_attachment` failure' do + it_behaves_like 'import failure entity' do + let(:source) { 'Gitlab::GithubImport::Importer::NoteAttachmentsImporter' } + let(:title) { 'Note attachment' } + let(:provider_url) { '' } + let(:github_identifiers) do + { + 'db_id' => 123456, + 'noteable_type' => 'Issue', + 'object_type' => 'note_attachment' + } + end + end + end + + context 'with `lfs_object` failure' do + it_behaves_like 'import failure entity' do + let(:source) { 'Gitlab::GithubImport::Importer::LfsObjectImporter' } + let(:title) { '42' } + let(:provider_url) { '' } + let(:github_identifiers) do + { + 'oid' => 42, + 'size' => 123456, + 'object_type' => 'lfs_object' + } + end + end + end + + context 'with unknown failure' do + it_behaves_like 'import failure entity' do + let(:source) { 'Gitlab::GithubImport::Importer::NewObjectTypeImporter' } + let(:title) { '' } + let(:provider_url) { '' } + let(:github_identifiers) do + { + 'id' => 123456, + 'object_type' => 'new_object_type' + } + end + end + end + + context 'with an invalid import_url' do + let(:project) { instance_double(Project, id: 123456, import_url: 'Invalid url', import_source: 'example/repo') } + + it_behaves_like 'import failure entity' do + let(:title) { 'Implement cool feature' } + let(:provider_url) { '' } + end + end +end diff --git a/spec/serializers/import/github_failure_serializer_spec.rb b/spec/serializers/import/github_failure_serializer_spec.rb new file mode 100644 index 00000000000..170b2739cfc --- /dev/null +++ b/spec/serializers/import/github_failure_serializer_spec.rb @@ -0,0 +1,71 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Import::GithubFailureSerializer, feature_category: :importers do + subject(:serializer) { described_class.new } + + it 'represents GithubFailureEntity entities' do + expect(described_class.entity_class).to eq(Import::GithubFailureEntity) + end + + describe '#represent' do + let(:timestamp) { Time.new(2023, 1, 1).utc } + let(:github_identifiers) { { 'iid' => 2, 'object_type' => 'pull_request', 'title' => 'Implement cool feature' } } + let(:project) do + instance_double( + Project, + id: 123456, + import_status: 'finished', + import_url: 'https://github.com/example/repo.git', + import_source: 'example/repo' + ) + end + + let(:import_failure) do + instance_double( + ImportFailure, + project: project, + exception_class: 'Some class', + exception_message: 'Something went wrong', + source: 'Gitlab::GithubImport::Importer::PullRequestImporter', + correlation_id_value: '2ea9c4b8587b6df49f35a3fb703688aa', + external_identifiers: github_identifiers, + created_at: timestamp + ) + end + + let(:expected_data) do + { + type: 'pull_request', + title: 'Implement cool feature', + provider_url: 'https://github.com/example/repo/pull/2', + details: { + exception_class: import_failure.exception_class, + exception_message: import_failure.exception_message, + correlation_id_value: import_failure.correlation_id_value, + source: import_failure.source, + github_identifiers: github_identifiers, + created_at: timestamp.iso8601(3) + } + }.deep_stringify_keys + end + + context 'when a single object is being serialized' do + let(:resource) { import_failure } + + it 'serializes import failure' do + expect(serializer.represent(resource).as_json).to eq expected_data + end + end + + context 'when multiple objects are being serialized' do + let(:count) { 3 } + let(:resource) { Array.new(count, import_failure) } + + it 'serializes array of import failures' do + expect(serializer.represent(resource).as_json).to all(eq(expected_data)) + end + end + end +end diff --git a/spec/serializers/integrations/field_entity_spec.rb b/spec/serializers/integrations/field_entity_spec.rb index 1ca1545c11a..4d190b9a98e 100644 --- a/spec/serializers/integrations/field_entity_spec.rb +++ b/spec/serializers/integrations/field_entity_spec.rb @@ -23,10 +23,11 @@ RSpec.describe Integrations::FieldEntity, feature_category: :integrations do section: 'connection', type: 'text', name: 'username', - title: 'Username or email', + title: 'Email or username', placeholder: nil, - help: 'Username for the server version or an email for the cloud version', - required: true, + help: 'Only required for Basic authentication. ' \ + 'Email for Jira Cloud or username for Jira Data Center and Jira Server', + required: false, choices: nil, value: 'jira_username', checkbox_label: nil @@ -44,9 +45,9 @@ RSpec.describe Integrations::FieldEntity, feature_category: :integrations do section: 'connection', type: 'password', name: 'password', - title: 'Enter new password or API token', + title: 'New API token, password, or Jira personal access token', placeholder: nil, - help: 'Leave blank to use your current password or API token.', + help: 'Leave blank to use your current configuration', required: true, choices: nil, value: 'true', diff --git a/spec/serializers/issue_board_entity_spec.rb b/spec/serializers/issue_board_entity_spec.rb index 0c9c8f05e17..6042dea249f 100644 --- a/spec/serializers/issue_board_entity_spec.rb +++ b/spec/serializers/issue_board_entity_spec.rb @@ -16,13 +16,17 @@ RSpec.describe IssueBoardEntity do subject { described_class.new(resource, request: request).as_json } it 'has basic attributes' do - expect(subject).to include(:id, :iid, :title, :confidential, :due_date, :project_id, :relative_position, - :labels, :assignees, project: hash_including(:id, :path, :path_with_namespace)) + expect(subject).to include( + :id, :iid, :title, :confidential, :due_date, :project_id, :relative_position, + :labels, :assignees, project: hash_including(:id, :path, :path_with_namespace) + ) end it 'has path and endpoints' do - expect(subject).to include(:reference_path, :real_path, :issue_sidebar_endpoint, - :toggle_subscription_endpoint, :assignable_labels_endpoint) + expect(subject).to include( + :reference_path, :real_path, :issue_sidebar_endpoint, + :toggle_subscription_endpoint, :assignable_labels_endpoint + ) end it 'has milestone attributes' do @@ -57,18 +61,8 @@ RSpec.describe IssueBoardEntity do context 'when issue is of type task' do let(:resource) { create(:issue, :task, project: project) } - context 'when the use_iid_in_work_items_path feature flag is disabled' do - before do - stub_feature_flags(use_iid_in_work_items_path: false) - end - - it 'has a work item path' do - expect(subject[:real_path]).to eq(project_work_items_path(project, resource.id)) - end - end - it 'has a work item path with iid' do - expect(subject[:real_path]).to eq(project_work_items_path(project, resource.iid, iid_path: true)) + expect(subject[:real_path]).to eq(project_work_items_path(project, resource.iid)) end end end diff --git a/spec/serializers/issue_entity_spec.rb b/spec/serializers/issue_entity_spec.rb index 06d8523b2e7..38c81257a7d 100644 --- a/spec/serializers/issue_entity_spec.rb +++ b/spec/serializers/issue_entity_spec.rb @@ -17,19 +17,9 @@ RSpec.describe IssueEntity do context 'when issue is of type task' do let(:resource) { create(:issue, :task, project: project) } - context 'when use_iid_in_work_items_path feature flag is disabled' do - before do - stub_feature_flags(use_iid_in_work_items_path: false) - end - - # This was already a path and not a url when the work items change was introduced - it 'has a work item path' do - expect(subject[:web_url]).to eq(project_work_items_path(project, resource.id)) - end - end - + # This was already a path and not a url when the work items change was introduced it 'has a work item path with iid' do - expect(subject[:web_url]).to eq(project_work_items_path(project, resource.iid, iid_path: true)) + expect(subject[:web_url]).to eq(project_work_items_path(project, resource.iid)) end end end @@ -41,8 +31,10 @@ RSpec.describe IssueEntity do end it 'has Issuable attributes' do - expect(subject).to include(:id, :iid, :author_id, :description, :lock_version, :milestone_id, - :title, :updated_by_id, :created_at, :updated_at, :milestone, :labels) + expect(subject).to include( + :id, :iid, :author_id, :description, :lock_version, :milestone_id, + :title, :updated_by_id, :created_at, :updated_at, :milestone, :labels + ) end it 'has time estimation attributes' do @@ -51,8 +43,9 @@ RSpec.describe IssueEntity do describe 'current_user' do it 'has the exprected permissions' do - expect(subject[:current_user]).to include(:can_create_note, :can_update, :can_set_issue_metadata, - :can_award_emoji) + expect(subject[:current_user]).to include( + :can_create_note, :can_update, :can_set_issue_metadata, :can_award_emoji + ) end end diff --git a/spec/serializers/issue_sidebar_basic_entity_spec.rb b/spec/serializers/issue_sidebar_basic_entity_spec.rb index 64a271e359a..d81d87f4060 100644 --- a/spec/serializers/issue_sidebar_basic_entity_spec.rb +++ b/spec/serializers/issue_sidebar_basic_entity_spec.rb @@ -44,7 +44,10 @@ RSpec.describe IssueSidebarBasicEntity do context 'for an incident issue' do before do - issue.update!(issue_type: Issue.issue_types[:incident]) + issue.update!( + issue_type: WorkItems::Type.base_types[:incident], + work_item_type: WorkItems::Type.default_by_type(:incident) + ) end it 'is present and true' do diff --git a/spec/serializers/jira_connect/app_data_serializer_spec.rb b/spec/serializers/jira_connect/app_data_serializer_spec.rb index 9c10a8a54a1..1ade3dea6e7 100644 --- a/spec/serializers/jira_connect/app_data_serializer_spec.rb +++ b/spec/serializers/jira_connect/app_data_serializer_spec.rb @@ -4,12 +4,10 @@ require 'spec_helper' RSpec.describe JiraConnect::AppDataSerializer do describe '#as_json' do - subject(:app_data_json) { described_class.new(subscriptions, signed_in).as_json } + subject(:app_data_json) { described_class.new(subscriptions).as_json } let_it_be(:subscriptions) { create_list(:jira_connect_subscription, 2) } - let(:signed_in) { false } - it 'uses the subscription entity' do expect(JiraConnect::SubscriptionEntity).to receive(:represent).with(subscriptions) @@ -23,12 +21,5 @@ RSpec.describe JiraConnect::AppDataSerializer do end it { is_expected.to include(subscriptions_path: '/-/jira_connect/subscriptions') } - it { is_expected.to include(login_path: '/-/jira_connect/users') } - - context 'when signed in' do - let(:signed_in) { true } - - it { is_expected.to include(login_path: nil) } - end end end diff --git a/spec/serializers/linked_project_issue_entity_spec.rb b/spec/serializers/linked_project_issue_entity_spec.rb index d415d1cbcb2..2f7fb912115 100644 --- a/spec/serializers/linked_project_issue_entity_spec.rb +++ b/spec/serializers/linked_project_issue_entity_spec.rb @@ -47,19 +47,9 @@ RSpec.describe LinkedProjectIssueEntity do context 'when related issue is a task' do let_it_be(:issue_link) { create(:issue_link, target: create(:issue, :task)) } - context 'when use_iid_in_work_items_path feature flag is disabled' do - before do - stub_feature_flags(use_iid_in_work_items_path: false) - end - - it 'returns a work items path' do - expect(serialized_entity).to include(path: project_work_items_path(related_issue.project, related_issue.id)) - end - end - it 'returns a work items path using iid' do expect(serialized_entity).to include( - path: project_work_items_path(related_issue.project, related_issue.iid, iid_path: true) + path: project_work_items_path(related_issue.project, related_issue.iid) ) end end diff --git a/spec/serializers/merge_request_metrics_helper_spec.rb b/spec/serializers/merge_request_metrics_helper_spec.rb index ec764bf7853..4aba7ff5e9c 100644 --- a/spec/serializers/merge_request_metrics_helper_spec.rb +++ b/spec/serializers/merge_request_metrics_helper_spec.rb @@ -55,12 +55,12 @@ RSpec.describe MergeRequestMetricsHelper do closed_event = merge_request.closed_event merge_event = merge_request.merge_event - expect(MergeRequest::Metrics).to receive(:new) - .with(latest_closed_at: closed_event&.updated_at, - latest_closed_by: closed_event&.author, - merged_at: merge_event&.updated_at, - merged_by: merge_event&.author) - .and_call_original + expect(MergeRequest::Metrics).to receive(:new).with( + latest_closed_at: closed_event&.updated_at, + latest_closed_by: closed_event&.author, + merged_at: merge_event&.updated_at, + merged_by: merge_event&.author + ).and_call_original subject end diff --git a/spec/serializers/merge_request_poll_cached_widget_entity_spec.rb b/spec/serializers/merge_request_poll_cached_widget_entity_spec.rb index f883156628a..458d9ecd916 100644 --- a/spec/serializers/merge_request_poll_cached_widget_entity_spec.rb +++ b/spec/serializers/merge_request_poll_cached_widget_entity_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe MergeRequestPollCachedWidgetEntity do +RSpec.describe MergeRequestPollCachedWidgetEntity, feature_category: :code_review_workflow do using RSpec::Parameterized::TableSyntax let_it_be(:project, refind: true) { create :project, :repository } @@ -49,8 +49,9 @@ RSpec.describe MergeRequestPollCachedWidgetEntity do describe 'diverged_commits_count' do context 'when MR open and its diverging' do it 'returns diverged commits count' do - allow(resource).to receive_messages(open?: true, diverged_from_target_branch?: true, - diverged_commits_count: 10) + allow(resource).to receive_messages( + open?: true, diverged_from_target_branch?: true, diverged_commits_count: 10 + ) expect(subject[:diverged_commits_count]).to eq(10) end @@ -330,4 +331,39 @@ RSpec.describe MergeRequestPollCachedWidgetEntity do end end end + + describe 'favicon overlay path' do + context 'when merged' do + before do + resource.mark_as_merged! + resource.metrics.update!(merged_by: user) + end + + it 'returns merged favicon overlay' do + expect(subject[:favicon_overlay_path]).to match_asset_path('/assets/mr_favicons/favicon_status_merged.png') + end + + context 'with pipeline' do + let_it_be(:pipeline) { create(:ci_empty_pipeline, project: project, ref: resource.source_branch, sha: resource.source_branch_sha, head_pipeline_of: resource) } + + it 'returns merged favicon overlay' do + expect(subject[:favicon_overlay_path]).to match_asset_path('/assets/mr_favicons/favicon_status_merged.png') + end + end + end + + context 'when not merged' do + it 'returns no favicon overlay' do + expect(subject[:favicon_overlay_path]).to be_nil + end + + context 'with pipeline' do + let_it_be(:pipeline) { create(:ci_empty_pipeline, project: project, ref: resource.source_branch, sha: resource.source_branch_sha, head_pipeline_of: resource) } + + it 'returns pipeline favicon overlay' do + expect(subject[:favicon_overlay_path]).to match_asset_path('/assets/ci_favicons/favicon_status_pending.png') + end + end + end + end end diff --git a/spec/serializers/merge_request_poll_widget_entity_spec.rb b/spec/serializers/merge_request_poll_widget_entity_spec.rb index 418f629a301..726f35418a1 100644 --- a/spec/serializers/merge_request_poll_widget_entity_spec.rb +++ b/spec/serializers/merge_request_poll_widget_entity_spec.rb @@ -62,9 +62,7 @@ RSpec.describe MergeRequestPollWidgetEntity do context 'when head pipeline is running' do before do - create(:ci_pipeline, :running, project: project, - ref: resource.source_branch, - sha: resource.diff_head_sha) + create(:ci_pipeline, :running, project: project, ref: resource.source_branch, sha: resource.diff_head_sha) resource.update_head_pipeline end @@ -96,9 +94,7 @@ RSpec.describe MergeRequestPollWidgetEntity do context 'when head pipeline is finished' do before do - create(:ci_pipeline, :success, project: project, - ref: resource.source_branch, - sha: resource.diff_head_sha) + create(:ci_pipeline, :success, project: project, ref: resource.source_branch, sha: resource.diff_head_sha) resource.update_head_pipeline end diff --git a/spec/serializers/note_entity_spec.rb b/spec/serializers/note_entity_spec.rb index 19438e69a10..bbb1d2ca164 100644 --- a/spec/serializers/note_entity_spec.rb +++ b/spec/serializers/note_entity_spec.rb @@ -14,4 +14,67 @@ RSpec.describe NoteEntity do subject { entity.as_json } it_behaves_like 'note entity' + + shared_examples 'external author' do + context 'when anonymous' do + let(:user) { nil } + + it { is_expected.to eq(obfuscated_email) } + end + + context 'with signed in user' do + before do + stub_member_access_level(note.project, access_level => user) if access_level + end + + context 'when user has no role in project' do + let(:access_level) { nil } + + it { is_expected.to eq(obfuscated_email) } + end + + context 'when user has guest role in project' do + let(:access_level) { :guest } + + it { is_expected.to eq(obfuscated_email) } + end + + context 'when user has reporter role in project' do + let(:access_level) { :reporter } + + it { is_expected.to eq(email) } + end + + context 'when user has developer role in project' do + let(:access_level) { :developer } + + it { is_expected.to eq(email) } + end + end + end + + describe 'with email participant' do + let_it_be(:note) { create(:note) } + let_it_be(:note_metadata) { create(:note_metadata, note: note) } + + subject { entity.as_json[:external_author] } + + context 'when external_note_author_service_desk feature flag is enabled' do + let(:obfuscated_email) { 'em*****@e*****.c**' } + let(:email) { 'email@example.com' } + + it_behaves_like 'external author' + end + + context 'when external_note_author_service_desk feature flag is disabled' do + let(:email) { nil } + let(:obfuscated_email) { nil } + + before do + stub_feature_flags(external_note_author_service_desk: false) + end + + it_behaves_like 'external author' + end + end end diff --git a/spec/serializers/pipeline_details_entity_spec.rb b/spec/serializers/pipeline_details_entity_spec.rb index de05d2afd2b..71b088e4e0d 100644 --- a/spec/serializers/pipeline_details_entity_spec.rb +++ b/spec/serializers/pipeline_details_entity_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe PipelineDetailsEntity do +RSpec.describe PipelineDetailsEntity, feature_category: :continuous_integration do let_it_be(:user) { create(:user) } let(:request) { double('request') } @@ -32,15 +32,37 @@ RSpec.describe PipelineDetailsEntity do expect(subject[:details]) .to include :duration, :finished_at expect(subject[:details]) - .to include :stages, :manual_actions, :scheduled_actions + .to include :stages, :manual_actions, :has_manual_actions, :scheduled_actions, :has_scheduled_actions expect(subject[:details][:status]).to include :icon, :favicon, :text, :label end it 'contains flags' do - expect(subject).to include :flags - expect(subject[:flags]) - .to include :latest, :stuck, - :yaml_errors, :retryable, :cancelable + expect(subject).to include(:flags) + expect(subject[:flags]).to include(:latest, :stuck, :yaml_errors, :retryable, :cancelable) + end + end + + context 'when disable_manual_and_scheduled_actions is true' do + let(:pipeline) { create(:ci_pipeline, status: :success) } + let(:subject) do + described_class.represent(pipeline, request: request, disable_manual_and_scheduled_actions: true).as_json + end + + it 'does not contain manual and scheduled actions' do + expect(subject[:details]) + .not_to include :manual_actions, :scheduled_actions + end + end + + context 'when pipeline has manual builds' do + let(:pipeline) { create(:ci_pipeline, status: :success) } + + before do + create(:ci_build, :manual, pipeline: pipeline) + end + + it 'sets :has_manual_actions to true' do + expect(subject[:details][:has_manual_actions]).to eq true end end diff --git a/spec/serializers/pipeline_serializer_spec.rb b/spec/serializers/pipeline_serializer_spec.rb index 33fee68a2f2..d1c74bd5ec0 100644 --- a/spec/serializers/pipeline_serializer_spec.rb +++ b/spec/serializers/pipeline_serializer_spec.rb @@ -99,21 +99,25 @@ RSpec.describe PipelineSerializer do let(:resource) { Ci::Pipeline.all } let!(:merge_request_1) do - create(:merge_request, - :with_detached_merge_request_pipeline, - target_project: project, - target_branch: 'master', - source_project: project, - source_branch: 'feature') + create( + :merge_request, + :with_detached_merge_request_pipeline, + target_project: project, + target_branch: 'master', + source_project: project, + source_branch: 'feature' + ) end let!(:merge_request_2) do - create(:merge_request, - :with_detached_merge_request_pipeline, - target_project: project, - target_branch: 'master', - source_project: project, - source_branch: '2-mb-file') + create( + :merge_request, + :with_detached_merge_request_pipeline, + target_project: project, + target_branch: 'master', + source_project: project, + source_branch: '2-mb-file' + ) end before_all do @@ -235,11 +239,13 @@ RSpec.describe PipelineSerializer do end def create_pipeline(status) - create(:ci_empty_pipeline, - project: project, - status: status, - name: 'Build pipeline', - ref: 'feature').tap do |pipeline| + create( + :ci_empty_pipeline, + project: project, + status: status, + name: 'Build pipeline', + ref: 'feature' + ).tap do |pipeline| Ci::Build::AVAILABLE_STATUSES.each do |build_status| create_build(pipeline, status, build_status) end @@ -247,9 +253,11 @@ RSpec.describe PipelineSerializer do end def create_build(pipeline, stage, status) - create(:ci_build, :tags, :triggered, :artifacts, - pipeline: pipeline, stage: stage, - name: stage, status: status, ref: pipeline.ref) + create( + :ci_build, :tags, :triggered, :artifacts, + pipeline: pipeline, stage: stage, + name: stage, status: status, ref: pipeline.ref + ) end end end diff --git a/spec/serializers/profile/event_entity_spec.rb b/spec/serializers/profile/event_entity_spec.rb new file mode 100644 index 00000000000..1551fc76466 --- /dev/null +++ b/spec/serializers/profile/event_entity_spec.rb @@ -0,0 +1,149 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Profile::EventEntity, feature_category: :user_profile do + let_it_be(:group) { create(:group) } # rubocop:disable RSpec/FactoryBot/AvoidCreate + let_it_be(:project) { build(:project_empty_repo, group: group) } + let_it_be(:user) { create(:user) } # rubocop:disable RSpec/FactoryBot/AvoidCreate + let_it_be(:merge_request) { create(:merge_request, source_project: project, target_project: project) } # rubocop:disable RSpec/FactoryBot/AvoidCreate + + let(:target_user) { user } + let(:event) { build(:event, :merged, author: user, project: project, target: merge_request) } + let(:request) { double(described_class, current_user: user, target_user: target_user) } # rubocop:disable RSpec/VerifiedDoubles + let(:entity) { described_class.new(event, request: request) } + + subject { entity.as_json } + + before do + group.add_maintainer(user) + end + + it 'exposes fields', :aggregate_failures do + expect(subject[:created_at]).to eq(event.created_at) + expect(subject[:action]).to eq(event.action) + expect(subject[:author][:id]).to eq(target_user.id) + expect(subject[:author][:name]).to eq(target_user.name) + expect(subject[:author][:path]).to eq(target_user.username) + end + + context 'for push events' do + let_it_be(:commit_from) { Gitlab::Git::BLANK_SHA } + let_it_be(:commit_title) { 'My commit' } + let(:event) { build(:push_event, project: project, author: target_user) } + + it 'exposes ref fields' do + build(:push_event_payload, event: event, ref_count: 3) + + expect(subject[:ref][:type]).to eq(event.ref_type) + expect(subject[:ref][:count]).to eq(event.ref_count) + expect(subject[:ref][:name]).to eq(event.ref_name) + expect(subject[:ref][:path]).to be_nil + end + + shared_examples 'returns ref path' do + specify do + expect(subject[:ref][:path]).to be_present + end + end + + context 'with tag' do + before do + allow(project.repository).to receive(:tag_exists?).and_return(true) + build(:push_event_payload, event: event, ref_type: :tag) + end + + it_behaves_like 'returns ref path' + end + + context 'with branch' do + before do + allow(project.repository).to receive(:branch_exists?).and_return(true) + build(:push_event_payload, event: event, ref_type: :branch) + end + + it_behaves_like 'returns ref path' + end + + it 'exposes commit fields' do + build(:push_event_payload, event: event, commit_title: commit_title, commit_from: commit_from, commit_count: 2) + + compare_path = "/#{group.path}/#{project.path}/-/compare/#{commit_from}...#{event.commit_to}" + expect(subject[:commit][:compare_path]).to eq(compare_path) + expect(event.commit_id).to include(subject[:commit][:truncated_sha]) + expect(subject[:commit][:path]).to be_present + expect(subject[:commit][:title]).to eq(commit_title) + expect(subject[:commit][:count]).to eq(2) + expect(commit_from).to include(subject[:commit][:from_truncated_sha]) + expect(event.commit_to).to include(subject[:commit][:to_truncated_sha]) + expect(subject[:commit][:create_mr_path]).to be_nil + end + + it 'exposes create_mr_path' do + allow(project).to receive(:default_branch).and_return('main') + allow(project.repository).to receive(:branch_exists?).and_return(true) + build(:push_event_payload, event: event, action: :created, commit_from: commit_from, commit_count: 2) + + new_mr_path = "/#{group.path}/#{project.path}/-/merge_requests/new?" \ + "merge_request%5Bsource_branch%5D=#{event.branch_name}" + expect(subject[:commit][:create_mr_path]).to eq(new_mr_path) + end + end + + context 'with target' do + let_it_be(:note) { build(:note_on_merge_request, :with_attachment, noteable: merge_request, project: project) } + + context 'when target does not responds to :reference_link_text' do + let(:event) { build(:event, :commented, project: project, target: note, author: target_user) } + + it 'exposes target fields' do + expect(subject[:target]).not_to include(:reference_link_text) + expect(subject[:target][:target_type]).to eq(note.class.to_s) + expect(subject[:target][:target_url]).to be_present + expect(subject[:target][:title]).to eq(note.title) + expect(subject[:target][:first_line_in_markdown]).to be_present + expect(subject[:target][:attachment][:url]).to eq(note.attachment.url) + end + end + + context 'when target responds to :reference_link_text' do + it 'exposes reference_link_text' do + expect(subject[:target][:reference_link_text]).to eq(merge_request.reference_link_text) + end + end + end + + context 'with resource parent' do + it 'exposes resource parent fields' do + resource_parent = event.resource_parent + + expect(subject[:resource_parent][:type]).to eq('project') + expect(subject[:resource_parent][:full_name]).to eq(resource_parent.full_name) + expect(subject[:resource_parent][:full_path]).to eq(resource_parent.full_path) + end + end + + context 'for private events' do + let(:event) { build(:event, :merged, author: target_user) } + + context 'when include_private_contributions? is true' do + let(:target_user) { build(:user, include_private_contributions: true) } + + it 'exposes only created_at, action, and author', :aggregate_failures do + expect(subject[:created_at]).to eq(event.created_at) + expect(subject[:action]).to eq('private') + expect(subject[:author][:id]).to eq(target_user.id) + expect(subject[:author][:name]).to eq(target_user.name) + expect(subject[:author][:path]).to eq(target_user.username) + + is_expected.not_to include(:ref, :commit, :target, :resource_parent) + end + end + + context 'when include_private_contributions? is false' do + let(:target_user) { build(:user, include_private_contributions: false) } + + it { is_expected.to be_empty } + end + end +end diff --git a/spec/serializers/project_import_entity_spec.rb b/spec/serializers/project_import_entity_spec.rb index 6d292d18ae7..521d0127dbb 100644 --- a/spec/serializers/project_import_entity_spec.rb +++ b/spec/serializers/project_import_entity_spec.rb @@ -5,10 +5,11 @@ require 'spec_helper' RSpec.describe ProjectImportEntity, feature_category: :importers do include ImportHelper - let_it_be(:project) { create(:project, import_status: :started, import_source: 'namespace/project') } + let_it_be(:project) { create(:project, import_status: :started, import_source: 'import_user/project') } let(:provider_url) { 'https://provider.com' } - let(:entity) { described_class.represent(project, provider_url: provider_url) } + let(:client) { nil } + let(:entity) { described_class.represent(project, provider_url: provider_url, client: client) } before do create(:import_failure, project: project) @@ -23,6 +24,31 @@ RSpec.describe ProjectImportEntity, feature_category: :importers do expect(subject[:human_import_status_name]).to eq(project.human_import_status_name) expect(subject[:provider_link]).to eq(provider_project_link_url(provider_url, project[:import_source])) expect(subject[:import_error]).to eq(nil) + expect(subject[:relation_type]).to eq(nil) + end + + context 'when client option present', :clean_gitlab_redis_cache do + let(:octokit) { instance_double(Octokit::Client, access_token: 'stub') } + let(:client) do + instance_double( + ::Gitlab::GithubImport::Clients::Proxy, + user: { login: 'import_user' }, octokit: octokit + ) + end + + it 'includes relation_type' do + expect(subject[:relation_type]).to eq('owned') + end + + context 'with remove_legacy_github_client FF is disabled' do + before do + stub_feature_flags(remove_legacy_github_client: false) + end + + it "doesn't include relation_type" do + expect(subject[:relation_type]).to eq(nil) + end + end end context 'when import is failed' do diff --git a/spec/serializers/runner_entity_spec.rb b/spec/serializers/runner_entity_spec.rb index f34cb794834..b94e1e225ed 100644 --- a/spec/serializers/runner_entity_spec.rb +++ b/spec/serializers/runner_entity_spec.rb @@ -22,5 +22,23 @@ RSpec.describe RunnerEntity do expect(subject).to include(:edit_path) expect(subject).to include(:short_sha) end + + context 'without admin permissions' do + it 'does not contain admin_path field' do + expect(subject).not_to include(:admin_path) + end + end + + context 'with admin permissions' do + let_it_be(:user) { create(:user, :admin) } + + before do + allow(user).to receive(:can_admin_all_resources?).and_return(true) + end + + it 'contains admin_path field' do + expect(subject).to include(:admin_path) + end + end end end |