diff options
author | Constance Okoghenun <cokoghenun@gitlab.com> | 2018-01-09 00:50:54 +0100 |
---|---|---|
committer | Constance Okoghenun <cokoghenun@gitlab.com> | 2018-01-09 00:50:54 +0100 |
commit | 85e8acedaf1d4e51335c59a0efa2f95576a4fde3 (patch) | |
tree | 9b21d76626568158cf746e2a7eb4853efe3aa0d5 /spec/models | |
parent | cdcade0dd4e748bcf0119b307c06993e0669f507 (diff) | |
parent | bd50ecbad8c00e7c9ab5c60fa8bc839a8905b4ab (diff) | |
download | gitlab-ce-move-project-dropdown.tar.gz |
Resolved conflictsmove-project-dropdown
Diffstat (limited to 'spec/models')
39 files changed, 815 insertions, 297 deletions
diff --git a/spec/models/ability_spec.rb b/spec/models/ability_spec.rb index 71aa51e1857..38fb98d4f50 100644 --- a/spec/models/ability_spec.rb +++ b/spec/models/ability_spec.rb @@ -34,19 +34,19 @@ describe Ability do end it 'returns false for a guest user' do - project.team << [user, :guest] + project.add_guest(user) expect(described_class.can_edit_note?(user, note)).to be_falsy end it 'returns false for a developer' do - project.team << [user, :developer] + project.add_developer(user) expect(described_class.can_edit_note?(user, note)).to be_falsy end it 'returns true for a master' do - project.team << [user, :master] + project.add_master(user) expect(described_class.can_edit_note?(user, note)).to be_truthy end diff --git a/spec/models/blob_viewer/package_json_spec.rb b/spec/models/blob_viewer/package_json_spec.rb index 0f8330e91c1..5ed2f4400bc 100644 --- a/spec/models/blob_viewer/package_json_spec.rb +++ b/spec/models/blob_viewer/package_json_spec.rb @@ -22,4 +22,51 @@ describe BlobViewer::PackageJson do expect(subject.package_name).to eq('module-name') end end + + describe '#package_url' do + it 'returns the package URL' do + expect(subject).to receive(:prepare!) + + expect(subject.package_url).to eq("https://www.npmjs.com/package/#{subject.package_name}") + end + end + + describe '#package_type' do + it 'returns "package"' do + expect(subject).to receive(:prepare!) + + expect(subject.package_type).to eq('package') + end + end + + context 'when package.json has "private": true' do + let(:data) do + <<-SPEC.strip_heredoc + { + "name": "module-name", + "version": "10.3.1", + "private": true, + "homepage": "myawesomepackage.com" + } + SPEC + end + let(:blob) { fake_blob(path: 'package.json', data: data) } + subject { described_class.new(blob) } + + describe '#package_url' do + it 'returns homepage if any' do + expect(subject).to receive(:prepare!) + + expect(subject.package_url).to eq('myawesomepackage.com') + end + end + + describe '#package_type' do + it 'returns "private package"' do + expect(subject).to receive(:prepare!) + + expect(subject.package_type).to eq('private package') + end + end + end end diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb index 871e8b47650..3eaeeebf97d 100644 --- a/spec/models/ci/build_spec.rb +++ b/spec/models/ci/build_spec.rb @@ -255,6 +255,42 @@ describe Ci::Build do end end + describe '#cache' do + let(:options) { { cache: { key: "key", paths: ["public"], policy: "pull-push" } } } + + subject { build.cache } + + context 'when build has cache' do + before do + allow(build).to receive(:options).and_return(options) + end + + context 'when project has jobs_cache_index' do + before do + allow_any_instance_of(Project).to receive(:jobs_cache_index).and_return(1) + end + + it { is_expected.to be_an(Array).and all(include(key: "key:1")) } + end + + context 'when project does not have jobs_cache_index' do + before do + allow_any_instance_of(Project).to receive(:jobs_cache_index).and_return(nil) + end + + it { is_expected.to eq([options[:cache]]) } + end + end + + context 'when build does not have cache' do + before do + allow(build).to receive(:options).and_return({}) + end + + it { is_expected.to eq([nil]) } + end + end + describe '#depends_on_builds' do let!(:build) { create(:ci_build, pipeline: pipeline, name: 'build', stage_idx: 0, stage: 'build') } let!(:rspec_test) { create(:ci_build, pipeline: pipeline, name: 'rspec', stage_idx: 1, stage: 'test') } diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb index a1f63a2534b..7bef798a782 100644 --- a/spec/models/ci/pipeline_spec.rb +++ b/spec/models/ci/pipeline_spec.rb @@ -1440,7 +1440,7 @@ describe Ci::Pipeline, :mailer do end before do - project.team << [pipeline.user, Gitlab::Access::DEVELOPER] + project.add_developer(pipeline.user) pipeline.user.global_notification_setting .update(level: 'custom', failed_pipeline: true, success_pipeline: true) diff --git a/spec/models/ci/trigger_spec.rb b/spec/models/ci/trigger_spec.rb index bd9c837402f..d4b72205203 100644 --- a/spec/models/ci/trigger_spec.rb +++ b/spec/models/ci/trigger_spec.rb @@ -69,7 +69,7 @@ describe Ci::Trigger do context 'and is member of the project' do before do - project.team << [owner, :developer] + project.add_developer(owner) end it { is_expected.to eq(true) } diff --git a/spec/models/clusters/applications/helm_spec.rb b/spec/models/clusters/applications/helm_spec.rb index f8855079842..eb57abaf6ef 100644 --- a/spec/models/clusters/applications/helm_spec.rb +++ b/spec/models/clusters/applications/helm_spec.rb @@ -40,13 +40,13 @@ describe Clusters::Applications::Helm do describe '#install_command' do it 'has all the needed information' do - expect(subject.install_command).to have_attributes(name: subject.name, install_helm: true, chart: nil) + expect(subject.install_command).to have_attributes(name: subject.name, install_helm: true) end end describe 'status state machine' do describe '#make_installing' do - subject { create(:cluster_applications_helm, :scheduled) } + subject { create(:clusters_applications_helm, :scheduled) } it 'is installing' do subject.make_installing! @@ -56,7 +56,7 @@ describe Clusters::Applications::Helm do end describe '#make_installed' do - subject { create(:cluster_applications_helm, :installing) } + subject { create(:clusters_applications_helm, :installing) } it 'is installed' do subject.make_installed @@ -66,7 +66,7 @@ describe Clusters::Applications::Helm do end describe '#make_errored' do - subject { create(:cluster_applications_helm, :installing) } + subject { create(:clusters_applications_helm, :installing) } let(:reason) { 'some errors' } it 'is errored' do @@ -78,7 +78,7 @@ describe Clusters::Applications::Helm do end describe '#make_scheduled' do - subject { create(:cluster_applications_helm, :installable) } + subject { create(:clusters_applications_helm, :installable) } it 'is scheduled' do subject.make_scheduled @@ -87,7 +87,7 @@ describe Clusters::Applications::Helm do end describe 'when was errored' do - subject { create(:cluster_applications_helm, :errored) } + subject { create(:clusters_applications_helm, :errored) } it 'clears #status_reason' do expect(subject.status_reason).not_to be_nil diff --git a/spec/models/clusters/applications/ingress_spec.rb b/spec/models/clusters/applications/ingress_spec.rb index b83472e1944..619c088b0bf 100644 --- a/spec/models/clusters/applications/ingress_spec.rb +++ b/spec/models/clusters/applications/ingress_spec.rb @@ -4,105 +4,5 @@ describe Clusters::Applications::Ingress do it { is_expected.to belong_to(:cluster) } it { is_expected.to validate_presence_of(:cluster) } - describe '#name' do - it 'is .application_name' do - expect(subject.name).to eq(described_class.application_name) - end - - it 'is recorded in Clusters::Cluster::APPLICATIONS' do - expect(Clusters::Cluster::APPLICATIONS[subject.name]).to eq(described_class) - end - end - - describe '#status' do - let(:cluster) { create(:cluster, :provided_by_gcp) } - - subject { described_class.new(cluster: cluster) } - - it 'defaults to :not_installable' do - expect(subject.status_name).to be(:not_installable) - end - - context 'when application helm is scheduled' do - before do - create(:cluster_applications_helm, :scheduled, cluster: cluster) - end - - it 'defaults to :not_installable' do - expect(subject.status_name).to be(:not_installable) - end - end - - context 'when application helm is installed' do - before do - create(:cluster_applications_helm, :installed, cluster: cluster) - end - - it 'defaults to :installable' do - expect(subject.status_name).to be(:installable) - end - end - end - - describe '#install_command' do - it 'has all the needed information' do - expect(subject.install_command).to have_attributes(name: subject.name, install_helm: false, chart: subject.chart) - end - end - - describe 'status state machine' do - describe '#make_installing' do - subject { create(:cluster_applications_ingress, :scheduled) } - - it 'is installing' do - subject.make_installing! - - expect(subject).to be_installing - end - end - - describe '#make_installed' do - subject { create(:cluster_applications_ingress, :installing) } - - it 'is installed' do - subject.make_installed - - expect(subject).to be_installed - end - end - - describe '#make_errored' do - subject { create(:cluster_applications_ingress, :installing) } - let(:reason) { 'some errors' } - - it 'is errored' do - subject.make_errored(reason) - - expect(subject).to be_errored - expect(subject.status_reason).to eq(reason) - end - end - - describe '#make_scheduled' do - subject { create(:cluster_applications_ingress, :installable) } - - it 'is scheduled' do - subject.make_scheduled - - expect(subject).to be_scheduled - end - - describe 'when was errored' do - subject { create(:cluster_applications_ingress, :errored) } - - it 'clears #status_reason' do - expect(subject.status_reason).not_to be_nil - - subject.make_scheduled! - - expect(subject.status_reason).to be_nil - end - end - end - end + include_examples 'cluster application specs', described_class end diff --git a/spec/models/clusters/applications/prometheus_spec.rb b/spec/models/clusters/applications/prometheus_spec.rb new file mode 100644 index 00000000000..696099f7cf7 --- /dev/null +++ b/spec/models/clusters/applications/prometheus_spec.rb @@ -0,0 +1,16 @@ +require 'rails_helper' + +describe Clusters::Applications::Prometheus do + it { is_expected.to belong_to(:cluster) } + it { is_expected.to validate_presence_of(:cluster) } + + include_examples 'cluster application specs', described_class + + describe "#chart_values_file" do + subject { create(:clusters_applications_prometheus).chart_values_file } + + it 'should return chart values file path' do + expect(subject).to eq("#{Rails.root}/vendor/prometheus/values.yaml") + end + end +end diff --git a/spec/models/clusters/cluster_spec.rb b/spec/models/clusters/cluster_spec.rb index 2683d21ddbe..799d7ced116 100644 --- a/spec/models/clusters/cluster_spec.rb +++ b/spec/models/clusters/cluster_spec.rb @@ -5,6 +5,9 @@ describe Clusters::Cluster do it { is_expected.to have_many(:projects) } it { is_expected.to have_one(:provider_gcp) } it { is_expected.to have_one(:platform_kubernetes) } + it { is_expected.to have_one(:application_helm) } + it { is_expected.to have_one(:application_ingress) } + it { is_expected.to have_one(:application_prometheus) } it { is_expected.to delegate_method(:status).to(:provider) } it { is_expected.to delegate_method(:status_reason).to(:provider) } it { is_expected.to delegate_method(:status_name).to(:provider) } @@ -190,11 +193,12 @@ describe Clusters::Cluster do end context 'when applications are created' do - let!(:helm) { create(:cluster_applications_helm, cluster: cluster) } - let!(:ingress) { create(:cluster_applications_ingress, cluster: cluster) } + let!(:helm) { create(:clusters_applications_helm, cluster: cluster) } + let!(:ingress) { create(:clusters_applications_ingress, cluster: cluster) } + let!(:prometheus) { create(:clusters_applications_prometheus, cluster: cluster) } it 'returns a list of created applications' do - is_expected.to contain_exactly(helm, ingress) + is_expected.to contain_exactly(helm, ingress, prometheus) end end end diff --git a/spec/models/commit_spec.rb b/spec/models/commit_spec.rb index d18a5c9dfa6..817254c7d1e 100644 --- a/spec/models/commit_spec.rb +++ b/spec/models/commit_spec.rb @@ -13,6 +13,45 @@ describe Commit do it { is_expected.to include_module(StaticModel) } end + describe '.lazy' do + set(:project) { create(:project, :repository) } + + context 'when the commits are found' do + let(:oids) do + %w( + 498214de67004b1da3d820901307bed2a68a8ef6 + c642fe9b8b9f28f9225d7ea953fe14e74748d53b + 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9 + 048721d90c449b244b7b4c53a9186b04330174ec + 281d3a76f31c812dbf48abce82ccf6860adedd81 + ) + end + + subject { oids.map { |oid| described_class.lazy(project, oid) } } + + it 'batches requests for commits' do + expect(project.repository).to receive(:commits_by).once.and_call_original + + subject.first.title + subject.last.title + end + + it 'maintains ordering' do + subject.each_with_index do |commit, i| + expect(commit.id).to eq(oids[i]) + end + end + end + + context 'when not found' do + it 'returns nil as commit' do + commit = described_class.lazy(project, 'deadbeef').__sync + + expect(commit).to be_nil + end + end + end + describe '#author' do it 'looks up the author in a case-insensitive way' do user = create(:user, email: commit.author_email.upcase) @@ -142,7 +181,6 @@ eos it { is_expected.to respond_to(:parents) } it { is_expected.to respond_to(:date) } it { is_expected.to respond_to(:diffs) } - it { is_expected.to respond_to(:tree) } it { is_expected.to respond_to(:id) } it { is_expected.to respond_to(:to_patch) } end @@ -154,8 +192,8 @@ eos let(:commiter) { create :user } before do - project.team << [commiter, :developer] - other_project.team << [commiter, :developer] + project.add_developer(commiter) + other_project.add_developer(commiter) end it 'detects issues that this commit is marked as closing' do diff --git a/spec/models/concerns/blocks_json_serialization_spec.rb b/spec/models/concerns/blocks_json_serialization_spec.rb new file mode 100644 index 00000000000..5906b588d0e --- /dev/null +++ b/spec/models/concerns/blocks_json_serialization_spec.rb @@ -0,0 +1,17 @@ +require 'rails_helper' + +describe BlocksJsonSerialization do + DummyModel = Class.new do + include BlocksJsonSerialization + end + + it 'blocks as_json' do + expect { DummyModel.new.as_json } + .to raise_error(described_class::JsonSerializationError, /DummyModel/) + end + + it 'blocks to_json' do + expect { DummyModel.new.to_json } + .to raise_error(described_class::JsonSerializationError, /DummyModel/) + end +end diff --git a/spec/models/concerns/deployment_platform_spec.rb b/spec/models/concerns/deployment_platform_spec.rb new file mode 100644 index 00000000000..7bb89fe41dc --- /dev/null +++ b/spec/models/concerns/deployment_platform_spec.rb @@ -0,0 +1,73 @@ +require 'rails_helper' + +describe DeploymentPlatform do + let(:project) { create(:project) } + + describe '#deployment_platform' do + subject { project.deployment_platform } + + context 'with no Kubernetes configuration on CI/CD, no Kubernetes Service and a Kubernetes template configured' do + let!(:kubernetes_service) { create(:kubernetes_service, template: true) } + + it 'returns a platform kubernetes' do + expect(subject).to be_a_kind_of(Clusters::Platforms::Kubernetes) + end + + it 'creates a cluster and a platform kubernetes' do + expect { subject } + .to change { Clusters::Cluster.count }.by(1) + .and change { Clusters::Platforms::Kubernetes.count }.by(1) + end + + it 'includes appropriate attributes for Cluster' do + cluster = subject.cluster + expect(cluster.name).to eq('kubernetes-template') + expect(cluster.project).to eq(project) + expect(cluster.provider_type).to eq('user') + expect(cluster.platform_type).to eq('kubernetes') + end + + it 'creates a platform kubernetes' do + expect { subject }.to change { Clusters::Platforms::Kubernetes.count }.by(1) + end + + it 'copies attributes from Clusters::Platform::Kubernetes template into the new Cluster::Platforms::Kubernetes' do + expect(subject.api_url).to eq(kubernetes_service.api_url) + expect(subject.ca_pem).to eq(kubernetes_service.ca_pem) + expect(subject.token).to eq(kubernetes_service.token) + expect(subject.namespace).to eq(kubernetes_service.namespace) + end + end + + context 'with no Kubernetes configuration on CI/CD, no Kubernetes Service and no Kubernetes template configured' do + it { is_expected.to be_nil } + end + + context 'when user configured kubernetes from CI/CD > Clusters' do + let!(:cluster) { create(:cluster, :provided_by_gcp, projects: [project]) } + let(:platform_kubernetes) { cluster.platform_kubernetes } + + it 'returns the Kubernetes platform' do + expect(subject).to eq(platform_kubernetes) + end + end + + context 'when user configured kubernetes integration from project services' do + let!(:kubernetes_service) { create(:kubernetes_service, project: project) } + + it 'returns the Kubernetes service' do + expect(subject).to eq(kubernetes_service) + end + end + + context 'when the cluster creation fails' do + let!(:kubernetes_service) { create(:kubernetes_service, template: true) } + + before do + allow_any_instance_of(Clusters::Cluster).to receive(:persisted?).and_return(false) + end + + it { is_expected.to be_nil } + end + end +end diff --git a/spec/models/concerns/issuable_spec.rb b/spec/models/concerns/issuable_spec.rb index 9df26f06a11..4b217df2e8f 100644 --- a/spec/models/concerns/issuable_spec.rb +++ b/spec/models/concerns/issuable_spec.rb @@ -291,7 +291,7 @@ describe Issuable do context 'total_time_spent is updated' do before do - issue.spend_time(duration: 2, user: user, spent_at: Time.now) + issue.spend_time(duration: 2, user_id: user.id, spent_at: Time.now) issue.save expect(Gitlab::HookData::IssuableBuilder) .to receive(:new).with(issue).and_return(builder) @@ -485,7 +485,7 @@ describe Issuable do let(:issue) { create(:issue) } def spend_time(seconds) - issue.spend_time(duration: seconds, user: user) + issue.spend_time(duration: seconds, user_id: user.id) issue.save! end diff --git a/spec/models/concerns/mentionable_spec.rb b/spec/models/concerns/mentionable_spec.rb index 8b545aec7f5..c73ea6aa94c 100644 --- a/spec/models/concerns/mentionable_spec.rb +++ b/spec/models/concerns/mentionable_spec.rb @@ -62,7 +62,7 @@ describe Issue, "Mentionable" do context 'when the current user can see the issue' do before do - private_project.team << [user, Gitlab::Access::DEVELOPER] + private_project.add_developer(user) end it 'includes the reference' do @@ -107,7 +107,7 @@ describe Issue, "Mentionable" do let(:issues) { create_list(:issue, 2, project: project, author: author) } before do - project.team << [author, Gitlab::Access::DEVELOPER] + project.add_developer(author) end context 'before changes are persisted' do diff --git a/spec/models/concerns/milestoneish_spec.rb b/spec/models/concerns/milestoneish_spec.rb index 9048da0c73d..87bf731340f 100644 --- a/spec/models/concerns/milestoneish_spec.rb +++ b/spec/models/concerns/milestoneish_spec.rb @@ -24,8 +24,8 @@ describe Milestone, 'Milestoneish' do let(:label_3) { create(:label, title: 'label_3', project: project) } before do - project.team << [member, :developer] - project.team << [guest, :guest] + project.add_developer(member) + project.add_guest(guest) end describe '#sorted_issues' do @@ -189,9 +189,9 @@ describe Milestone, 'Milestoneish' do describe '#total_issue_time_spent' do it 'calculates total issue time spent' do - closed_issue_1.spend_time(duration: 300, user: author) + closed_issue_1.spend_time(duration: 300, user_id: author.id) closed_issue_1.save! - closed_issue_2.spend_time(duration: 600, user: assignee) + closed_issue_2.spend_time(duration: 600, user_id: assignee.id) closed_issue_2.save! expect(milestone.total_issue_time_spent).to eq(900) diff --git a/spec/models/concerns/resolvable_discussion_spec.rb b/spec/models/concerns/resolvable_discussion_spec.rb index 1616c2ea985..2a2ef5a304d 100644 --- a/spec/models/concerns/resolvable_discussion_spec.rb +++ b/spec/models/concerns/resolvable_discussion_spec.rb @@ -190,7 +190,7 @@ describe Discussion, ResolvableDiscussion do context "when the signed in user can push to the project" do before do - subject.project.team << [current_user, :master] + subject.project.add_master(current_user) end it "returns true" do diff --git a/spec/models/diff_discussion_spec.rb b/spec/models/diff_discussion_spec.rb index fa02434b0fd..50b19000799 100644 --- a/spec/models/diff_discussion_spec.rb +++ b/spec/models/diff_discussion_spec.rb @@ -47,8 +47,20 @@ describe DiffDiscussion do diff_note.save! end - it 'returns the diff ID for the version to show' do - expect(subject.merge_request_version_params).to eq(diff_id: merge_request_diff1.id) + context 'when commit_id is not present' do + it 'returns the diff ID for the version to show' do + expect(subject.merge_request_version_params).to eq(diff_id: merge_request_diff1.id) + end + end + + context 'when commit_id is present' do + before do + diff_note.update_attribute(:commit_id, 'commit_123') + end + + it 'includes the commit_id in the result' do + expect(subject.merge_request_version_params).to eq(diff_id: merge_request_diff1.id, commit_id: 'commit_123') + end end end @@ -70,8 +82,20 @@ describe DiffDiscussion do diff_note.save! end - it 'returns the diff ID and start sha of the versions to compare' do - expect(subject.merge_request_version_params).to eq(diff_id: merge_request_diff3.id, start_sha: merge_request_diff1.head_commit_sha) + context 'when commit_id is not present' do + it 'returns the diff ID and start sha of the versions to compare' do + expect(subject.merge_request_version_params).to eq(diff_id: merge_request_diff3.id, start_sha: merge_request_diff1.head_commit_sha) + end + end + + context 'when commit_id is present' do + before do + diff_note.update_attribute(:commit_id, 'commit_123') + end + + it 'includes the commit_id in the result' do + expect(subject.merge_request_version_params).to eq(diff_id: merge_request_diff3.id, start_sha: merge_request_diff1.head_commit_sha, commit_id: 'commit_123') + end end end @@ -83,8 +107,20 @@ describe DiffDiscussion do diff_note.save! end - it 'returns nil' do - expect(subject.merge_request_version_params).to be_nil + context 'when commit_id is not present' do + it 'returns empty hash' do + expect(subject.merge_request_version_params).to eq(nil) + end + end + + context 'when commit_id is present' do + before do + diff_note.update_attribute(:commit_id, 'commit_123') + end + + it 'returns the commit_id' do + expect(subject.merge_request_version_params).to eq(commit_id: 'commit_123') + end end end end diff --git a/spec/models/diff_note_spec.rb b/spec/models/diff_note_spec.rb index 4d0b3245a13..2705421e540 100644 --- a/spec/models/diff_note_spec.rb +++ b/spec/models/diff_note_spec.rb @@ -112,22 +112,6 @@ describe DiffNote do end end - describe "#for_line?" do - context "when provided the correct diff line" do - it "returns true" do - expect(subject.for_line?(subject.diff_line)).to be true - end - end - - context "when provided a different diff line" do - it "returns false" do - some_line = subject.diff_file.diff_lines.first - - expect(subject.for_line?(some_line)).to be false - end - end - end - describe "#active?" do context "when noteable is a commit" do subject { build(:diff_note_on_commit, project: project, position: position) } diff --git a/spec/models/event_spec.rb b/spec/models/event_spec.rb index aa7a8342a4c..67f49348acb 100644 --- a/spec/models/event_spec.rb +++ b/spec/models/event_spec.rb @@ -125,8 +125,8 @@ describe Event do let(:event) { described_class.new(project: project, target: target, author_id: author.id) } before do - project.team << [member, :developer] - project.team << [guest, :guest] + project.add_developer(member) + project.add_guest(guest) end context 'commit note event' do @@ -347,6 +347,22 @@ describe Event do end end + describe '#target' do + it 'eager loads the author of an event target' do + create(:closed_issue_event) + + events = described_class.preload(:target).all.to_a + count = ActiveRecord::QueryRecorder + .new { events.first.target.author }.count + + # This expectation exists to make sure the test doesn't pass when the + # author is for some reason not loaded at all. + expect(events.first.target.author).to be_an_instance_of(User) + + expect(count).to be_zero + end + end + def create_push_event(project, user) event = create(:push_event, project: project, author: user) diff --git a/spec/models/generic_commit_status_spec.rb b/spec/models/generic_commit_status_spec.rb index 7f1909710d8..673049d1cc4 100644 --- a/spec/models/generic_commit_status_spec.rb +++ b/spec/models/generic_commit_status_spec.rb @@ -43,7 +43,7 @@ describe GenericCommitStatus do context 'when user has ability to see datails' do before do - project.team << [user, :developer] + project.add_developer(user) end it 'details path points to an external URL' do diff --git a/spec/models/hooks/system_hook_spec.rb b/spec/models/hooks/system_hook_spec.rb index 431e3db9f00..0e965f541d8 100644 --- a/spec/models/hooks/system_hook_spec.rb +++ b/spec/models/hooks/system_hook_spec.rb @@ -62,7 +62,7 @@ describe SystemHook do end it "project_create hook" do - project.team << [user, :master] + project.add_master(user) expect(WebMock).to have_requested(:post, system_hook.url).with( body: /user_add_to_team/, @@ -71,7 +71,7 @@ describe SystemHook do end it "project_destroy hook" do - project.team << [user, :master] + project.add_master(user) project.project_members.destroy_all expect(WebMock).to have_requested(:post, system_hook.url).with( diff --git a/spec/models/identity_spec.rb b/spec/models/identity_spec.rb index a45a6088831..7c66c98231b 100644 --- a/spec/models/identity_spec.rb +++ b/spec/models/identity_spec.rb @@ -44,4 +44,31 @@ describe Identity do end end end + + context 'callbacks' do + context 'before_save' do + describe 'normalizes extern uid' do + let!(:ldap_identity) { create(:identity, provider: 'ldapmain', extern_uid: 'uid=john smith,ou=people,dc=example,dc=com') } + + it 'if extern_uid changes' do + expect(ldap_identity).not_to receive(:ensure_normalized_extern_uid) + ldap_identity.save + end + + it 'if current_uid is nil' do + expect(ldap_identity).to receive(:ensure_normalized_extern_uid) + + ldap_identity.update(extern_uid: nil) + + expect(ldap_identity.extern_uid).to be_nil + end + + it 'if extern_uid changed and not nil' do + ldap_identity.update(extern_uid: 'uid=john1,ou=PEOPLE,dc=example,dc=com') + + expect(ldap_identity.extern_uid).to eq 'uid=john1,ou=people,dc=example,dc=com' + end + end + end + end end diff --git a/spec/models/issue_collection_spec.rb b/spec/models/issue_collection_spec.rb index 34d98a3c975..580a98193af 100644 --- a/spec/models/issue_collection_spec.rb +++ b/spec/models/issue_collection_spec.rb @@ -42,7 +42,7 @@ describe IssueCollection do context 'using a user that has reporter access to the project' do it 'returns the issues of the project' do - project.team << [user, :reporter] + project.add_reporter(user) expect(collection.updatable_by_user(user)).to eq([issue1, issue2]) end diff --git a/spec/models/issue_spec.rb b/spec/models/issue_spec.rb index 0ea287d007a..5ced000cdb6 100644 --- a/spec/models/issue_spec.rb +++ b/spec/models/issue_spec.rb @@ -23,6 +23,32 @@ describe Issue do it { is_expected.to have_db_index(:deleted_at) } end + describe 'callbacks' do + describe '#ensure_metrics' do + it 'creates metrics after saving' do + issue = create(:issue) + + expect(issue.metrics).to be_persisted + expect(Issue::Metrics.count).to eq(1) + end + + it 'does not create duplicate metrics for an issue' do + issue = create(:issue) + + issue.close! + + expect(issue.metrics).to be_persisted + expect(Issue::Metrics.count).to eq(1) + end + + it 'records current metrics' do + expect_any_instance_of(Issue::Metrics).to receive(:record!) + + create(:issue) + end + end + end + describe '#order_by_position_and_priority' do let(:project) { create :project } let(:p1) { create(:label, title: 'P1', project: project, priority: 1) } @@ -238,7 +264,7 @@ describe Issue do let(:issue) { create(:issue, project: project) } before do - project.team << [user, :reporter] + project.add_reporter(user) end it { is_expected.to eq true } @@ -254,7 +280,7 @@ describe Issue do context 'destination project allowed' do before do - to_project.team << [user, :reporter] + to_project.add_reporter(user) end it { is_expected.to eq true } @@ -262,7 +288,7 @@ describe Issue do context 'destination project not allowed' do before do - to_project.team << [user, :guest] + to_project.add_guest(user) end it { is_expected.to eq false } @@ -550,7 +576,7 @@ describe Issue do context 'when the user is the project owner' do before do - project.team << [user, :master] + project.add_master(user) end it 'returns true for a regular issue' do @@ -574,7 +600,7 @@ describe Issue do context 'using a public project' do before do - project.team << [user, Gitlab::Access::DEVELOPER] + project.add_developer(user) end it 'returns true for a regular issue' do @@ -594,7 +620,7 @@ describe Issue do let(:project) { create(:project, :internal) } before do - project.team << [user, Gitlab::Access::DEVELOPER] + project.add_developer(user) end it 'returns true for a regular issue' do @@ -614,7 +640,7 @@ describe Issue do let(:project) { create(:project, :private) } before do - project.team << [user, Gitlab::Access::DEVELOPER] + project.add_developer(user) end it 'returns true for a regular issue' do diff --git a/spec/models/member_spec.rb b/spec/models/member_spec.rb index 0a017c068ad..6aa0e7f49c3 100644 --- a/spec/models/member_spec.rb +++ b/spec/models/member_spec.rb @@ -62,12 +62,12 @@ describe Member do @owner_user = create(:user).tap { |u| group.add_owner(u) } @owner = group.members.find_by(user_id: @owner_user.id) - @master_user = create(:user).tap { |u| project.team << [u, :master] } + @master_user = create(:user).tap { |u| project.add_master(u) } @master = project.members.find_by(user_id: @master_user.id) @blocked_user = create(:user).tap do |u| - project.team << [u, :master] - project.team << [u, :developer] + project.add_master(u) + project.add_developer(u) u.block! end @@ -527,7 +527,7 @@ describe Member do it "refreshes user's authorized projects" do project = create(:project, :private) user = create(:user) - member = project.team << [user, :reporter] + member = project.add_reporter(user) member.destroy diff --git a/spec/models/members/project_member_spec.rb b/spec/models/members/project_member_spec.rb index fa3e80ba062..3e46fa36375 100644 --- a/spec/models/members/project_member_spec.rb +++ b/spec/models/members/project_member_spec.rb @@ -88,8 +88,8 @@ describe ProjectMember do @user_1 = create :user @user_2 = create :user - @project_1.team << [@user_1, :developer] - @project_2.team << [@user_2, :reporter] + @project_1.add_developer(@user_1) + @project_2.add_reporter(@user_2) @status = @project_2.team.import(@project_1) end @@ -136,8 +136,8 @@ describe ProjectMember do @user_1 = create :user @user_2 = create :user - @project_1.team << [@user_1, :developer] - @project_2.team << [@user_2, :reporter] + @project_1.add_developer(@user_1) + @project_2.add_reporter(@user_2) described_class.truncate_teams([@project_1.id, @project_2.id]) end diff --git a/spec/models/merge_request/metrics_spec.rb b/spec/models/merge_request/metrics_spec.rb index 9353d5c3c8a..02ff7839739 100644 --- a/spec/models/merge_request/metrics_spec.rb +++ b/spec/models/merge_request/metrics_spec.rb @@ -1,16 +1,11 @@ require 'spec_helper' describe MergeRequest::Metrics do - subject { create(:merge_request) } + subject { described_class.new } - describe "when recording the default set of metrics on merge request save" do - it "records the merge time" do - time = Time.now - Timecop.freeze(time) { subject.mark_as_merged } - metrics = subject.metrics - - expect(metrics).to be_present - expect(metrics.merged_at).to be_like_time(time) - end + describe 'associations' do + it { is_expected.to belong_to(:merge_request) } + it { is_expected.to belong_to(:latest_closed_by).class_name('User') } + it { is_expected.to belong_to(:merged_by).class_name('User') } end end diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index bb63abd167b..07b3e1c1758 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -65,6 +65,25 @@ describe MergeRequest do end end + describe 'callbacks' do + describe '#ensure_merge_request_metrics' do + it 'creates metrics after saving' do + merge_request = create(:merge_request) + + expect(merge_request.metrics).to be_persisted + expect(MergeRequest::Metrics.count).to eq(1) + end + + it 'does not duplicate metrics for a merge request' do + merge_request = create(:merge_request) + + merge_request.mark_as_merged! + + expect(MergeRequest::Metrics.count).to eq(1) + end + end + end + describe 'respond to' do it { is_expected.to respond_to(:unchecked?) } it { is_expected.to respond_to(:can_be_merged?) } @@ -195,7 +214,7 @@ describe MergeRequest do describe '#cache_merge_request_closes_issues!' do before do - subject.project.team << [subject.author, :developer] + subject.project.add_developer(subject.author) subject.target_branch = subject.project.default_branch end @@ -481,7 +500,7 @@ describe MergeRequest do let(:commit2) { double('commit2', safe_message: "Fixes #{issue1.to_reference}") } before do - subject.project.team << [subject.author, :developer] + subject.project.add_developer(subject.author) allow(subject).to receive(:commits).and_return([commit0, commit1, commit2]) end @@ -509,7 +528,7 @@ describe MergeRequest do let(:commit) { double('commit', safe_message: "Fixes #{closing_issue.to_reference}") } it 'detects issues mentioned in description but not closed' do - subject.project.team << [subject.author, :developer] + subject.project.add_developer(subject.author) subject.description = "Is related to #{mentioned_issue.to_reference} and #{closing_issue.to_reference}" allow(subject).to receive(:commits).and_return([commit]) @@ -521,7 +540,7 @@ describe MergeRequest do context 'when the project has an external issue tracker' do before do - subject.project.team << [subject.author, :developer] + subject.project.add_developer(subject.author) commit = double(:commit, safe_message: 'Fixes TEST-3') create(:jira_service, project: subject.project) @@ -660,7 +679,7 @@ describe MergeRequest do it 'includes its closed issues in the body' do issue = create(:issue, project: subject.project) - subject.project.team << [subject.author, :developer] + subject.project.add_developer(subject.author) subject.description = "This issue Closes #{issue.to_reference}" allow(subject.project).to receive(:default_branch) @@ -1688,7 +1707,7 @@ describe MergeRequest do let(:mr_sha) { merge_request.diff_head_sha } before do - project.team << [developer, :developer] + project.add_developer(developer) end context 'when autocomplete_precheck is set to true' do @@ -1884,4 +1903,50 @@ describe MergeRequest do end end end + + describe '#should_be_rebased?' do + let(:project) { create(:project, :repository) } + + it 'returns false for the same source and target branches' do + merge_request = create(:merge_request, source_project: project, target_project: project) + + expect(merge_request.should_be_rebased?).to be_falsey + end + end + + describe '#rebase_in_progress?' do + # Create merge request and project before we stub file calls + before do + subject + end + + it 'returns true when there is a current rebase directory' do + allow(File).to receive(:exist?).and_return(true) + allow(File).to receive(:mtime).and_return(Time.now) + + expect(subject.rebase_in_progress?).to be_truthy + end + + it 'returns false when there is no rebase directory' do + allow(File).to receive(:exist?).and_return(false) + + expect(subject.rebase_in_progress?).to be_falsey + end + + it 'returns false when the rebase directory has expired' do + allow(File).to receive(:exist?).and_return(true) + allow(File).to receive(:mtime).and_return(20.minutes.ago) + + expect(subject.rebase_in_progress?).to be_falsey + end + + it 'returns false when the source project has been removed' do + allow(subject).to receive(:source_project).and_return(nil) + allow(File).to receive(:exist?).and_return(true) + allow(File).to receive(:mtime).and_return(Time.now) + + expect(File).not_to have_received(:exist?) + expect(subject.rebase_in_progress?).to be_falsey + end + end end diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb index b7c6286fd83..b3f160f3119 100644 --- a/spec/models/namespace_spec.rb +++ b/spec/models/namespace_spec.rb @@ -203,7 +203,7 @@ describe Namespace do context 'with subgroups' do let(:parent) { create(:group, name: 'parent', path: 'parent') } let(:child) { create(:group, name: 'child', path: 'child', parent: parent) } - let!(:project) { create(:project_empty_repo, path: 'the-project', namespace: child) } + let!(:project) { create(:project_empty_repo, path: 'the-project', namespace: child, skip_disk_validation: true) } let(:uploads_dir) { File.join(CarrierWave.root, FileUploader.base_dir) } let(:pages_dir) { File.join(TestEnv.pages_path) } @@ -240,6 +240,24 @@ describe Namespace do end end end + + it 'updates project full path in .git/config for each project inside namespace' do + parent = create(:group, name: 'mygroup', path: 'mygroup') + subgroup = create(:group, name: 'mysubgroup', path: 'mysubgroup', parent: parent) + project_in_parent_group = create(:project, :repository, namespace: parent, name: 'foo1') + hashed_project_in_subgroup = create(:project, :repository, :hashed, namespace: subgroup, name: 'foo2') + legacy_project_in_subgroup = create(:project, :repository, namespace: subgroup, name: 'foo3') + + parent.update(path: 'mygroup_new') + + expect(project_rugged(project_in_parent_group).config['gitlab.fullpath']).to eq "mygroup_new/#{project_in_parent_group.path}" + expect(project_rugged(hashed_project_in_subgroup).config['gitlab.fullpath']).to eq "mygroup_new/mysubgroup/#{hashed_project_in_subgroup.path}" + expect(project_rugged(legacy_project_in_subgroup).config['gitlab.fullpath']).to eq "mygroup_new/mysubgroup/#{legacy_project_in_subgroup.path}" + end + + def project_rugged(project) + project.repository.rugged + end end describe '#rm_dir', 'callback' do diff --git a/spec/models/note_spec.rb b/spec/models/note_spec.rb index cefbf60b28c..3d030927036 100644 --- a/spec/models/note_spec.rb +++ b/spec/models/note_spec.rb @@ -195,7 +195,7 @@ describe Note do describe "cross_reference_not_visible_for?" do let(:private_user) { create(:user) } - let(:private_project) { create(:project, namespace: private_user.namespace) { |p| p.team << [private_user, :master] } } + let(:private_project) { create(:project, namespace: private_user.namespace) { |p| p.add_master(private_user) } } let(:private_issue) { create(:issue, project: private_project) } let(:ext_proj) { create(:project, :public) } diff --git a/spec/models/pages_domain_spec.rb b/spec/models/pages_domain_spec.rb index 7d835511dfb..9d12f96c642 100644 --- a/spec/models/pages_domain_spec.rb +++ b/spec/models/pages_domain_spec.rb @@ -68,7 +68,7 @@ describe PagesDomain do subject { domain.url } context 'without the certificate' do - let(:domain) { build(:pages_domain) } + let(:domain) { build(:pages_domain, certificate: '') } it { is_expected.to eq('http://my.domain.com') } end diff --git a/spec/models/project_feature_spec.rb b/spec/models/project_feature_spec.rb index de3e86b627f..63c6fbda3f2 100644 --- a/spec/models/project_feature_spec.rb +++ b/spec/models/project_feature_spec.rb @@ -37,7 +37,7 @@ describe ProjectFeature do end it "returns true when user is a team member" do - project.team << [user, :developer] + project.add_developer(user) features.each do |feature| project.project_feature.update_attribute("#{feature}_access_level".to_sym, ProjectFeature::PRIVATE) diff --git a/spec/models/project_services/kubernetes_service_spec.rb b/spec/models/project_services/kubernetes_service_spec.rb index f037ee77a94..6980ba335b8 100644 --- a/spec/models/project_services/kubernetes_service_spec.rb +++ b/spec/models/project_services/kubernetes_service_spec.rb @@ -52,12 +52,75 @@ describe KubernetesService, :use_clean_rails_memory_store_caching do context 'when service is inactive' do before do + subject.project = project subject.active = false end it { is_expected.not_to validate_presence_of(:api_url) } it { is_expected.not_to validate_presence_of(:token) } end + + context 'with a deprecated service' do + let(:kubernetes_service) { create(:kubernetes_service) } + + before do + kubernetes_service.update_attribute(:active, false) + kubernetes_service.properties[:namespace] = "foo" + end + + it 'should not update attributes' do + expect(kubernetes_service.save).to be_falsy + end + + it 'should include an error with a deprecation message' do + kubernetes_service.valid? + expect(kubernetes_service.errors[:base].first).to match(/Kubernetes service integration has been deprecated/) + end + end + + context 'with a non-deprecated service' do + let(:kubernetes_service) { create(:kubernetes_service) } + + it 'should update attributes' do + kubernetes_service.properties[:namespace] = 'foo' + expect(kubernetes_service.save).to be_truthy + end + end + + context 'with an active and deprecated service' do + let(:kubernetes_service) { create(:kubernetes_service) } + + before do + kubernetes_service.active = false + kubernetes_service.properties[:namespace] = 'foo' + kubernetes_service.save + end + + it 'should deactive the service' do + expect(kubernetes_service.active?).to be_falsy + end + + it 'should not include a deprecation message as error' do + expect(kubernetes_service.errors.messages.count).to eq(0) + end + + it 'should update attributes' do + expect(kubernetes_service.properties[:namespace]).to eq("foo") + end + end + + context 'with a template service' do + let(:kubernetes_service) { create(:kubernetes_service, template: true, active: false) } + + before do + kubernetes_service.properties[:namespace] = 'foo' + end + + it 'should update attributes' do + expect(kubernetes_service.save).to be_truthy + expect(kubernetes_service.properties[:namespace]).to eq('foo') + end + end end describe '#initialize_properties' do @@ -318,4 +381,42 @@ describe KubernetesService, :use_clean_rails_memory_store_caching do it { is_expected.to eq(pods: []) } end end + + describe "#deprecated?" do + let(:kubernetes_service) { create(:kubernetes_service) } + + context 'with an active kubernetes service' do + it 'should return false' do + expect(kubernetes_service.deprecated?).to be_falsy + end + end + + context 'with a inactive kubernetes service' do + it 'should return true' do + kubernetes_service.update_attribute(:active, false) + expect(kubernetes_service.deprecated?).to be_truthy + end + end + end + + describe "#deprecation_message" do + let(:kubernetes_service) { create(:kubernetes_service) } + + it 'should indicate the service is deprecated' do + expect(kubernetes_service.deprecation_message).to match(/Kubernetes service integration has been deprecated/) + end + + context 'if the services is active' do + it 'should return a message' do + expect(kubernetes_service.deprecation_message).to match(/Your cluster information on this page is still editable/) + end + end + + context 'if the service is not active' do + it 'should return a message' do + kubernetes_service.update_attribute(:active, false) + expect(kubernetes_service.deprecation_message).to match(/Fields on this page are now uneditable/) + end + end + end end diff --git a/spec/models/project_services/pipelines_email_service_spec.rb b/spec/models/project_services/pipelines_email_service_spec.rb index be07ca2d945..75ae2207910 100644 --- a/spec/models/project_services/pipelines_email_service_spec.rb +++ b/spec/models/project_services/pipelines_email_service_spec.rb @@ -37,7 +37,7 @@ describe PipelinesEmailService, :mailer do let(:user) { create(:user) } before do - project.team << [user, :developer] + project.add_developer(user) end it 'builds test data' do diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index f805f2dcddb..00afa09f1a3 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -93,7 +93,7 @@ describe Project do let(:developer) { create(:user) } before do project.request_access(requester) - project.team << [developer, :developer] + project.add_developer(developer) end it_behaves_like 'members and requesters associations' do @@ -418,14 +418,21 @@ describe Project do end describe '#merge_method' do - it 'returns "ff" merge_method when ff is enabled' do - project = build(:project, merge_requests_ff_only_enabled: true) - expect(project.merge_method).to be :ff + using RSpec::Parameterized::TableSyntax + + where(:ff, :rebase, :method) do + true | true | :ff + true | false | :ff + false | true | :rebase_merge + false | false | :merge end - it 'returns "merge" merge_method when ff is disabled' do - project = build(:project, merge_requests_ff_only_enabled: false) - expect(project.merge_method).to be :merge + with_them do + let(:project) { build(:project, merge_requests_rebase_enabled: rebase, merge_requests_ff_only_enabled: ff) } + + subject { project.merge_method } + + it { is_expected.to eq(method) } end end @@ -520,7 +527,7 @@ describe Project do let(:user) { create(:user) } before do - project.team << [user, :developer] + project.add_developer(user) end context 'with default issues tracker' do @@ -1435,35 +1442,35 @@ describe Project do let(:user) { create(:user) } it 'returns false when default_branch_protection is in full protection and user is developer' do - project.team << [user, :developer] + project.add_developer(user) stub_application_setting(default_branch_protection: Gitlab::Access::PROTECTION_FULL) expect(project.user_can_push_to_empty_repo?(user)).to be_falsey end it 'returns false when default_branch_protection only lets devs merge and user is dev' do - project.team << [user, :developer] + project.add_developer(user) stub_application_setting(default_branch_protection: Gitlab::Access::PROTECTION_DEV_CAN_MERGE) expect(project.user_can_push_to_empty_repo?(user)).to be_falsey end it 'returns true when default_branch_protection lets devs push and user is developer' do - project.team << [user, :developer] + project.add_developer(user) stub_application_setting(default_branch_protection: Gitlab::Access::PROTECTION_DEV_CAN_PUSH) expect(project.user_can_push_to_empty_repo?(user)).to be_truthy end it 'returns true when default_branch_protection is unprotected and user is developer' do - project.team << [user, :developer] + project.add_developer(user) stub_application_setting(default_branch_protection: Gitlab::Access::PROTECTION_NONE) expect(project.user_can_push_to_empty_repo?(user)).to be_truthy end it 'returns true when user is master' do - project.team << [user, :master] + project.add_master(user) expect(project.user_can_push_to_empty_repo?(user)).to be_truthy end @@ -1863,11 +1870,10 @@ describe Project do project.change_head(project.default_branch) end - it 'creates the new reference' do - expect(project.repository.raw_repository).to receive(:write_ref).with('HEAD', + it 'creates the new reference with rugged' do + expect(project.repository.rugged.references).to receive(:create).with('HEAD', "refs/heads/#{project.default_branch}", force: true) - project.change_head(project.default_branch) end @@ -2627,6 +2633,14 @@ describe Project do project.rename_repo end end + + it 'updates project full path in .git/config' do + allow(project_storage).to receive(:rename_repo).and_return(true) + + project.rename_repo + + expect(project.repository.rugged.config['gitlab.fullpath']).to eq(project.full_path) + end end describe '#pages_path' do @@ -2669,14 +2683,12 @@ describe Project do end context 'hashed storage' do - let(:project) { create(:project, :repository) } + let(:project) { create(:project, :repository, skip_disk_validation: true) } let(:gitlab_shell) { Gitlab::Shell.new } - let(:hash) { '6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b' } + let(:hash) { Digest::SHA2.hexdigest(project.id.to_s) } before do stub_application_setting(hashed_storage_enabled: true) - allow(Digest::SHA2).to receive(:hexdigest) { hash } - allow(project).to receive(:gitlab_shell).and_return(gitlab_shell) end describe '#legacy_storage?' do @@ -2699,13 +2711,13 @@ describe Project do describe '#base_dir' do it 'returns base_dir based on hash of project id' do - expect(project.base_dir).to eq('@hashed/6b/86') + expect(project.base_dir).to eq("@hashed/#{hash[0..1]}/#{hash[2..3]}") end end describe '#disk_path' do it 'returns disk_path based on hash of project id' do - hashed_path = '@hashed/6b/86/6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b' + hashed_path = "@hashed/#{hash[0..1]}/#{hash[2..3]}/#{hash}" expect(project.disk_path).to eq(hashed_path) end @@ -2713,7 +2725,9 @@ describe Project do describe '#ensure_storage_path_exists' do it 'delegates to gitlab_shell to ensure namespace is created' do - expect(gitlab_shell).to receive(:add_namespace).with(project.repository_storage_path, '@hashed/6b/86') + allow(project).to receive(:gitlab_shell).and_return(gitlab_shell) + + expect(gitlab_shell).to receive(:add_namespace).with(project.repository_storage_path, "@hashed/#{hash[0..1]}/#{hash[2..3]}") project.ensure_storage_path_exists end @@ -2773,7 +2787,7 @@ describe Project do end context 'when not rolled out' do - let(:project) { create(:project, :repository, storage_version: 1) } + let(:project) { create(:project, :repository, storage_version: 1, skip_disk_validation: true) } it 'moves pages folder to new location' do expect_any_instance_of(Gitlab::UploadsTransfer).to receive(:rename_project) @@ -2782,6 +2796,12 @@ describe Project do end end end + + it 'updates project full path in .git/config' do + project.rename_repo + + expect(project.repository.rugged.config['gitlab.fullpath']).to eq(project.full_path) + end end describe '#pages_path' do @@ -3059,9 +3079,51 @@ describe Project do expect(project).to receive(:import_finish) expect(project).to receive(:update_project_counter_caches) expect(project).to receive(:remove_import_jid) + expect(project).to receive(:after_create_default_branch) project.after_import end + + context 'branch protection' do + let(:project) { create(:project, :repository) } + + it 'does not protect when branch protection is disabled' do + stub_application_setting(default_branch_protection: Gitlab::Access::PROTECTION_NONE) + + project.after_import + + expect(project.protected_branches).to be_empty + end + + it "gives developer access to push when branch protection is set to 'developers can push'" do + stub_application_setting(default_branch_protection: Gitlab::Access::PROTECTION_DEV_CAN_PUSH) + + project.after_import + + expect(project.protected_branches).not_to be_empty + expect(project.default_branch).to eq(project.protected_branches.first.name) + expect(project.protected_branches.first.push_access_levels.map(&:access_level)).to eq([Gitlab::Access::DEVELOPER]) + end + + it "gives developer access to merge when branch protection is set to 'developers can merge'" do + stub_application_setting(default_branch_protection: Gitlab::Access::PROTECTION_DEV_CAN_MERGE) + + project.after_import + + expect(project.protected_branches).not_to be_empty + expect(project.default_branch).to eq(project.protected_branches.first.name) + expect(project.protected_branches.first.merge_access_levels.map(&:access_level)).to eq([Gitlab::Access::DEVELOPER]) + end + + it 'protects default branch' do + project.after_import + + expect(project.protected_branches).not_to be_empty + expect(project.default_branch).to eq(project.protected_branches.first.name) + expect(project.protected_branches.first.push_access_levels.map(&:access_level)).to eq([Gitlab::Access::MASTER]) + expect(project.protected_branches.first.merge_access_levels.map(&:access_level)).to eq([Gitlab::Access::MASTER]) + end + end end describe '#update_project_counter_caches' do @@ -3124,22 +3186,25 @@ describe Project do end end - describe '#deployment_platform' do - subject { project.deployment_platform } + describe '#write_repository_config' do + set(:project) { create(:project, :repository) } - let(:project) { create(:project) } + it 'writes full path in .git/config when key is missing' do + project.write_repository_config + + expect(project.repository.rugged.config['gitlab.fullpath']).to eq project.full_path + end - context 'when user configured kubernetes from Integration > Kubernetes' do - let!(:kubernetes_service) { create(:kubernetes_service, project: project) } + it 'updates full path in .git/config when key is present' do + project.write_repository_config(gl_full_path: 'old/path') - it { is_expected.to eq(kubernetes_service) } + expect { project.write_repository_config }.to change { project.repository.rugged.config['gitlab.fullpath'] }.from('old/path').to(project.full_path) end - context 'when user configured kubernetes from CI/CD > Clusters' do - let!(:cluster) { create(:cluster, :provided_by_gcp, projects: [project]) } - let(:platform_kubernetes) { cluster.platform_kubernetes } + it 'does not raise an error with an empty repository' do + project = create(:project_empty_repo) - it { is_expected.to eq(platform_kubernetes) } + expect { project.write_repository_config }.not_to raise_error end end end diff --git a/spec/models/project_team_spec.rb b/spec/models/project_team_spec.rb index 314824b32da..e07c522800a 100644 --- a/spec/models/project_team_spec.rb +++ b/spec/models/project_team_spec.rb @@ -291,8 +291,8 @@ describe ProjectTeam do group.add_master(master) group.add_developer(developer) - members_project.team << [developer, :developer] - members_project.team << [master, :master] + members_project.add_developer(developer) + members_project.add_master(master) create(:project_group_link, project: shared_project, group: group) end diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index bdc430c9095..c0db2c1b386 100644 --- a/spec/models/repository_spec.rb +++ b/spec/models/repository_spec.rb @@ -239,6 +239,54 @@ describe Repository do end end + describe '#commits_by' do + set(:project) { create(:project, :repository) } + + shared_examples 'batch commits fetching' do + let(:oids) { TestEnv::BRANCH_SHA.values } + + subject { project.repository.commits_by(oids: oids) } + + it 'finds each commit' do + expect(subject).not_to include(nil) + expect(subject.size).to eq(oids.size) + end + + it 'returns only Commit instances' do + expect(subject).to all( be_a(Commit) ) + end + + context 'when some commits are not found ' do + let(:oids) do + ['deadbeef'] + TestEnv::BRANCH_SHA.values.first(10) + end + + it 'returns only found commits' do + expect(subject).not_to include(nil) + expect(subject.size).to eq(10) + end + end + + context 'when no oids are passed' do + let(:oids) { [] } + + it 'does not call #batch_by_oid' do + expect(Gitlab::Git::Commit).not_to receive(:batch_by_oid) + + subject + end + end + end + + context 'when Gitaly list_commits_by_oid is enabled' do + it_behaves_like 'batch commits fetching' + end + + context 'when Gitaly list_commits_by_oid is enabled', :disable_gitaly do + it_behaves_like 'batch commits fetching' + end + end + describe '#find_commits_by_message' do shared_examples 'finding commits by message' do it 'returns commits with messages containing a given string' do @@ -534,38 +582,6 @@ describe Repository do end end - describe '#get_committer_and_author' do - it 'returns the committer and author data' do - options = repository.get_committer_and_author(user) - expect(options[:committer][:email]).to eq(user.email) - expect(options[:author][:email]).to eq(user.email) - end - - context 'when the email/name are given' do - it 'returns an object containing the email/name' do - options = repository.get_committer_and_author(user, email: author_email, name: author_name) - expect(options[:author][:email]).to eq(author_email) - expect(options[:author][:name]).to eq(author_name) - end - end - - context 'when the email is given but the name is not' do - it 'returns the committer as the author' do - options = repository.get_committer_and_author(user, email: author_email) - expect(options[:author][:email]).to eq(user.email) - expect(options[:author][:name]).to eq(user.name) - end - end - - context 'when the name is given but the email is not' do - it 'returns nil' do - options = repository.get_committer_and_author(user, name: author_name) - expect(options[:author][:email]).to eq(user.email) - expect(options[:author][:name]).to eq(user.name) - end - end - end - describe "search_files_by_content" do let(:results) { repository.search_files_by_content('feature', 'master') } subject { results } @@ -1064,16 +1080,16 @@ describe Repository do allow_any_instance_of(Gitlab::Git::Hook).to receive(:trigger).and_return([true, '']) end - it 'expires branch cache' do - expect(repository).not_to receive(:expire_exists_cache) - expect(repository).not_to receive(:expire_root_ref_cache) - expect(repository).not_to receive(:expire_emptiness_caches) - expect(repository).to receive(:expire_branches_cache) - - repository.with_branch(user, 'new-feature') do + subject do + Gitlab::Git::OperationService.new(git_user, repository.raw_repository).with_branch('new-feature') do new_rev end end + + it 'returns branch_created as true' do + expect(subject).not_to be_repo_created + expect(subject).to be_branch_created + end end context 'when repository is empty' do @@ -1931,23 +1947,6 @@ describe Repository do File.delete(path) end - - it "attempting to call keep_around when exists a lock does not fail" do - ref = repository.send(:keep_around_ref_name, sample_commit.id) - path = File.join(repository.path, ref) - lock_path = "#{path}.lock" - - FileUtils.mkdir_p(File.dirname(path)) - File.open(lock_path, 'w') { |f| f.write('') } - - begin - expect { repository.keep_around(sample_commit.id) }.not_to raise_error(Gitlab::Git::Repository::GitError) - - expect(File.exist?(lock_path)).to be_falsey - ensure - File.delete(path) - end - end end describe '#update_ref' do @@ -2184,6 +2183,15 @@ describe Repository do end end + describe '#diverging_commit_counts' do + it 'returns the commit counts behind and ahead of default branch' do + result = repository.diverging_commit_counts( + repository.find_branch('fix')) + + expect(result).to eq(behind: 29, ahead: 2) + end + end + describe '#cache_method_output', :use_clean_rails_memory_store_caching do let(:fallback) { 10 } diff --git a/spec/models/service_spec.rb b/spec/models/service_spec.rb index 0f2f906c667..ab6678cab38 100644 --- a/spec/models/service_spec.rb +++ b/spec/models/service_spec.rb @@ -254,4 +254,30 @@ describe Service do end end end + + describe "#deprecated?" do + let(:project) { create(:project, :repository) } + + it 'should return false by default' do + service = create(:service, project: project) + expect(service.deprecated?).to be_falsy + end + end + + describe "#deprecation_message" do + let(:project) { create(:project, :repository) } + + it 'should be empty by default' do + service = create(:service, project: project) + expect(service.deprecation_message).to be_nil + end + end + + describe '.find_by_template' do + let!(:kubernetes_service) { create(:kubernetes_service, template: true) } + + it 'returns service template' do + expect(KubernetesService.find_by_template).to eq(kubernetes_service) + end + end end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 4687d9dfa00..8d0eaf565a7 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -12,6 +12,7 @@ describe User do it { is_expected.to include_module(Referable) } it { is_expected.to include_module(Sortable) } it { is_expected.to include_module(TokenAuthenticatable) } + it { is_expected.to include_module(BlocksJsonSerialization) } end describe 'delegations' do @@ -21,7 +22,9 @@ describe User do describe 'associations' do it { is_expected.to have_one(:namespace) } it { is_expected.to have_many(:snippets).dependent(:destroy) } - it { is_expected.to have_many(:project_members).dependent(:destroy) } + it { is_expected.to have_many(:members) } + it { is_expected.to have_many(:project_members) } + it { is_expected.to have_many(:group_members) } it { is_expected.to have_many(:groups) } it { is_expected.to have_many(:keys).dependent(:destroy) } it { is_expected.to have_many(:deploy_keys).dependent(:destroy) } @@ -133,6 +136,16 @@ describe User do end end + it 'has a DB-level NOT NULL constraint on projects_limit' do + user = create(:user) + + expect(user.persisted?).to eq(true) + + expect do + user.update_columns(projects_limit: nil) + end.to raise_error(ActiveRecord::StatementInvalid) + end + it { is_expected.to validate_presence_of(:projects_limit) } it { is_expected.to validate_numericality_of(:projects_limit) } it { is_expected.to allow_value(0).for(:projects_limit) } @@ -759,7 +772,7 @@ describe User do before do # add user to project - project.team << [user, :master] + project.add_master(user) # create invite to projet create(:project_member, :developer, project: project, invite_token: '1234', invite_email: 'inviteduser1@example.com') @@ -804,6 +817,13 @@ describe User do expect(user.can_create_group).to be_falsey expect(user.theme_id).to eq(1) end + + it 'does not undo projects_limit setting if it matches old DB default of 10' do + # If the real default project limit is 10 then this test is worthless + expect(Gitlab.config.gitlab.default_projects_limit).not_to eq(10) + user = described_class.new(projects_limit: 10) + expect(user.projects_limit).to eq(10) + end end context 'when current_application_settings.user_default_external is true' do @@ -1447,8 +1467,8 @@ describe User do let!(:merge_event) { create(:event, :created, project: project3, target: merge_request, author: subject) } before do - project1.team << [subject, :master] - project2.team << [subject, :master] + project1.add_master(subject) + project2.add_master(subject) end it "includes IDs for projects the user has pushed to" do @@ -1547,7 +1567,7 @@ describe User do user = create(:user) project = create(:project, :private) - project.team << [user, Gitlab::Access::MASTER] + project.add_master(user) expect(user.authorized_projects(Gitlab::Access::REPORTER)) .to contain_exactly(project) @@ -1566,7 +1586,7 @@ describe User do user2 = create(:user) project = create(:project, :private, namespace: user1.namespace) - project.team << [user2, Gitlab::Access::DEVELOPER] + project.add_developer(user2) expect(user2.authorized_projects).to include(project) end @@ -1611,7 +1631,7 @@ describe User do user2 = create(:user) project = create(:project, :private, namespace: user1.namespace) - project.team << [user2, Gitlab::Access::DEVELOPER] + project.add_developer(user2) expect(user2.authorized_projects).to include(project) @@ -1701,7 +1721,7 @@ describe User do shared_examples :member do context 'when the user is a master' do before do - add_user(Gitlab::Access::MASTER) + add_user(:master) end it 'loads' do @@ -1711,7 +1731,7 @@ describe User do context 'when the user is a developer' do before do - add_user(Gitlab::Access::DEVELOPER) + add_user(:developer) end it 'does not load' do @@ -1735,7 +1755,7 @@ describe User do let(:project) { create(:project) } def add_user(access) - project.team << [user, access] + project.add_role(user, access) end it_behaves_like :member @@ -1748,8 +1768,8 @@ describe User do let(:user) { create(:user) } before do - project1.team << [user, :reporter] - project2.team << [user, :guest] + project1.add_reporter(user) + project2.add_guest(user) end it 'returns the projects when using a single project ID' do @@ -1891,8 +1911,8 @@ describe User do let(:user) { create(:user) } before do - project1.team << [user, :reporter] - project2.team << [user, :guest] + project1.add_reporter(user) + project2.add_guest(user) user.project_authorizations.delete_all user.refresh_authorized_projects |