diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-01-17 18:08:41 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-01-17 18:08:41 +0000 |
commit | 22a0d312ae82e7dda3073d5d1a5a766d7641738d (patch) | |
tree | 41a677a7212f24e2f29c2fbd5623430f92fb2b45 /spec | |
parent | 37eff29d5ce44899e34c7c2ac319b314f2f26d15 (diff) | |
download | gitlab-ce-22a0d312ae82e7dda3073d5d1a5a766d7641738d.tar.gz |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
23 files changed, 574 insertions, 137 deletions
diff --git a/spec/controllers/projects/forks_controller_spec.rb b/spec/controllers/projects/forks_controller_spec.rb index 80b5eb9a7ee..e351fb2b1f6 100644 --- a/spec/controllers/projects/forks_controller_spec.rb +++ b/spec/controllers/projects/forks_controller_spec.rb @@ -12,6 +12,21 @@ describe Projects::ForksController do group.add_owner(user) end + shared_examples 'forking disabled' do + let(:project) { create(:project, :private, :repository, :forking_disabled) } + + before do + project.add_developer(user) + sign_in(user) + end + + it 'returns with 404' do + subject + + expect(response).to have_gitlab_http_status(404) + end + end + describe 'GET index' do def get_forks(search: nil) get :index, @@ -138,19 +153,19 @@ describe Projects::ForksController do end describe 'GET new' do - def get_new + subject do get :new, - params: { - namespace_id: project.namespace, - project_id: project - } + params: { + namespace_id: project.namespace, + project_id: project + } end context 'when user is signed in' do it 'responds with status 200' do sign_in(user) - get_new + subject expect(response).to have_gitlab_http_status(200) end @@ -160,21 +175,26 @@ describe Projects::ForksController do it 'redirects to the sign-in page' do sign_out(user) - get_new + subject expect(response).to redirect_to(new_user_session_path) end end + + it_behaves_like 'forking disabled' end describe 'POST create' do - def post_create(params = {}) - post :create, - params: { - namespace_id: project.namespace, - project_id: project, - namespace_key: user.namespace.id - }.merge(params) + let(:params) do + { + namespace_id: project.namespace, + project_id: project, + namespace_key: user.namespace.id + } + end + + subject do + post :create, params: params end context 'when user is signed in' do @@ -183,18 +203,34 @@ describe Projects::ForksController do end it 'responds with status 302' do - post_create + subject expect(response).to have_gitlab_http_status(302) expect(response).to redirect_to(namespace_project_import_path(user.namespace, project)) end - it 'passes continue params to the redirect' do - continue_params = { to: '/-/ide/project/path', notice: 'message' } - post_create continue: continue_params + context 'continue params' do + let(:params) do + { + namespace_id: project.namespace, + project_id: project, + namespace_key: user.namespace.id, + continue: continue_params + } + end + let(:continue_params) do + { + to: '/-/ide/project/path', + notice: 'message' + } + end - expect(response).to have_gitlab_http_status(302) - expect(response).to redirect_to(namespace_project_import_path(user.namespace, project, continue: continue_params)) + it 'passes continue params to the redirect' do + subject + + expect(response).to have_gitlab_http_status(302) + expect(response).to redirect_to(namespace_project_import_path(user.namespace, project, continue: continue_params)) + end end end @@ -202,10 +238,12 @@ describe Projects::ForksController do it 'redirects to the sign-in page' do sign_out(user) - post_create + subject expect(response).to redirect_to(new_user_session_path) end end + + it_behaves_like 'forking disabled' end end diff --git a/spec/factories/projects.rb b/spec/factories/projects.rb index 46efc0111c0..490ae9e84e7 100644 --- a/spec/factories/projects.rb +++ b/spec/factories/projects.rb @@ -25,6 +25,7 @@ FactoryBot.define do builds_access_level { ProjectFeature::ENABLED } snippets_access_level { ProjectFeature::ENABLED } issues_access_level { ProjectFeature::ENABLED } + forking_access_level { ProjectFeature::ENABLED } merge_requests_access_level { ProjectFeature::ENABLED } repository_access_level { ProjectFeature::ENABLED } pages_access_level do @@ -48,6 +49,7 @@ FactoryBot.define do builds_access_level: builds_access_level, snippets_access_level: evaluator.snippets_access_level, issues_access_level: evaluator.issues_access_level, + forking_access_level: evaluator.forking_access_level, merge_requests_access_level: merge_requests_access_level, repository_access_level: evaluator.repository_access_level } @@ -264,6 +266,9 @@ FactoryBot.define do trait(:issues_disabled) { issues_access_level { ProjectFeature::DISABLED } } trait(:issues_enabled) { issues_access_level { ProjectFeature::ENABLED } } trait(:issues_private) { issues_access_level { ProjectFeature::PRIVATE } } + trait(:forking_disabled) { forking_access_level { ProjectFeature::DISABLED } } + trait(:forking_enabled) { forking_access_level { ProjectFeature::ENABLED } } + trait(:forking_private) { forking_access_level { ProjectFeature::PRIVATE } } trait(:merge_requests_enabled) { merge_requests_access_level { ProjectFeature::ENABLED } } trait(:merge_requests_disabled) { merge_requests_access_level { ProjectFeature::DISABLED } } trait(:merge_requests_private) { merge_requests_access_level { ProjectFeature::PRIVATE } } diff --git a/spec/features/projects/features_visibility_spec.rb b/spec/features/projects/features_visibility_spec.rb index a825911b01a..9854335a7ad 100644 --- a/spec/features/projects/features_visibility_spec.rb +++ b/spec/features/projects/features_visibility_spec.rb @@ -186,7 +186,7 @@ describe 'Edit Project Settings' do click_button "Save changes" end - expect(find(".sharing-permissions")).to have_selector(".project-feature-toggle.is-disabled", count: 2) + expect(find(".sharing-permissions")).to have_selector(".project-feature-toggle.is-disabled", count: 3) end it "shows empty features project homepage" do diff --git a/spec/features/projects/fork_spec.rb b/spec/features/projects/fork_spec.rb index 0f97032eefa..bfab4387688 100644 --- a/spec/features/projects/fork_spec.rb +++ b/spec/features/projects/fork_spec.rb @@ -27,6 +27,89 @@ describe 'Project fork' do expect(page).to have_css('a.disabled', text: 'Fork') end + context 'forking enabled / disabled in project settings' do + before do + project.project_feature.update_attribute( + :forking_access_level, forking_access_level) + end + + context 'forking is enabled' do + let(:forking_access_level) { ProjectFeature::ENABLED } + + it 'enables fork button' do + visit project_path(project) + + expect(page).to have_css('a', text: 'Fork') + expect(page).not_to have_css('a.disabled', text: 'Fork') + end + + it 'renders new project fork page' do + visit new_project_fork_path(project) + + expect(page.status_code).to eq(200) + expect(page).to have_text(' Select a namespace to fork the project ') + end + end + + context 'forking is disabled' do + let(:forking_access_level) { ProjectFeature::DISABLED } + + it 'does not render fork button' do + visit project_path(project) + + expect(page).not_to have_css('a', text: 'Fork') + end + + it 'does not render new project fork page' do + visit new_project_fork_path(project) + + expect(page.status_code).to eq(404) + end + end + + context 'forking is private' do + let(:forking_access_level) { ProjectFeature::PRIVATE } + + before do + project.update(visibility_level: Gitlab::VisibilityLevel::INTERNAL) + end + + context 'user is not a team member' do + it 'does not render fork button' do + visit project_path(project) + + expect(page).not_to have_css('a', text: 'Fork') + end + + it 'does not render new project fork page' do + visit new_project_fork_path(project) + + expect(page.status_code).to eq(404) + end + end + + context 'user is a team member' do + before do + project.add_developer(user) + end + + it 'enables fork button' do + visit project_path(project) + + expect(page).to have_css('a', text: 'Fork') + expect(page).not_to have_css('a.disabled', text: 'Fork') + end + + it 'renders new project fork page' do + visit new_project_fork_path(project) + + expect(page.status_code).to eq(200) + expect(page).to have_text(' Select a namespace to fork the project ') + end + end + end + end + it 'forks the project', :sidekiq_might_not_need_inline do visit project_path(project) diff --git a/spec/features/projects/settings/project_settings_spec.rb b/spec/features/projects/settings/project_settings_spec.rb index 7afddc0e712..b601866c96b 100644 --- a/spec/features/projects/settings/project_settings_spec.rb +++ b/spec/features/projects/settings/project_settings_spec.rb @@ -34,6 +34,26 @@ describe 'Projects settings' do expect_toggle_state(:expanded) end + context 'forking enabled', :js do + it 'toggles forking enabled / disabled' do + visit edit_project_path(project) + + forking_enabled_input = find('input[name="project[project_feature_attributes][forking_access_level]"]', visible: :hidden) + forking_enabled_button = find('input[name="project[project_feature_attributes][forking_access_level]"] + label > button') + + expect(forking_enabled_input.value).to eq('20') + + # disable by clicking toggle + forking_enabled_button.click + page.within('.sharing-permissions') do + find('input[value="Save changes"]').click + end + wait_for_requests + + expect(forking_enabled_input.value).to eq('0') + end + end + def expect_toggle_state(state) is_collapsed = state == :collapsed diff --git a/spec/frontend/sidebar/assignees_spec.js b/spec/frontend/sidebar/assignees_spec.js index fcd08dc2dc7..0cb182b2df4 100644 --- a/spec/frontend/sidebar/assignees_spec.js +++ b/spec/frontend/sidebar/assignees_spec.js @@ -15,7 +15,6 @@ describe('Assignee component', () => { const createWrapper = (propsData = getDefaultProps()) => { wrapper = mount(Assignee, { propsData, - attachToDocument: true, }); }; diff --git a/spec/frontend/sidebar/components/assignees/assignee_avatar_link_spec.js b/spec/frontend/sidebar/components/assignees/assignee_avatar_link_spec.js index 8d57fd94eb5..03d1ac3ab8d 100644 --- a/spec/frontend/sidebar/components/assignees/assignee_avatar_link_spec.js +++ b/spec/frontend/sidebar/components/assignees/assignee_avatar_link_spec.js @@ -23,7 +23,6 @@ describe('AssigneeAvatarLink component', () => { }; wrapper = shallowMount(AssigneeAvatarLink, { - attachToDocument: true, propsData, }); } diff --git a/spec/frontend/sidebar/components/assignees/collapsed_assignee_list_spec.js b/spec/frontend/sidebar/components/assignees/collapsed_assignee_list_spec.js index a303e5f493e..a1e19c1dd8e 100644 --- a/spec/frontend/sidebar/components/assignees/collapsed_assignee_list_spec.js +++ b/spec/frontend/sidebar/components/assignees/collapsed_assignee_list_spec.js @@ -16,7 +16,6 @@ describe('CollapsedAssigneeList component', () => { }; wrapper = shallowMount(CollapsedAssigneeList, { - attachToDocument: true, propsData, }); } diff --git a/spec/frontend/sidebar/components/assignees/uncollapsed_assignee_list_spec.js b/spec/frontend/sidebar/components/assignees/uncollapsed_assignee_list_spec.js index 6d8e62404e0..1cf0af48bef 100644 --- a/spec/frontend/sidebar/components/assignees/uncollapsed_assignee_list_spec.js +++ b/spec/frontend/sidebar/components/assignees/uncollapsed_assignee_list_spec.js @@ -18,7 +18,6 @@ describe('UncollapsedAssigneeList component', () => { }; wrapper = mount(UncollapsedAssigneeList, { - attachToDocument: true, propsData, }); } diff --git a/spec/graphql/types/group_type_spec.rb b/spec/graphql/types/group_type_spec.rb index 3dd5b602aa2..de11bad0723 100644 --- a/spec/graphql/types/group_type_spec.rb +++ b/spec/graphql/types/group_type_spec.rb @@ -8,4 +8,10 @@ describe GitlabSchema.types['Group'] do it { expect(described_class.graphql_name).to eq('Group') } it { expect(described_class).to require_graphql_authorizations(:read_group) } + + it 'has the expected fields' do + expected_fields = %w[web_url avatar_url mentions_disabled parent] + + is_expected.to include_graphql_fields(*expected_fields) + end end diff --git a/spec/lib/gitlab/ci/yaml_processor_spec.rb b/spec/lib/gitlab/ci/yaml_processor_spec.rb index 058afddd73f..11168a969fc 100644 --- a/spec/lib/gitlab/ci/yaml_processor_spec.rb +++ b/spec/lib/gitlab/ci/yaml_processor_spec.rb @@ -1331,9 +1331,9 @@ module Gitlab stub_feature_flags(ci_release_generation: false) end - it "returns release info" do - expect(processor.stage_builds_attributes('release').first[:options].include?(config[:release])) - .to be false + it 'raises error' do + expect { processor }.to raise_error( + 'jobs:release config release features are not enabled: release') end end end diff --git a/spec/lib/gitlab/import_export/base_object_builder_spec.rb b/spec/lib/gitlab/import_export/base_object_builder_spec.rb new file mode 100644 index 00000000000..fbb3b08cf56 --- /dev/null +++ b/spec/lib/gitlab/import_export/base_object_builder_spec.rb @@ -0,0 +1,53 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Gitlab::ImportExport::BaseObjectBuilder do + let(:project) do + create(:project, :repository, + :builds_disabled, + :issues_disabled, + name: 'project', + path: 'project') + end + let(:klass) { Milestone } + let(:attributes) { { 'title' => 'Test BaseObjectBuilder Milestone', 'project' => project } } + + subject { described_class.build(klass, attributes) } + + describe '#build' do + context 'when object exists' do + context 'when where_clauses are implemented' do + before do + allow_next_instance_of(described_class) do |object_builder| + allow(object_builder).to receive(:where_clauses).and_return([klass.arel_table['title'].eq(attributes['title'])]) + end + end + + let!(:milestone) { create(:milestone, title: attributes['title'], project: project) } + + it 'finds existing object instead of creating one' do + expect(subject).to eq(milestone) + end + end + + context 'when where_clauses are not implemented' do + it 'raises NotImplementedError' do + expect { subject }.to raise_error(NotImplementedError) + end + end + end + + context 'when object does not exist' do + before do + allow_next_instance_of(described_class) do |object_builder| + allow(object_builder).to receive(:find_object).and_return(nil) + end + end + + it 'creates new object' do + expect { subject }.to change { Milestone.count }.from(0).to(1) + end + end + end +end diff --git a/spec/lib/gitlab/import_export/base_relation_factory_spec.rb b/spec/lib/gitlab/import_export/base_relation_factory_spec.rb new file mode 100644 index 00000000000..def3e43de9b --- /dev/null +++ b/spec/lib/gitlab/import_export/base_relation_factory_spec.rb @@ -0,0 +1,145 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Gitlab::ImportExport::BaseRelationFactory do + let(:user) { create(:admin) } + let(:project) { create(:project) } + let(:members_mapper) { double('members_mapper').as_null_object } + let(:relation_sym) { :project_snippets } + let(:merge_requests_mapping) { {} } + let(:relation_hash) { {} } + let(:excluded_keys) { [] } + + subject do + described_class.create(relation_sym: relation_sym, + relation_hash: relation_hash, + object_builder: Gitlab::ImportExport::GroupProjectObjectBuilder, + members_mapper: members_mapper, + merge_requests_mapping: merge_requests_mapping, + user: user, + importable: project, + excluded_keys: excluded_keys) + end + + describe '#create' do + context 'when relation is invalid' do + before do + expect_next_instance_of(described_class) do |relation_factory| + expect(relation_factory).to receive(:invalid_relation?).and_return(true) + end + end + + it 'returns without creating new relations' do + expect(subject).to be_nil + end + end + + context 'when #setup_models is not implemented' do + it 'raises NotImplementedError' do + expect { subject }.to raise_error(NotImplementedError) + end + end + + context 'when #setup_models is implemented' do + let(:relation_sym) { :notes } + let(:relation_hash) do + { + "id" => 4947, + "note" => "merged", + "noteable_type" => "MergeRequest", + "author_id" => 999, + "created_at" => "2016-11-18T09:29:42.634Z", + "updated_at" => "2016-11-18T09:29:42.634Z", + "project_id" => 1, + "attachment" => { + "url" => nil + }, + "noteable_id" => 377, + "system" => true, + "events" => [] + } + end + + before do + expect_next_instance_of(described_class) do |relation_factory| + expect(relation_factory).to receive(:setup_models).and_return(true) + end + end + + it 'creates imported object' do + expect(subject).to be_instance_of(Note) + end + + context 'when relation contains user references' do + let(:new_user) { create(:user) } + let(:exported_member) do + { + "id" => 111, + "access_level" => 30, + "source_id" => 1, + "source_type" => "Project", + "user_id" => 3, + "notification_level" => 3, + "created_at" => "2016-11-18T09:29:42.634Z", + "updated_at" => "2016-11-18T09:29:42.634Z", + "user" => { + "id" => 999, + "email" => new_user.email, + "username" => new_user.username + } + } + end + + let(:members_mapper) do + Gitlab::ImportExport::MembersMapper.new( + exported_members: [exported_member], + user: user, + importable: project) + end + + it 'maps the right author to the imported note' do + expect(subject.author).to eq(new_user) + end + end + + context 'when relation contains token attributes' do + let(:relation_sym) { 'ProjectHook' } + let(:relation_hash) { { token: 'secret' } } + + it 'removes token attributes' do + expect(subject.token).to be_nil + end + end + + context 'when relation contains encrypted attributes' do + let(:relation_sym) { 'Ci::Variable' } + let(:relation_hash) do + create(:ci_variable).as_json + end + + it 'removes encrypted attributes' do + expect(subject.value).to be_nil + end + end + end + end + + describe '.relation_class' do + context 'when relation name is pluralized' do + let(:relation_name) { 'MergeRequest::Metrics' } + + it 'returns constantized class' do + expect(described_class.relation_class(relation_name)).to eq(MergeRequest::Metrics) + end + end + + context 'when relation name is singularized' do + let(:relation_name) { 'Badge' } + + it 'returns constantized class' do + expect(described_class.relation_class(relation_name)).to eq(Badge) + end + end + end +end diff --git a/spec/lib/gitlab/import_export/relation_factory_spec.rb b/spec/lib/gitlab/import_export/project_relation_factory_spec.rb index 5704f823b93..0ade7ac4fc7 100644 --- a/spec/lib/gitlab/import_export/relation_factory_spec.rb +++ b/spec/lib/gitlab/import_export/project_relation_factory_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Gitlab::ImportExport::RelationFactory do +describe Gitlab::ImportExport::ProjectRelationFactory do let(:group) { create(:group) } let(:project) { create(:project, :repository, group: group) } let(:members_mapper) { double('members_mapper').as_null_object } @@ -12,10 +12,11 @@ describe Gitlab::ImportExport::RelationFactory do let(:created_object) do described_class.create(relation_sym: relation_sym, relation_hash: relation_hash, + object_builder: Gitlab::ImportExport::GroupProjectObjectBuilder, members_mapper: members_mapper, merge_requests_mapping: merge_requests_mapping, user: user, - project: project, + importable: project, excluded_keys: excluded_keys) end @@ -97,7 +98,7 @@ describe Gitlab::ImportExport::RelationFactory do end end - context 'merge_requset object' do + context 'merge_request object' do let(:relation_sym) { :merge_requests } let(:exported_member) do @@ -244,11 +245,11 @@ describe Gitlab::ImportExport::RelationFactory do context 'Project references' do let(:relation_sym) { :project_foo_model } let(:relation_hash) do - Gitlab::ImportExport::RelationFactory::PROJECT_REFERENCES.map { |ref| { ref => 99 } }.inject(:merge) + Gitlab::ImportExport::ProjectRelationFactory::PROJECT_REFERENCES.map { |ref| { ref => 99 } }.inject(:merge) end class ProjectFooModel < FooModel - attr_accessor(*Gitlab::ImportExport::RelationFactory::PROJECT_REFERENCES) + attr_accessor(*Gitlab::ImportExport::ProjectRelationFactory::PROJECT_REFERENCES) end before do diff --git a/spec/lib/gitlab/import_export/relation_tree_restorer_spec.rb b/spec/lib/gitlab/import_export/relation_tree_restorer_spec.rb index c761f9652ab..edb2c0a131a 100644 --- a/spec/lib/gitlab/import_export/relation_tree_restorer_spec.rb +++ b/spec/lib/gitlab/import_export/relation_tree_restorer_spec.rb @@ -27,6 +27,7 @@ describe Gitlab::ImportExport::RelationTreeRestorer do shared: shared, tree_hash: tree_hash, importable: importable, + object_builder: object_builder, members_mapper: members_mapper, relation_factory: relation_factory, reader: reader @@ -38,7 +39,8 @@ describe Gitlab::ImportExport::RelationTreeRestorer do context 'when restoring a project' do let(:path) { 'spec/fixtures/lib/gitlab/import_export/complex/project.json' } let(:importable) { create(:project, :builds_enabled, :issues_disabled, name: 'project', path: 'project') } - let(:relation_factory) { Gitlab::ImportExport::RelationFactory } + let(:object_builder) { Gitlab::ImportExport::GroupProjectObjectBuilder } + let(:relation_factory) { Gitlab::ImportExport::ProjectRelationFactory } let(:reader) { Gitlab::ImportExport::Reader.new(shared: shared) } let(:tree_hash) { importable_hash } diff --git a/spec/lib/gitlab/import_export/safe_model_attributes.yml b/spec/lib/gitlab/import_export/safe_model_attributes.yml index 01beb5ba33c..ad363233bfe 100644 --- a/spec/lib/gitlab/import_export/safe_model_attributes.yml +++ b/spec/lib/gitlab/import_export/safe_model_attributes.yml @@ -545,6 +545,7 @@ ProjectFeature: - id - project_id - merge_requests_access_level +- forking_access_level - issues_access_level - wiki_access_level - snippets_access_level diff --git a/spec/models/error_tracking/project_error_tracking_setting_spec.rb b/spec/models/error_tracking/project_error_tracking_setting_spec.rb index 6babc39cdc3..5b402e572c3 100644 --- a/spec/models/error_tracking/project_error_tracking_setting_spec.rb +++ b/spec/models/error_tracking/project_error_tracking_setting_spec.rb @@ -64,6 +64,22 @@ describe ErrorTracking::ProjectErrorTrackingSetting do end end + describe '.extract_sentry_external_url' do + subject { described_class.extract_sentry_external_url(sentry_url) } + + describe 'when passing a URL' do + let(:sentry_url) { 'https://sentrytest.gitlab.com/api/0/projects/sentry-org/sentry-project' } + + it { is_expected.to eq('https://sentrytest.gitlab.com/sentry-org/sentry-project') } + end + + describe 'when passing nil' do + let(:sentry_url) { nil } + + it { is_expected.to be_nil } + end + end + describe '#sentry_external_url' do let(:sentry_url) { 'https://sentrytest.gitlab.com/api/0/projects/sentry-org/sentry-project' } diff --git a/spec/requests/api/groups_spec.rb b/spec/requests/api/groups_spec.rb index a4f68df928f..35b77832c73 100644 --- a/spec/requests/api/groups_spec.rb +++ b/spec/requests/api/groups_spec.rb @@ -358,6 +358,7 @@ describe API::Groups do expect(json_response['two_factor_grace_period']).to eq(group1.two_factor_grace_period) expect(json_response['auto_devops_enabled']).to eq(group1.auto_devops_enabled) expect(json_response['emails_disabled']).to eq(group1.emails_disabled) + expect(json_response['mentions_disabled']).to eq(group1.mentions_disabled) expect(json_response['project_creation_level']).to eq('maintainer') expect(json_response['subgroup_creation_level']).to eq('maintainer') expect(json_response['web_url']).to eq(group1.web_url) @@ -556,6 +557,7 @@ describe API::Groups do expect(json_response['two_factor_grace_period']).to eq(48) expect(json_response['auto_devops_enabled']).to eq(nil) expect(json_response['emails_disabled']).to eq(nil) + expect(json_response['mentions_disabled']).to eq(nil) expect(json_response['project_creation_level']).to eq("noone") expect(json_response['subgroup_creation_level']).to eq("maintainer") expect(json_response['request_access_enabled']).to eq(true) diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index e1297c035b5..fce49d0248c 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -2858,6 +2858,20 @@ describe API::Projects do expect(json_response['message']).to eq('401 Unauthorized') end end + + context 'forking disabled' do + before do + project.project_feature.update_attribute( + :forking_access_level, ProjectFeature::DISABLED) + end + + it 'denies project to be forked' do + post api("/projects/#{project.id}/fork", admin) + + expect(response).to have_gitlab_http_status(409) + expect(json_response['message']['forked_from_project_id']).to eq(['is forbidden']) + end + end end describe 'POST /projects/:id/housekeeping' do diff --git a/spec/services/projects/fork_service_spec.rb b/spec/services/projects/fork_service_spec.rb index fc01c93b5cf..e7b904fcd60 100644 --- a/spec/services/projects/fork_service_spec.rb +++ b/spec/services/projects/fork_service_spec.rb @@ -224,6 +224,19 @@ describe Projects::ForkService do end end end + + context 'when forking is disabled' do + before do + @from_project.project_feature.update_attribute( + :forking_access_level, ProjectFeature::DISABLED) + end + + it 'fails' do + to_project = fork_project(@from_project, @to_user, namespace: @to_user.namespace) + + expect(to_project.errors[:forked_from_project_id]).to eq(['is forbidden']) + end + end end describe 'fork to namespace' do diff --git a/spec/services/system_note_service_spec.rb b/spec/services/system_note_service_spec.rb index fa7b1003b8d..4ba22af85f0 100644 --- a/spec/services/system_note_service_spec.rb +++ b/spec/services/system_note_service_spec.rb @@ -76,28 +76,14 @@ describe SystemNoteService do end describe '.change_due_date' do - subject { described_class.change_due_date(noteable, project, author, due_date) } + let(:due_date) { double } - let(:due_date) { Date.today } - - it_behaves_like 'a note with overridable created_at' - - it_behaves_like 'a system note' do - let(:action) { 'due_date' } - end - - context 'when due date added' do - it 'sets the note text' do - expect(subject.note).to eq "changed due date to #{Date.today.to_s(:long)}" + it 'calls TimeTrackingService' do + expect_next_instance_of(::SystemNotes::TimeTrackingService) do |service| + expect(service).to receive(:change_due_date).with(due_date) end - end - context 'when due date removed' do - let(:due_date) { nil } - - it 'sets the note text' do - expect(subject.note).to eq 'removed due date' - end + described_class.change_due_date(noteable, project, author, due_date) end end @@ -488,36 +474,12 @@ describe SystemNoteService do end describe '.change_time_estimate' do - subject { described_class.change_time_estimate(noteable, project, author) } - - it_behaves_like 'a system note' do - let(:action) { 'time_tracking' } - end - - context 'with a time estimate' do - it 'sets the note text' do - noteable.update_attribute(:time_estimate, 277200) - - expect(subject.note).to eq "changed time estimate to 1w 4d 5h" - end - - context 'when time_tracking_limit_to_hours setting is true' do - before do - stub_application_setting(time_tracking_limit_to_hours: true) - end - - it 'sets the note text' do - noteable.update_attribute(:time_estimate, 277200) - - expect(subject.note).to eq "changed time estimate to 77h" - end + it 'calls TimeTrackingService' do + expect_next_instance_of(::SystemNotes::TimeTrackingService) do |service| + expect(service).to receive(:change_time_estimate) end - end - context 'without a time estimate' do - it 'sets the note text' do - expect(subject.note).to eq "removed time estimate" - end + described_class.change_time_estimate(noteable, project, author) end end @@ -548,61 +510,12 @@ describe SystemNoteService do end describe '.change_time_spent' do - # We need a custom noteable in order to the shared examples to be green. - let(:noteable) do - mr = create(:merge_request, source_project: project) - mr.spend_time(duration: 360000, user_id: author.id) - mr.save! - mr - end - - subject do - described_class.change_time_spent(noteable, project, author) - end - - it_behaves_like 'a system note' do - let(:action) { 'time_tracking' } - end - - context 'when time was added' do - it 'sets the note text' do - spend_time!(277200) - - expect(subject.note).to eq "added 1w 4d 5h of time spent" + it 'calls TimeTrackingService' do + expect_next_instance_of(::SystemNotes::TimeTrackingService) do |service| + expect(service).to receive(:change_time_spent) end - end - - context 'when time was subtracted' do - it 'sets the note text' do - spend_time!(-277200) - - expect(subject.note).to eq "subtracted 1w 4d 5h of time spent" - end - end - - context 'when time was removed' do - it 'sets the note text' do - spend_time!(:reset) - expect(subject.note).to eq "removed time spent" - end - end - - context 'when time_tracking_limit_to_hours setting is true' do - before do - stub_application_setting(time_tracking_limit_to_hours: true) - end - - it 'sets the note text' do - spend_time!(277200) - - expect(subject.note).to eq "added 77h of time spent" - end - end - - def spend_time!(seconds) - noteable.spend_time(duration: seconds, user_id: author.id) - noteable.save! + described_class.change_time_spent(noteable, project, author) end end diff --git a/spec/services/system_notes/time_tracking_service_spec.rb b/spec/services/system_notes/time_tracking_service_spec.rb new file mode 100644 index 00000000000..7e3e6a75cdf --- /dev/null +++ b/spec/services/system_notes/time_tracking_service_spec.rb @@ -0,0 +1,129 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe ::SystemNotes::TimeTrackingService do + let_it_be(:author) { create(:user) } + let_it_be(:project) { create(:project, :repository) } + + let(:noteable) { create(:issue, project: project) } + + describe '#change_due_date' do + subject { described_class.new(noteable: noteable, project: project, author: author).change_due_date(due_date) } + + let(:due_date) { Date.today } + + it_behaves_like 'a note with overridable created_at' + + it_behaves_like 'a system note' do + let(:action) { 'due_date' } + end + + context 'when due date added' do + it 'sets the note text' do + expect(subject.note).to eq "changed due date to #{due_date.to_s(:long)}" + end + end + + context 'when due date removed' do + let(:due_date) { nil } + + it 'sets the note text' do + expect(subject.note).to eq 'removed due date' + end + end + end + + describe '.change_time_estimate' do + subject { described_class.new(noteable: noteable, project: project, author: author).change_time_estimate } + + it_behaves_like 'a system note' do + let(:action) { 'time_tracking' } + end + + context 'with a time estimate' do + it 'sets the note text' do + noteable.update_attribute(:time_estimate, 277200) + + expect(subject.note).to eq "changed time estimate to 1w 4d 5h" + end + + context 'when time_tracking_limit_to_hours setting is true' do + before do + stub_application_setting(time_tracking_limit_to_hours: true) + end + + it 'sets the note text' do + noteable.update_attribute(:time_estimate, 277200) + + expect(subject.note).to eq "changed time estimate to 77h" + end + end + end + + context 'without a time estimate' do + it 'sets the note text' do + expect(subject.note).to eq "removed time estimate" + end + end + end + + describe '.change_time_spent' do + # We need a custom noteable in order to the shared examples to be green. + let(:noteable) do + mr = create(:merge_request, source_project: project) + mr.spend_time(duration: 360000, user_id: author.id) + mr.save! + mr + end + + subject do + described_class.new(noteable: noteable, project: project, author: author).change_time_spent + end + + it_behaves_like 'a system note' do + let(:action) { 'time_tracking' } + end + + context 'when time was added' do + it 'sets the note text' do + spend_time!(277200) + + expect(subject.note).to eq "added 1w 4d 5h of time spent" + end + end + + context 'when time was subtracted' do + it 'sets the note text' do + spend_time!(-277200) + + expect(subject.note).to eq "subtracted 1w 4d 5h of time spent" + end + end + + context 'when time was removed' do + it 'sets the note text' do + spend_time!(:reset) + + expect(subject.note).to eq "removed time spent" + end + end + + context 'when time_tracking_limit_to_hours setting is true' do + before do + stub_application_setting(time_tracking_limit_to_hours: true) + end + + it 'sets the note text' do + spend_time!(277200) + + expect(subject.note).to eq "added 77h of time spent" + end + end + + def spend_time!(seconds) + noteable.spend_time(duration: seconds, user_id: author.id) + noteable.save! + end + end +end diff --git a/spec/support/import_export/configuration_helper.rb b/spec/support/import_export/configuration_helper.rb index 2e5a99bb8b2..27819b5201a 100644 --- a/spec/support/import_export/configuration_helper.rb +++ b/spec/support/import_export/configuration_helper.rb @@ -36,8 +36,8 @@ module ConfigurationHelper end def relation_class_for_name(relation_name) - relation_name = Gitlab::ImportExport::RelationFactory.overrides[relation_name.to_sym] || relation_name - Gitlab::ImportExport::RelationFactory.relation_class(relation_name) + relation_name = Gitlab::ImportExport::ProjectRelationFactory.overrides[relation_name.to_sym] || relation_name + Gitlab::ImportExport::ProjectRelationFactory.relation_class(relation_name) end def parsed_attributes(relation_name, attributes, config: Gitlab::ImportExport.config_file) |