diff options
Diffstat (limited to 'spec/services')
29 files changed, 661 insertions, 70 deletions
diff --git a/spec/services/ci/create_cluster_service_spec.rb b/spec/services/ci/create_cluster_service_spec.rb new file mode 100644 index 00000000000..6e7398fbffa --- /dev/null +++ b/spec/services/ci/create_cluster_service_spec.rb @@ -0,0 +1,47 @@ +require 'spec_helper' + +describe Ci::CreateClusterService do + describe '#execute' do + let(:access_token) { 'xxx' } + let(:project) { create(:project) } + let(:user) { create(:user) } + let(:result) { described_class.new(project, user, params).execute(access_token) } + + context 'when correct params' do + let(:params) do + { + gcp_project_id: 'gcp-project', + gcp_cluster_name: 'test-cluster', + gcp_cluster_zone: 'us-central1-a', + gcp_cluster_size: 1 + } + end + + it 'creates a cluster object' do + expect(ClusterProvisionWorker).to receive(:perform_async) + expect { result }.to change { Gcp::Cluster.count }.by(1) + expect(result.gcp_project_id).to eq('gcp-project') + expect(result.gcp_cluster_name).to eq('test-cluster') + expect(result.gcp_cluster_zone).to eq('us-central1-a') + expect(result.gcp_cluster_size).to eq(1) + expect(result.gcp_token).to eq(access_token) + end + end + + context 'when invalid params' do + let(:params) do + { + gcp_project_id: 'gcp-project', + gcp_cluster_name: 'test-cluster', + gcp_cluster_zone: 'us-central1-a', + gcp_cluster_size: 'ABC' + } + end + + it 'returns an error' do + expect(ClusterProvisionWorker).not_to receive(:perform_async) + expect { result }.to change { Gcp::Cluster.count }.by(0) + end + end + end +end diff --git a/spec/services/ci/create_pipeline_service_spec.rb b/spec/services/ci/create_pipeline_service_spec.rb index eb6e683cc23..08847183bf4 100644 --- a/spec/services/ci/create_pipeline_service_spec.rb +++ b/spec/services/ci/create_pipeline_service_spec.rb @@ -1,6 +1,8 @@ require 'spec_helper' describe Ci::CreatePipelineService do + include ProjectForksHelper + set(:project) { create(:project, :repository) } let(:user) { create(:admin) } let(:ref_name) { 'refs/heads/master' } @@ -82,13 +84,9 @@ describe Ci::CreatePipelineService do end context 'when merge request target project is different from source project' do + let!(:project) { fork_project(target_project, nil, repository: true) } let!(:target_project) { create(:project, :repository) } - let!(:forked_project_link) do - create(:forked_project_link, forked_to_project: project, - forked_from_project: target_project) - end - it 'updates head pipeline for merge request' do merge_request = create(:merge_request, source_branch: 'master', target_branch: "branch_1", diff --git a/spec/services/ci/extract_sections_from_build_trace_service_spec.rb b/spec/services/ci/extract_sections_from_build_trace_service_spec.rb new file mode 100644 index 00000000000..28f2fa7903a --- /dev/null +++ b/spec/services/ci/extract_sections_from_build_trace_service_spec.rb @@ -0,0 +1,55 @@ +require 'spec_helper' + +describe Ci::ExtractSectionsFromBuildTraceService, '#execute' do + let(:user) { create(:user) } + let(:project) { create(:project) } + let(:build) { create(:ci_build, project: project) } + + subject { described_class.new(project, user) } + + shared_examples 'build trace has sections markers' do + before do + build.trace.set(File.read(expand_fixture_path('trace/trace_with_sections'))) + end + + it 'saves the correct extracted sections' do + expect(build.trace_sections).to be_empty + expect(subject.execute(build)).to be(true) + expect(build.trace_sections).not_to be_empty + end + + it "fails if trace_sections isn't empty" do + expect(subject.execute(build)).to be(true) + expect(build.trace_sections).not_to be_empty + + expect(subject.execute(build)).to be(false) + expect(build.trace_sections).not_to be_empty + end + end + + shared_examples 'build trace has no sections markers' do + before do + build.trace.set('no markerts') + end + + it 'extracts no sections' do + expect(build.trace_sections).to be_empty + expect(subject.execute(build)).to be(true) + expect(build.trace_sections).to be_empty + end + end + + context 'when the build has no user' do + it_behaves_like 'build trace has sections markers' + it_behaves_like 'build trace has no sections markers' + end + + context 'when the build has a valid user' do + before do + build.user = user + end + + it_behaves_like 'build trace has sections markers' + it_behaves_like 'build trace has no sections markers' + end +end diff --git a/spec/services/ci/fetch_gcp_operation_service_spec.rb b/spec/services/ci/fetch_gcp_operation_service_spec.rb new file mode 100644 index 00000000000..7792979c5cb --- /dev/null +++ b/spec/services/ci/fetch_gcp_operation_service_spec.rb @@ -0,0 +1,36 @@ +require 'spec_helper' +require 'google/apis' + +describe Ci::FetchGcpOperationService do + describe '#execute' do + let(:cluster) { create(:gcp_cluster) } + let(:operation) { double } + + context 'when suceeded' do + before do + allow_any_instance_of(GoogleApi::CloudPlatform::Client) + .to receive(:projects_zones_operations).and_return(operation) + end + + it 'fetch the gcp operaion' do + expect { |b| described_class.new.execute(cluster, &b) } + .to yield_with_args(operation) + end + end + + context 'when raises an error' do + let(:error) { Google::Apis::ServerError.new('a') } + + before do + allow_any_instance_of(GoogleApi::CloudPlatform::Client) + .to receive(:projects_zones_operations).and_raise(error) + end + + it 'sets an error to cluster object' do + expect { |b| described_class.new.execute(cluster, &b) } + .not_to yield_with_args + expect(cluster.reload).to be_errored + end + end + end +end diff --git a/spec/services/ci/fetch_kubernetes_token_service_spec.rb b/spec/services/ci/fetch_kubernetes_token_service_spec.rb new file mode 100644 index 00000000000..1d05c9671a9 --- /dev/null +++ b/spec/services/ci/fetch_kubernetes_token_service_spec.rb @@ -0,0 +1,64 @@ +require 'spec_helper' + +describe Ci::FetchKubernetesTokenService do + describe '#execute' do + subject { described_class.new(api_url, ca_pem, username, password).execute } + + let(:api_url) { 'http://111.111.111.111' } + let(:ca_pem) { '' } + let(:username) { 'admin' } + let(:password) { 'xxx' } + + context 'when params correct' do + let(:token) { 'xxx.token.xxx' } + + let(:secrets_json) do + [ + { + 'metadata': { + name: metadata_name + }, + 'data': { + 'token': Base64.encode64(token) + } + } + ] + end + + before do + allow_any_instance_of(Kubeclient::Client) + .to receive(:get_secrets).and_return(secrets_json) + end + + context 'when default-token exists' do + let(:metadata_name) { 'default-token-123' } + + it { is_expected.to eq(token) } + end + + context 'when default-token does not exist' do + let(:metadata_name) { 'another-token-123' } + + it { is_expected.to be_nil } + end + end + + context 'when api_url is nil' do + let(:api_url) { nil } + + it { expect { subject }.to raise_error("Incomplete settings") } + end + + context 'when username is nil' do + let(:username) { nil } + + it { expect { subject }.to raise_error("Incomplete settings") } + end + + context 'when password is nil' do + let(:password) { nil } + + it { expect { subject }.to raise_error("Incomplete settings") } + end + end +end diff --git a/spec/services/ci/finalize_cluster_creation_service_spec.rb b/spec/services/ci/finalize_cluster_creation_service_spec.rb new file mode 100644 index 00000000000..def3709fdb4 --- /dev/null +++ b/spec/services/ci/finalize_cluster_creation_service_spec.rb @@ -0,0 +1,61 @@ +require 'spec_helper' + +describe Ci::FinalizeClusterCreationService do + describe '#execute' do + let(:cluster) { create(:gcp_cluster) } + let(:result) { described_class.new.execute(cluster) } + + context 'when suceeded to get cluster from api' do + let(:gke_cluster) { double } + + before do + allow(gke_cluster).to receive(:endpoint).and_return('111.111.111.111') + allow(gke_cluster).to receive(:master_auth).and_return(spy) + allow_any_instance_of(GoogleApi::CloudPlatform::Client) + .to receive(:projects_zones_clusters_get).and_return(gke_cluster) + end + + context 'when suceeded to get kubernetes token' do + let(:kubernetes_token) { 'abc' } + + before do + allow_any_instance_of(Ci::FetchKubernetesTokenService) + .to receive(:execute).and_return(kubernetes_token) + end + + it 'executes integration cluster' do + expect_any_instance_of(Ci::IntegrateClusterService).to receive(:execute) + described_class.new.execute(cluster) + end + end + + context 'when failed to get kubernetes token' do + before do + allow_any_instance_of(Ci::FetchKubernetesTokenService) + .to receive(:execute).and_return(nil) + end + + it 'sets an error to cluster object' do + described_class.new.execute(cluster) + + expect(cluster.reload).to be_errored + end + end + end + + context 'when failed to get cluster from api' do + let(:error) { Google::Apis::ServerError.new('a') } + + before do + allow_any_instance_of(GoogleApi::CloudPlatform::Client) + .to receive(:projects_zones_clusters_get).and_raise(error) + end + + it 'sets an error to cluster object' do + described_class.new.execute(cluster) + + expect(cluster.reload).to be_errored + end + end + end +end diff --git a/spec/services/ci/integrate_cluster_service_spec.rb b/spec/services/ci/integrate_cluster_service_spec.rb new file mode 100644 index 00000000000..3a79c205bd1 --- /dev/null +++ b/spec/services/ci/integrate_cluster_service_spec.rb @@ -0,0 +1,42 @@ +require 'spec_helper' + +describe Ci::IntegrateClusterService do + describe '#execute' do + let(:cluster) { create(:gcp_cluster, :custom_project_namespace) } + let(:endpoint) { '123.123.123.123' } + let(:ca_cert) { 'ca_cert_xxx' } + let(:token) { 'token_xxx' } + let(:username) { 'username_xxx' } + let(:password) { 'password_xxx' } + + before do + described_class + .new.execute(cluster, endpoint, ca_cert, token, username, password) + + cluster.reload + end + + context 'when correct params' do + it 'creates a cluster object' do + expect(cluster.endpoint).to eq(endpoint) + expect(cluster.ca_cert).to eq(ca_cert) + expect(cluster.kubernetes_token).to eq(token) + expect(cluster.username).to eq(username) + expect(cluster.password).to eq(password) + expect(cluster.service.active).to be_truthy + expect(cluster.service.api_url).to eq(cluster.api_url) + expect(cluster.service.ca_pem).to eq(ca_cert) + expect(cluster.service.namespace).to eq(cluster.project_namespace) + expect(cluster.service.token).to eq(token) + end + end + + context 'when invalid params' do + let(:endpoint) { nil } + + it 'sets an error to cluster object' do + expect(cluster).to be_errored + end + end + end +end diff --git a/spec/services/ci/provision_cluster_service_spec.rb b/spec/services/ci/provision_cluster_service_spec.rb new file mode 100644 index 00000000000..5ce5c788314 --- /dev/null +++ b/spec/services/ci/provision_cluster_service_spec.rb @@ -0,0 +1,85 @@ +require 'spec_helper' + +describe Ci::ProvisionClusterService do + describe '#execute' do + let(:cluster) { create(:gcp_cluster) } + let(:operation) { spy } + + shared_examples 'error' do + it 'sets an error to cluster object' do + described_class.new.execute(cluster) + + expect(cluster.reload).to be_errored + end + end + + context 'when suceeded to request provision' do + before do + allow_any_instance_of(GoogleApi::CloudPlatform::Client) + .to receive(:projects_zones_clusters_create).and_return(operation) + end + + context 'when operation status is RUNNING' do + before do + allow(operation).to receive(:status).and_return('RUNNING') + end + + context 'when suceeded to parse gcp operation id' do + before do + allow_any_instance_of(GoogleApi::CloudPlatform::Client) + .to receive(:parse_operation_id).and_return('operation-123') + end + + context 'when cluster status is scheduled' do + before do + allow_any_instance_of(GoogleApi::CloudPlatform::Client) + .to receive(:parse_operation_id).and_return('operation-123') + end + + it 'schedules a worker for status minitoring' do + expect(WaitForClusterCreationWorker).to receive(:perform_in) + + described_class.new.execute(cluster) + end + end + + context 'when cluster status is creating' do + before do + cluster.make_creating! + end + + it_behaves_like 'error' + end + end + + context 'when failed to parse gcp operation id' do + before do + allow_any_instance_of(GoogleApi::CloudPlatform::Client) + .to receive(:parse_operation_id).and_return(nil) + end + + it_behaves_like 'error' + end + end + + context 'when operation status is others' do + before do + allow(operation).to receive(:status).and_return('others') + end + + it_behaves_like 'error' + end + end + + context 'when failed to request provision' do + let(:error) { Google::Apis::ServerError.new('a') } + + before do + allow_any_instance_of(GoogleApi::CloudPlatform::Client) + .to receive(:projects_zones_clusters_create).and_raise(error) + end + + it_behaves_like 'error' + end + end +end diff --git a/spec/services/ci/retry_build_service_spec.rb b/spec/services/ci/retry_build_service_spec.rb index fbb3213f42b..9db3568abee 100644 --- a/spec/services/ci/retry_build_service_spec.rb +++ b/spec/services/ci/retry_build_service_spec.rb @@ -20,7 +20,7 @@ describe Ci::RetryBuildService do erased_at auto_canceled_by].freeze IGNORE_ACCESSORS = - %i[type lock_version target_url base_tags + %i[type lock_version target_url base_tags trace_sections commit_id deployments erased_by_id last_deployment project_id runner_id tag_taggings taggings tags trigger_request_id user_id auto_canceled_by_id retried failure_reason].freeze diff --git a/spec/services/ci/update_cluster_service_spec.rb b/spec/services/ci/update_cluster_service_spec.rb new file mode 100644 index 00000000000..a289385b88f --- /dev/null +++ b/spec/services/ci/update_cluster_service_spec.rb @@ -0,0 +1,37 @@ +require 'spec_helper' + +describe Ci::UpdateClusterService do + describe '#execute' do + let(:cluster) { create(:gcp_cluster, :created_on_gke, :with_kubernetes_service) } + + before do + described_class.new(cluster.project, cluster.user, params).execute(cluster) + + cluster.reload + end + + context 'when correct params' do + context 'when enabled is true' do + let(:params) { { 'enabled' => 'true' } } + + it 'enables cluster and overwrite kubernetes service' do + expect(cluster.enabled).to be_truthy + expect(cluster.service.active).to be_truthy + expect(cluster.service.api_url).to eq(cluster.api_url) + expect(cluster.service.ca_pem).to eq(cluster.ca_cert) + expect(cluster.service.namespace).to eq(cluster.project_namespace) + expect(cluster.service.token).to eq(cluster.kubernetes_token) + end + end + + context 'when enabled is false' do + let(:params) { { 'enabled' => 'false' } } + + it 'disables cluster and kubernetes service' do + expect(cluster.enabled).to be_falsy + expect(cluster.service.active).to be_falsy + end + end + end + end +end diff --git a/spec/services/delete_merged_branches_service_spec.rb b/spec/services/delete_merged_branches_service_spec.rb index 03c682ae0d7..5a9eb359ee1 100644 --- a/spec/services/delete_merged_branches_service_spec.rb +++ b/spec/services/delete_merged_branches_service_spec.rb @@ -1,6 +1,8 @@ require 'spec_helper' describe DeleteMergedBranchesService do + include ProjectForksHelper + subject(:service) { described_class.new(project, project.owner) } let(:project) { create(:project, :repository) } @@ -50,9 +52,9 @@ describe DeleteMergedBranchesService do context 'open merge requests' do it 'does not delete branches from open merge requests' do - fork_link = create(:forked_project_link, forked_from_project: project) + forked_project = fork_project(project) create(:merge_request, :opened, source_project: project, target_project: project, source_branch: 'branch-merged', target_branch: 'master') - create(:merge_request, :opened, source_project: fork_link.forked_to_project, target_project: project, target_branch: 'improve/awesome', source_branch: 'master') + create(:merge_request, :opened, source_project: forked_project, target_project: project, target_branch: 'improve/awesome', source_branch: 'master') service.execute diff --git a/spec/services/discussions/update_diff_position_service_spec.rb b/spec/services/discussions/update_diff_position_service_spec.rb index 82b156f5ebe..2b84206318f 100644 --- a/spec/services/discussions/update_diff_position_service_spec.rb +++ b/spec/services/discussions/update_diff_position_service_spec.rb @@ -164,8 +164,8 @@ describe Discussions::UpdateDiffPositionService do change_position = discussion.change_position expect(change_position.start_sha).to eq(old_diff_refs.head_sha) expect(change_position.head_sha).to eq(new_diff_refs.head_sha) - expect(change_position.old_line).to eq(9) - expect(change_position.new_line).to be_nil + expect(change_position.formatter.old_line).to eq(9) + expect(change_position.formatter.new_line).to be_nil end it 'creates a system discussion' do @@ -184,7 +184,7 @@ describe Discussions::UpdateDiffPositionService do expect(discussion.original_position).to eq(old_position) expect(discussion.position).not_to eq(old_position) - expect(discussion.position.new_line).to eq(22) + expect(discussion.position.formatter.new_line).to eq(22) end context 'when the resolve_outdated_diff_discussions setting is set' do diff --git a/spec/services/emails/confirm_service_spec.rb b/spec/services/emails/confirm_service_spec.rb new file mode 100644 index 00000000000..2b2c31e2521 --- /dev/null +++ b/spec/services/emails/confirm_service_spec.rb @@ -0,0 +1,15 @@ +require 'spec_helper' + +describe Emails::ConfirmService do + let(:user) { create(:user) } + + subject(:service) { described_class.new(user) } + + describe '#execute' do + it 'sends a confirmation email again' do + email = user.emails.create(email: 'new@email.com') + mail = service.execute(email) + expect(mail.subject).to eq('Confirmation instructions') + end + end +end diff --git a/spec/services/emails/create_service_spec.rb b/spec/services/emails/create_service_spec.rb index 75812c17309..54692c88623 100644 --- a/spec/services/emails/create_service_spec.rb +++ b/spec/services/emails/create_service_spec.rb @@ -12,6 +12,11 @@ describe Emails::CreateService do expect(Email.where(opts)).not_to be_empty end + it 'creates an email with additional attributes' do + expect { service.execute(confirmation_token: 'abc') }.to change { Email.count }.by(1) + expect(Email.where(opts).first.confirmation_token).to eq 'abc' + end + it 'has the right user association' do service.execute diff --git a/spec/services/emails/destroy_service_spec.rb b/spec/services/emails/destroy_service_spec.rb index 7726fc0ef81..c3204fac3df 100644 --- a/spec/services/emails/destroy_service_spec.rb +++ b/spec/services/emails/destroy_service_spec.rb @@ -4,11 +4,11 @@ describe Emails::DestroyService do let!(:user) { create(:user) } let!(:email) { create(:email, user: user) } - subject(:service) { described_class.new(user, user: user, email: email.email) } + subject(:service) { described_class.new(user, user: user) } describe '#execute' do it 'removes an email' do - expect { service.execute }.to change { user.emails.count }.by(-1) + expect { service.execute(email) }.to change { user.emails.count }.by(-1) end end end diff --git a/spec/services/gpg_keys/create_service_spec.rb b/spec/services/gpg_keys/create_service_spec.rb index 20382a3a618..1cd2625531e 100644 --- a/spec/services/gpg_keys/create_service_spec.rb +++ b/spec/services/gpg_keys/create_service_spec.rb @@ -18,4 +18,14 @@ describe GpgKeys::CreateService do it 'creates a gpg key' do expect { subject.execute }.to change { user.gpg_keys.where(params).count }.by(1) end + + context 'when the public key contains subkeys' do + let(:params) { attributes_for(:gpg_key_with_subkeys) } + + it 'generates the gpg subkeys' do + gpg_key = subject.execute + + expect(gpg_key.subkeys.count).to eq(2) + end + end end diff --git a/spec/services/issues/update_service_spec.rb b/spec/services/issues/update_service_spec.rb index a8a8aeed1bd..f07b81e842a 100644 --- a/spec/services/issues/update_service_spec.rb +++ b/spec/services/issues/update_service_spec.rb @@ -48,7 +48,8 @@ describe Issues::UpdateService, :mailer do assignee_ids: [user2.id], state_event: 'close', label_ids: [label.id], - due_date: Date.tomorrow + due_date: Date.tomorrow, + discussion_locked: true } end @@ -62,6 +63,7 @@ describe Issues::UpdateService, :mailer do expect(issue).to be_closed expect(issue.labels).to match_array [label] expect(issue.due_date).to eq Date.tomorrow + expect(issue.discussion_locked).to be_truthy end it 'refreshes the number of open issues when the issue is made confidential', :use_clean_rails_memory_store_caching do @@ -110,6 +112,7 @@ describe Issues::UpdateService, :mailer do expect(issue.labels).to be_empty expect(issue.milestone).to be_nil expect(issue.due_date).to be_nil + expect(issue.discussion_locked).to be_falsey end end @@ -148,6 +151,13 @@ describe Issues::UpdateService, :mailer do expect(note).not_to be_nil expect(note.note).to eq 'changed title from **{-Old-} title** to **{+New+} title**' end + + it 'creates system note about discussion lock' do + note = find_note('locked this issue') + + expect(note).not_to be_nil + expect(note.note).to eq 'locked this issue' + end end end @@ -257,6 +267,30 @@ describe Issues::UpdateService, :mailer do end end + context 'when a new assignee added' do + subject { update_issue(assignees: issue.assignees + [user2]) } + + it 'creates only 1 new todo' do + expect { subject }.to change { Todo.count }.by(1) + end + + it 'creates a todo for new assignee' do + subject + + attributes = { + project: project, + author: user, + user: user2, + target_id: issue.id, + target_type: issue.class.name, + action: Todo::ASSIGNED, + state: :pending + } + + expect(Todo.where(attributes).count).to eq(1) + end + end + context 'when the milestone change' do it 'marks todos as done' do update_issue(milestone: create(:milestone)) diff --git a/spec/services/merge_requests/conflicts/resolve_service_spec.rb b/spec/services/merge_requests/conflicts/resolve_service_spec.rb index 6f49a65d795..9c9b0c4c4a1 100644 --- a/spec/services/merge_requests/conflicts/resolve_service_spec.rb +++ b/spec/services/merge_requests/conflicts/resolve_service_spec.rb @@ -1,14 +1,16 @@ require 'spec_helper' describe MergeRequests::Conflicts::ResolveService do + include ProjectForksHelper let(:user) { create(:user) } - let(:project) { create(:project, :repository) } - - let(:fork_project) do - create(:forked_project_with_submodules) do |fork_project| - fork_project.build_forked_project_link(forked_to_project_id: fork_project.id, forked_from_project_id: project.id) - fork_project.save - end + let(:project) { create(:project, :public, :repository) } + + let(:forked_project) do + forked_project = fork_project(project, user) + TestEnv.copy_repo(forked_project, + bare_repo: TestEnv.forked_repo_path_bare, + refs: TestEnv::FORKED_BRANCH_SHA) + forked_project end let(:merge_request) do @@ -19,7 +21,7 @@ describe MergeRequests::Conflicts::ResolveService do let(:merge_request_from_fork) do create(:merge_request, - source_branch: 'conflict-resolvable-fork', source_project: fork_project, + source_branch: 'conflict-resolvable-fork', source_project: forked_project, target_branch: 'conflict-start', target_project: project) end @@ -114,7 +116,7 @@ describe MergeRequests::Conflicts::ResolveService do end it 'gets conflicts from the source project' do - expect(fork_project.repository.rugged).to receive(:merge_commits).and_call_original + expect(forked_project.repository.rugged).to receive(:merge_commits).and_call_original expect(project.repository.rugged).not_to receive(:merge_commits) resolve_conflicts diff --git a/spec/services/merge_requests/get_urls_service_spec.rb b/spec/services/merge_requests/get_urls_service_spec.rb index 25599dea19f..274624aa8bb 100644 --- a/spec/services/merge_requests/get_urls_service_spec.rb +++ b/spec/services/merge_requests/get_urls_service_spec.rb @@ -1,6 +1,8 @@ require "spec_helper" describe MergeRequests::GetUrlsService do + include ProjectForksHelper + let(:project) { create(:project, :public, :repository) } let(:service) { described_class.new(project) } let(:source_branch) { "merge-test" } @@ -85,7 +87,7 @@ describe MergeRequests::GetUrlsService do context 'pushing to existing branch from forked project' do let(:user) { create(:user) } - let!(:forked_project) { Projects::ForkService.new(project, user).execute } + let!(:forked_project) { fork_project(project, user, repository: true) } let!(:merge_request) { create(:merge_request, source_project: forked_project, target_project: project, source_branch: source_branch) } let(:changes) { existing_branch_changes } # Source project is now the forked one diff --git a/spec/services/merge_requests/refresh_service_spec.rb b/spec/services/merge_requests/refresh_service_spec.rb index 64e676f22a0..a2c05761f6b 100644 --- a/spec/services/merge_requests/refresh_service_spec.rb +++ b/spec/services/merge_requests/refresh_service_spec.rb @@ -1,6 +1,8 @@ require 'spec_helper' describe MergeRequests::RefreshService do + include ProjectForksHelper + let(:project) { create(:project, :repository) } let(:user) { create(:user) } let(:service) { described_class } @@ -12,7 +14,8 @@ describe MergeRequests::RefreshService do group.add_owner(@user) @project = create(:project, :repository, namespace: group) - @fork_project = Projects::ForkService.new(@project, @user).execute + @fork_project = fork_project(@project, @user, repository: true) + @merge_request = create(:merge_request, source_project: @project, source_branch: 'master', @@ -58,7 +61,7 @@ describe MergeRequests::RefreshService do it 'executes hooks with update action' do expect(refresh_service).to have_received(:execute_hooks) - .with(@merge_request, 'update', @oldrev) + .with(@merge_request, 'update', old_rev: @oldrev) expect(@merge_request.notes).not_to be_empty expect(@merge_request).to be_open @@ -84,7 +87,7 @@ describe MergeRequests::RefreshService do it 'executes hooks with update action' do expect(refresh_service).to have_received(:execute_hooks) - .with(@merge_request, 'update', @oldrev) + .with(@merge_request, 'update', old_rev: @oldrev) expect(@merge_request.notes).not_to be_empty expect(@merge_request).to be_open @@ -179,7 +182,7 @@ describe MergeRequests::RefreshService do it 'executes hooks with update action' do expect(refresh_service).to have_received(:execute_hooks) - .with(@fork_merge_request, 'update', @oldrev) + .with(@fork_merge_request, 'update', old_rev: @oldrev) expect(@merge_request.notes).to be_empty expect(@merge_request).to be_open @@ -261,7 +264,7 @@ describe MergeRequests::RefreshService do it 'refreshes the merge request' do expect(refresh_service).to receive(:execute_hooks) - .with(@fork_merge_request, 'update', Gitlab::Git::BLANK_SHA) + .with(@fork_merge_request, 'update', old_rev: Gitlab::Git::BLANK_SHA) allow_any_instance_of(Repository).to receive(:merge_base).and_return(@oldrev) refresh_service.execute(Gitlab::Git::BLANK_SHA, @newrev, 'refs/heads/master') @@ -311,8 +314,7 @@ describe MergeRequests::RefreshService do context 'when the merge request is sourced from a different project' do it 'creates a `MergeRequestsClosingIssues` record for each issue closed by a commit' do - forked_project = create(:project, :repository) - create(:forked_project_link, forked_to_project: forked_project, forked_from_project: @project) + forked_project = fork_project(@project, @user, repository: true) merge_request = create(:merge_request, target_branch: 'master', diff --git a/spec/services/merge_requests/update_service_spec.rb b/spec/services/merge_requests/update_service_spec.rb index 681feee61d1..98409be4236 100644 --- a/spec/services/merge_requests/update_service_spec.rb +++ b/spec/services/merge_requests/update_service_spec.rb @@ -49,7 +49,8 @@ describe MergeRequests::UpdateService, :mailer do state_event: 'close', label_ids: [label.id], target_branch: 'target', - force_remove_source_branch: '1' + force_remove_source_branch: '1', + discussion_locked: true } end @@ -73,11 +74,13 @@ describe MergeRequests::UpdateService, :mailer do expect(@merge_request.labels.first.title).to eq(label.name) expect(@merge_request.target_branch).to eq('target') expect(@merge_request.merge_params['force_remove_source_branch']).to eq('1') + expect(@merge_request.discussion_locked).to be_truthy end it 'executes hooks with update action' do - expect(service).to have_received(:execute_hooks) - .with(@merge_request, 'update') + expect(service) + .to have_received(:execute_hooks) + .with(@merge_request, 'update', old_labels: [], old_assignees: [user3]) end it 'sends email to user2 about assign of new merge request and email to user3 about merge request unassignment' do @@ -123,6 +126,13 @@ describe MergeRequests::UpdateService, :mailer do expect(note.note).to eq 'changed target branch from `master` to `target`' end + it 'creates system note about discussion lock' do + note = find_note('locked this merge request') + + expect(note).not_to be_nil + expect(note.note).to eq 'locked this merge request' + end + context 'when not including source branch removal options' do before do opts.delete(:force_remove_source_branch) diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb index f4b36eb7eeb..b64ca5be8fc 100644 --- a/spec/services/notification_service_spec.rb +++ b/spec/services/notification_service_spec.rb @@ -105,18 +105,6 @@ describe NotificationService, :mailer do end end - describe 'Email' do - describe '#new_email' do - let!(:email) { create(:email) } - - it { expect(notification.new_email(email)).to be_truthy } - - it 'sends email to email owner' do - expect { notification.new_email(email) }.to change { ActionMailer::Base.deliveries.size }.by(1) - end - end - end - describe 'Notes' do context 'issue note' do let(:project) { create(:project, :private) } diff --git a/spec/services/projects/destroy_service_spec.rb b/spec/services/projects/destroy_service_spec.rb index c867139d1de..c90bad46295 100644 --- a/spec/services/projects/destroy_service_spec.rb +++ b/spec/services/projects/destroy_service_spec.rb @@ -212,6 +212,19 @@ describe Projects::DestroyService do end end + context 'as the root of a fork network' do + let!(:fork_network) { create(:fork_network, root_project: project) } + + it 'updates the fork network with the project name' do + destroy_project(project, user) + + fork_network.reload + + expect(fork_network.deleted_root_project_name).to eq(project.full_name) + expect(fork_network.root_project).to be_nil + end + end + def destroy_project(project, user, params = {}) if async Projects::DestroyService.new(project, user, params).async_execute diff --git a/spec/services/projects/fork_service_spec.rb b/spec/services/projects/fork_service_spec.rb index fa9d6969830..53862283a27 100644 --- a/spec/services/projects/fork_service_spec.rb +++ b/spec/services/projects/fork_service_spec.rb @@ -1,6 +1,7 @@ require 'spec_helper' describe Projects::ForkService do + include ProjectForksHelper let(:gitlab_shell) { Gitlab::Shell.new } describe 'fork by user' do @@ -33,7 +34,7 @@ describe Projects::ForkService do end describe "successfully creates project in the user namespace" do - let(:to_project) { fork_project(@from_project, @to_user) } + let(:to_project) { fork_project(@from_project, @to_user, namespace: @to_user.namespace) } it { expect(to_project).to be_persisted } it { expect(to_project.errors).to be_empty } @@ -60,13 +61,40 @@ describe Projects::ForkService do expect(@from_project.forks_count).to eq(1) end + + it 'creates a fork network with the new project and the root project set' do + to_project + fork_network = @from_project.reload.fork_network + + expect(fork_network).not_to be_nil + expect(fork_network.root_project).to eq(@from_project) + expect(fork_network.projects).to contain_exactly(@from_project, to_project) + end + end + + context 'creating a fork of a fork' do + let(:from_forked_project) { fork_project(@from_project, @to_user) } + let(:other_namespace) do + group = create(:group) + group.add_owner(@to_user) + group + end + let(:to_project) { fork_project(from_forked_project, @to_user, namespace: other_namespace) } + + it 'sets the root of the network to the root project' do + expect(to_project.fork_network.root_project).to eq(@from_project) + end + + it 'sets the forked_from_project on the membership' do + expect(to_project.fork_network_member.forked_from_project).to eq(from_forked_project) + end end end context 'project already exists' do it "fails due to validation, not transaction failure" do @existing_project = create(:project, :repository, creator_id: @to_user.id, name: @from_project.name, namespace: @to_namespace) - @to_project = fork_project(@from_project, @to_user) + @to_project = fork_project(@from_project, @to_user, namespace: @to_namespace) expect(@existing_project).to be_persisted expect(@to_project).not_to be_persisted @@ -88,7 +116,7 @@ describe Projects::ForkService do end it 'does not allow creation' do - to_project = fork_project(@from_project, @to_user) + to_project = fork_project(@from_project, @to_user, namespace: @to_user.namespace) expect(to_project).not_to be_persisted expect(to_project.errors.messages).to have_key(:base) @@ -182,9 +210,4 @@ describe Projects::ForkService do end end end - - def fork_project(from_project, user, params = {}) - allow(RepositoryForkWorker).to receive(:perform_async).and_return(true) - Projects::ForkService.new(from_project, user, params).execute - end end diff --git a/spec/services/projects/hashed_storage_migration_service_spec.rb b/spec/services/projects/hashed_storage_migration_service_spec.rb index 1b61207b550..aa1988d29d6 100644 --- a/spec/services/projects/hashed_storage_migration_service_spec.rb +++ b/spec/services/projects/hashed_storage_migration_service_spec.rb @@ -20,7 +20,7 @@ describe Projects::HashedStorageMigrationService do expect(gitlab_shell.exists?(project.repository_storage_path, "#{hashed_storage.disk_path}.wiki.git")).to be_truthy end - it 'updates project to be hashed and not readonly' do + it 'updates project to be hashed and not read-only' do service.execute expect(project.hashed_storage?).to be_truthy diff --git a/spec/services/projects/unlink_fork_service_spec.rb b/spec/services/projects/unlink_fork_service_spec.rb index 4f1ab697460..50d3a4ec982 100644 --- a/spec/services/projects/unlink_fork_service_spec.rb +++ b/spec/services/projects/unlink_fork_service_spec.rb @@ -1,19 +1,22 @@ require 'spec_helper' describe Projects::UnlinkForkService do - subject { described_class.new(fork_project, user) } + include ProjectForksHelper - let(:fork_link) { create(:forked_project_link) } - let(:fork_project) { fork_link.forked_to_project } + subject { described_class.new(forked_project, user) } + + let(:fork_link) { forked_project.forked_project_link } + let(:project) { create(:project, :public) } + let(:forked_project) { fork_project(project, user) } let(:user) { create(:user) } context 'with opened merge request on the source project' do - let(:merge_request) { create(:merge_request, source_project: fork_project, target_project: fork_link.forked_from_project) } - let(:mr_close_service) { MergeRequests::CloseService.new(fork_project, user) } + let(:merge_request) { create(:merge_request, source_project: forked_project, target_project: fork_link.forked_from_project) } + let(:mr_close_service) { MergeRequests::CloseService.new(forked_project, user) } before do allow(MergeRequests::CloseService).to receive(:new) - .with(fork_project, user) + .with(forked_project, user) .and_return(mr_close_service) end @@ -25,13 +28,24 @@ describe Projects::UnlinkForkService do end it 'remove fork relation' do - expect(fork_project.forked_project_link).to receive(:destroy) + expect(forked_project.forked_project_link).to receive(:destroy) + + subject.execute + end + + it 'removes the link to the fork network' do + expect(forked_project.fork_network_member).to be_present + expect(forked_project.fork_network).to be_present subject.execute + forked_project.reload + + expect(forked_project.fork_network_member).to be_nil + expect(forked_project.reload.fork_network).to be_nil end it 'refreshes the forks count cache of the source project' do - source = fork_project.forked_from_project + source = forked_project.forked_from_project expect(source.forks_count).to eq(1) diff --git a/spec/services/projects/update_service_spec.rb b/spec/services/projects/update_service_spec.rb index d400304622e..3da222e2ed8 100644 --- a/spec/services/projects/update_service_spec.rb +++ b/spec/services/projects/update_service_spec.rb @@ -1,6 +1,8 @@ require 'spec_helper' describe Projects::UpdateService, '#execute' do + include ProjectForksHelper + let(:gitlab_shell) { Gitlab::Shell.new } let(:user) { create(:user) } let(:admin) { create(:admin) } @@ -76,13 +78,7 @@ describe Projects::UpdateService, '#execute' do describe 'when updating project that has forks' do let(:project) { create(:project, :internal) } - let(:forked_project) { create(:forked_project_with_submodules, :internal) } - - before do - forked_project.build_forked_project_link(forked_to_project_id: forked_project.id, - forked_from_project_id: project.id) - forked_project.save - end + let(:forked_project) { fork_project(project) } it 'updates forks visibility level when parent set to more restrictive' do opts = { visibility_level: Gitlab::VisibilityLevel::PRIVATE } diff --git a/spec/services/system_note_service_spec.rb b/spec/services/system_note_service_spec.rb index b1241cd8d0b..cd473c1f388 100644 --- a/spec/services/system_note_service_spec.rb +++ b/spec/services/system_note_service_spec.rb @@ -1145,4 +1145,42 @@ describe SystemNoteService do it { expect(subject.note).to eq "marked #{duplicate_issue.to_reference(project)} as a duplicate of this issue" } end end + + describe '.discussion_lock' do + subject { described_class.discussion_lock(noteable, author) } + + context 'discussion unlocked' do + it_behaves_like 'a system note' do + let(:action) { 'unlocked' } + end + + it 'creates the note text correctly' do + [:issue, :merge_request].each do |type| + issuable = create(type) + + expect(described_class.discussion_lock(issuable, author).note) + .to eq("unlocked this #{type.to_s.titleize.downcase}") + end + end + end + + context 'discussion locked' do + before do + noteable.update_attribute(:discussion_locked, true) + end + + it_behaves_like 'a system note' do + let(:action) { 'locked' } + end + + it 'creates the note text correctly' do + [:issue, :merge_request].each do |type| + issuable = create(type, discussion_locked: true) + + expect(described_class.discussion_lock(issuable, author).note) + .to eq("locked this #{type.to_s.titleize.downcase}") + end + end + end + end end diff --git a/spec/services/users/activity_service_spec.rb b/spec/services/users/activity_service_spec.rb index fef4da0c76e..17eabad73be 100644 --- a/spec/services/users/activity_service_spec.rb +++ b/spec/services/users/activity_service_spec.rb @@ -38,6 +38,18 @@ describe Users::ActivityService do end end end + + context 'when in GitLab read-only instance' do + before do + allow(Gitlab::Database).to receive(:read_only?).and_return(true) + end + + it 'does not update last_activity_at' do + service.execute + + expect(last_hour_user_ids).to eq([]) + end + end end def last_hour_user_ids |