Skip to content

Commit

Permalink
tests[Op#57902]: DRY up custom field mapping bulk create unit specs
Browse files Browse the repository at this point in the history
  • Loading branch information
akabiru committed Sep 30, 2024
1 parent 4f37547 commit 4f94f66
Show file tree
Hide file tree
Showing 7 changed files with 186 additions and 281 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ def new

def create
create_service = ::CustomFields::CustomFieldProjects::BulkCreateService
.new(user: current_user, projects: @projects, custom_field: @custom_field,
.new(user: current_user, projects: @projects, model: @custom_field,
include_sub_projects: include_sub_projects?)
.call

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ def new_link

def link
create_service = ProjectCustomFieldProjectMappings::BulkCreateService
.new(user: current_user, projects: @projects, project_custom_field: @custom_field,
.new(user: current_user, projects: @projects, model: @custom_field,
include_sub_projects: include_sub_projects?)
.call

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,6 @@
module CustomFields
module CustomFieldProjects
class BulkCreateService < ::BulkServices::ProjectMappings::BaseCreateService
def initialize(user:, projects:, custom_field:, include_sub_projects: false)
super(user:, projects:, model: custom_field, include_sub_projects:)
end

def permission = :select_custom_fields
def model_foreign_key_id = :custom_field_id
def mapping_model_class = CustomFieldsProject
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,6 @@

module ProjectCustomFieldProjectMappings
class BulkCreateService < ::BulkServices::ProjectMappings::BaseCreateService
def initialize(user:, projects:, project_custom_field:, include_sub_projects: false)
super(user:, projects:, model: project_custom_field, include_sub_projects:)
end

private

def permission = :select_project_custom_fields
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# See COPYRIGHT and LICENSE files for more details.
#++

require "spec_helper"

RSpec.shared_examples "BulkServices project mappings create service" do
let(:model_mapping_class) { raise("Please define the model mapping class") }
let(:model_foreign_key_id) { raise("Please define the model foreign key id") }
let(:required_permission) { raise("Please define the required permission for the bulk create action") }
let(:model) { raise("Please define the model that will be linked to projects") }

context "with admin permissions" do
let(:user) { create(:admin) }

context "with a single project" do
let(:project) { create(:project) }
let(:instance) { described_class.new(user:, projects: [project], model:) }

it "creates the mappings" do
expect { instance.call }.to change(model_mapping_class, :count).by(1)

aggregate_failures "creates the mapping for the correct project and custom field" do
expect(model_mapping_class.where(model_foreign_key_id => model.id).pluck(:project_id)).to contain_exactly(project.id)
end
end
end

context "with subprojects" do
let(:projects) { create_list(:project, 2) }
let!(:subproject) { create(:project, parent: projects.first) }
let!(:subproject2) { create(:project, parent: subproject) }

it "creates the mappings for the project and sub-projects" do
create_service = described_class.new(user:, projects: projects.map(&:reload), model:,
include_sub_projects: true)

expect { create_service.call }.to change(model_mapping_class, :count).by(4)

aggregate_failures "creates the mapping for the correct project and custom field" do
expect(model_mapping_class.where(model_foreign_key_id => model.id).pluck(:project_id))
.to contain_exactly(*projects.map(&:id), subproject.id, subproject2.id)
end
end
end

context "with multiple projects including subprojects" do
let(:project) { create(:project) }
let!(:subproject) { create(:project, parent: project) }

it "creates the mappings for the project and sub-projects" do
create_service = described_class.new(user:, projects: [project.reload, subproject], model:,
include_sub_projects: true)

expect { create_service.call }.to change(model_mapping_class, :count).by(2)

aggregate_failures "creates the mapping for the correct project and custom field" do
expect(model_mapping_class.where(model_foreign_key_id => model.id).pluck(:project_id))
.to contain_exactly(project.id, subproject.id)
end
end
end

context "with duplicates" do
let(:project) { create(:project) }
let(:instance) { described_class.new(user:, projects: [project, project], model:) }

it "creates the mappings only once" do
expect { instance.call }.to change(model_mapping_class, :count).by(1)

aggregate_failures "creates the mapping for the correct project and custom field" do
expect(model_mapping_class.where(model_foreign_key_id => model.id).pluck(:project_id))
.to contain_exactly(project.id)
end
end
end
end

context "with non-admin but sufficient permissions" do
let(:user) do
create(:user,
member_with_permissions: {
project => %w[
view_work_packages
edit_project
].push(required_permission)
})
end

let(:project) { create(:project) }
let(:instance) { described_class.new(user:, projects: [project], model:) }

it "creates the mappings" do
expect { instance.call }.to change(model_mapping_class, :count).by(1)

aggregate_failures "creates the mapping for the correct project and custom field" do
expect(model_mapping_class.where(model_foreign_key_id => model.id).pluck(:project_id)).to contain_exactly(project.id)
end
end
end

context "without sufficient permissions" do
let(:user) do
create(:user,
member_with_permissions: {
project => %w[
view_work_packages
edit_project
]
})
end
let(:project) { create(:project) }
let(:instance) { described_class.new(user:, projects: [project], model:) }

it "does not create the mappings" do
expect { instance.call }.not_to change(model_mapping_class, :count)
expect(instance.call).to be_failure
end
end

context "with empty projects" do
let(:user) { create(:admin) }
let(:instance) { described_class.new(user:, projects: [], model:) }

it "does not create the mappings" do
service_result = instance.call
expect(service_result).to be_failure
expect(service_result.errors).to eq("not found")
end
end

context "with archived projects" do
let(:user) { create(:admin) }
let(:archived_project) { create(:project, active: false) }
let(:active_project) { create(:project) }

let(:instance) { described_class.new(user:, projects: [archived_project, active_project], model:) }

it "only creates mappins for the active project" do
expect { instance.call }.to change(model_mapping_class, :count).by(1)

aggregate_failures "creates the mapping for the correct project and custom field" do
expect(model_mapping_class.where(model_foreign_key_id => model.id).pluck(:project_id))
.to contain_exactly(active_project.id)
end
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -27,143 +27,15 @@
#++

require "spec_helper"
require_relative "../../bulk_services/project_mappings/behaves_like_bulk_project_mapping_create_service"

RSpec.describe CustomFields::CustomFieldProjects::BulkCreateService do
shared_let(:custom_field) { create(:wp_custom_field) }

context "with admin permissions" do
let(:user) { create(:admin) }

context "with a single project" do
let(:project) { create(:project) }
let(:instance) { described_class.new(user:, projects: [project], custom_field:) }

it "creates the mappings" do
expect { instance.call }.to change(CustomFieldsProject, :count).by(1)

aggregate_failures "creates the mapping for the correct project and custom field" do
expect(CustomFieldsProject.where(custom_field:).pluck(:project_id)).to contain_exactly(project.id)
end
end
end

context "with subprojects" do
let(:projects) { create_list(:project, 2) }
let!(:subproject) { create(:project, parent: projects.first) }
let!(:subproject2) { create(:project, parent: subproject) }

it "creates the mappings for the project and sub-projects" do
create_service = described_class.new(user:, projects: projects.map(&:reload), custom_field:,
include_sub_projects: true)

expect { create_service.call }.to change(CustomFieldsProject, :count).by(4)

aggregate_failures "creates the mapping for the correct project and custom field" do
expect(CustomFieldsProject.where(custom_field:).pluck(:project_id))
.to contain_exactly(*projects.map(&:id), subproject.id, subproject2.id)
end
end
end

context "with multiple projects including subprojects" do
let(:project) { create(:project) }
let!(:subproject) { create(:project, parent: project) }

it "creates the mappings for the project and sub-projects" do
create_service = described_class.new(user:, projects: [project.reload, subproject], custom_field:,
include_sub_projects: true)

expect { create_service.call }.to change(CustomFieldsProject, :count).by(2)

aggregate_failures "creates the mapping for the correct project and custom field" do
expect(CustomFieldsProject.where(custom_field:).pluck(:project_id))
.to contain_exactly(project.id, subproject.id)
end
end
end

context "with duplicates" do
let(:project) { create(:project) }
let(:instance) { described_class.new(user:, projects: [project, project], custom_field:) }

it "creates the mappings only once" do
expect { instance.call }.to change(CustomFieldsProject, :count).by(1)

aggregate_failures "creates the mapping for the correct project and custom field" do
expect(CustomFieldsProject.where(custom_field:).pluck(:project_id)).to contain_exactly(project.id)
end
end
end
end

context "with non-admin but sufficient permissions" do
let(:user) do
create(:user,
member_with_permissions: {
project => %w[
view_work_packages
edit_project
select_custom_fields
]
})
end

let(:project) { create(:project) }
let(:instance) { described_class.new(user:, projects: [project], custom_field:) }

it "creates the mappings" do
expect { instance.call }.to change(CustomFieldsProject, :count).by(1)

aggregate_failures "creates the mapping for the correct project and custom field" do
expect(CustomFieldsProject.where(custom_field:).pluck(:project_id)).to contain_exactly(project.id)
end
end
end

context "without sufficient permissions" do
let(:user) do
create(:user,
member_with_permissions: {
project => %w[
view_work_packages
edit_project
]
})
end
let(:project) { create(:project) }
let(:instance) { described_class.new(user:, projects: [project], custom_field:) }

it "does not create the mappings" do
expect { instance.call }.not_to change(CustomFieldsProject, :count)
expect(instance.call).to be_failure
end
end

context "with empty projects" do
let(:user) { create(:admin) }
let(:instance) { described_class.new(user:, projects: [], custom_field:) }

it "does not create the mappings" do
service_result = instance.call
expect(service_result).to be_failure
expect(service_result.errors).to eq("not found")
end
end

context "with archived projects" do
let(:user) { create(:admin) }
let(:archived_project) { create(:project, active: false) }
let(:active_project) { create(:project) }

let(:instance) { described_class.new(user:, projects: [archived_project, active_project], custom_field:) }

it "only creates mappins for the active project" do
expect { instance.call }.to change(CustomFieldsProject, :count).by(1)

aggregate_failures "creates the mapping for the correct project and custom field" do
expect(CustomFieldsProject.where(custom_field:).pluck(:project_id))
.to contain_exactly(active_project.id)
end
end
it_behaves_like "BulkServices project mappings create service" do
let(:model) { custom_field }
let(:model_mapping_class) { CustomFieldsProject }
let(:model_foreign_key_id) { :custom_field_id }
let(:required_permission) { :select_custom_fields }
end
end
Loading

0 comments on commit 4f94f66

Please sign in to comment.