-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
#-- copyright | ||
# OpenProject is an open source project management software. | ||
# Copyright (C) 2012-2020 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-2017 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 docs/COPYRIGHT.rdoc for more details. | ||
#++ | ||
|
||
FactoryBot.define do | ||
factory :company do | ||
sequence(:name) { |n| "Company No. #{n}" } | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
#-- copyright | ||
# OpenProject is an open source project management software. | ||
# Copyright (C) 2012-2020 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-2017 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 docs/COPYRIGHT.rdoc for more details. | ||
#++ | ||
|
||
FactoryBot.define do | ||
factory :share | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,261 @@ | ||
#-- copyright | ||
# OpenProject is an open source project management software. | ||
# Copyright (C) 2012-2020 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-2017 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 docs/COPYRIGHT.rdoc for more details. | ||
#++ | ||
|
||
require 'spec_helper' | ||
Check notice on line 29 in spec/requests/api/v3/companies_resource_spec.rb GitHub Actions / rubocop[rubocop] spec/requests/api/v3/companies_resource_spec.rb#L29 <Style/StringLiterals>
Raw output
|
||
require 'rack/test' | ||
Check notice on line 30 in spec/requests/api/v3/companies_resource_spec.rb GitHub Actions / rubocop[rubocop] spec/requests/api/v3/companies_resource_spec.rb#L30 <Style/StringLiterals>
Raw output
|
||
|
||
# For the sake of this coding exercise, a company is a very simple structure that only has | ||
# * an id | ||
# * a name | ||
# * a single owner | ||
# | ||
# The owner is a User object that already exists in OpenProject. Consequently, there are also | ||
# representers already available for rendering a user (API::V3::Users::UserRepresenter). | ||
# | ||
# The company can also belong to one or many different companies. This is expressed by a parent | ||
# company having a share in a child company. For the sake of simplicity a share is binary. A company | ||
# either has a share in another company or not. There is no representation of a ratio on how much | ||
# of the child company is owned by a parent company. However, a share can be inactive (because this is | ||
# an example). | ||
# | ||
# The resource should include: | ||
# * The id | ||
# * The name | ||
# * The actual users owning the company | ||
# | ||
# The first two are straight forward. The later however requires some explanation. For the sake of this | ||
# example, the set of owning users are those users, that are owners of companies, which are parents | ||
# (or any ancestor) to the company being represented. Those owners than overrule any owner directly | ||
# linked to the represented company. This overruling takes place on every level of ancestry. | ||
# | ||
# E.g. In a set of companies | ||
# | ||
# grandparent - (owner A) | ||
# parent - (owner B) | ||
# child - (owner C) | ||
# | ||
# the owning user of child is A. | ||
# | ||
# To complicate matters, that overruling only takes place if the share is active. So in the example above, | ||
# with the share between parent and grandparent not being active, the owning user of child would be B. | ||
# | ||
# If a company has no parent or only has parents on inactive shares, the owning user is the user of the company. | ||
# Referring to the example again, if the share between child and parent were to be inactive (or to not exist | ||
# at all), the owning user of child would be C. | ||
# | ||
# Since a company can have multiple parents, there can also be multiple owning users | ||
# | ||
# E.g. in a set of companies | ||
# | ||
# grandgrandparent 1 (parent to grandparent 2) - (owner A) | ||
# grandparent 1 - (owner B) grandparent 2 - (owner C) | ||
# parent - (owner D) | ||
# child - (owner E) | ||
# | ||
# assuming that every share is active, the owning users of child would be A and B. | ||
|
||
# rubocop:disable RSpec/IndexedLet | ||
Check warning on line 82 in spec/requests/api/v3/companies_resource_spec.rb GitHub Actions / rubocop[rubocop] spec/requests/api/v3/companies_resource_spec.rb#L82 <Lint/RedundantCopDisableDirective>
Raw output
|
||
RSpec.describe 'API v3 companies resource', content_type: :json do | ||
Check notice on line 83 in spec/requests/api/v3/companies_resource_spec.rb GitHub Actions / rubocop[rubocop] spec/requests/api/v3/companies_resource_spec.rb#L83 <Style/StringLiterals>
Raw output
|
||
include Rack::Test::Methods | ||
include API::V3::Utilities::PathHelper | ||
|
||
subject(:response) { last_response } | ||
|
||
let(:admin) do | ||
create(:admin) | ||
end | ||
let(:owner) do | ||
create(:user, firstname: 'The', lastname: 'owner') | ||
Check notice on line 93 in spec/requests/api/v3/companies_resource_spec.rb GitHub Actions / rubocop[rubocop] spec/requests/api/v3/companies_resource_spec.rb#L93 <Style/StringLiterals>
Raw output
Check notice on line 93 in spec/requests/api/v3/companies_resource_spec.rb GitHub Actions / rubocop[rubocop] spec/requests/api/v3/companies_resource_spec.rb#L93 <Style/StringLiterals>
Raw output
|
||
end | ||
let(:company) do | ||
create(:company, owner:) | ||
end | ||
|
||
current_user do | ||
create(:user) | ||
end | ||
|
||
describe 'GET /api/v3/companies/:id' do | ||
Check notice on line 103 in spec/requests/api/v3/companies_resource_spec.rb GitHub Actions / rubocop[rubocop] spec/requests/api/v3/companies_resource_spec.rb#L103 <Style/StringLiterals>
Raw output
|
||
let(:path) { api_v3_paths.company(company.id) } | ||
|
||
before do | ||
get path | ||
end | ||
|
||
it 'returns 200 OK' do | ||
Check notice on line 110 in spec/requests/api/v3/companies_resource_spec.rb GitHub Actions / rubocop[rubocop] spec/requests/api/v3/companies_resource_spec.rb#L110 <Style/StringLiterals>
Raw output
|
||
expect(subject.status) | ||
.to be(200) | ||
end | ||
|
||
it 'returns the company' do | ||
Check notice on line 115 in spec/requests/api/v3/companies_resource_spec.rb GitHub Actions / rubocop[rubocop] spec/requests/api/v3/companies_resource_spec.rb#L115 <Style/StringLiterals>
Raw output
|
||
expect(subject.body) | ||
.to be_json_eql('Company'.to_json) | ||
Check notice on line 117 in spec/requests/api/v3/companies_resource_spec.rb GitHub Actions / rubocop[rubocop] spec/requests/api/v3/companies_resource_spec.rb#L117 <Style/StringLiterals>
Raw output
|
||
.at_path('_type') | ||
Check notice on line 118 in spec/requests/api/v3/companies_resource_spec.rb GitHub Actions / rubocop[rubocop] spec/requests/api/v3/companies_resource_spec.rb#L118 <Style/StringLiterals>
Raw output
|
||
|
||
expect(subject.body) | ||
.to be_json_eql(company.id.to_json) | ||
.at_path('id') | ||
Check notice on line 122 in spec/requests/api/v3/companies_resource_spec.rb GitHub Actions / rubocop[rubocop] spec/requests/api/v3/companies_resource_spec.rb#L122 <Style/StringLiterals>
Raw output
|
||
|
||
expect(subject.body) | ||
.to be_json_eql(company.name.to_json) | ||
.at_path('name') | ||
Check notice on line 126 in spec/requests/api/v3/companies_resource_spec.rb GitHub Actions / rubocop[rubocop] spec/requests/api/v3/companies_resource_spec.rb#L126 <Style/StringLiterals>
Raw output
|
||
end | ||
|
||
it 'references the owning users' do | ||
Check notice on line 129 in spec/requests/api/v3/companies_resource_spec.rb GitHub Actions / rubocop[rubocop] spec/requests/api/v3/companies_resource_spec.rb#L129 <Style/StringLiterals>
Raw output
|
||
# References the owner of the company | ||
expect(subject.body) | ||
.to be_json_eql(api_v3_paths.user(owner.id).to_json) | ||
.at_path('_links/owningUsers/0/href') | ||
Check notice on line 133 in spec/requests/api/v3/companies_resource_spec.rb GitHub Actions / rubocop[rubocop] spec/requests/api/v3/companies_resource_spec.rb#L133 <Style/StringLiterals>
Raw output
|
||
|
||
expect(subject.body) | ||
.to be_json_eql(owner.name.to_json) | ||
.at_path('_embedded/owningUsers/0/name') | ||
Check notice on line 137 in spec/requests/api/v3/companies_resource_spec.rb GitHub Actions / rubocop[rubocop] spec/requests/api/v3/companies_resource_spec.rb#L137 <Style/StringLiterals>
Raw output
|
||
end | ||
|
||
context 'with a web of companies' do | ||
Check notice on line 140 in spec/requests/api/v3/companies_resource_spec.rb GitHub Actions / rubocop[rubocop] spec/requests/api/v3/companies_resource_spec.rb#L140 <Style/StringLiterals>
Raw output
|
||
let(:parent_company1_2_1) do | ||
create(:company, owner: owner_pc1_2_1) | ||
end | ||
let(:parent_company1_2_2) do | ||
create(:company, owner: owner_pc1_2_2) | ||
end | ||
|
||
let(:parent_company1_1) do | ||
create(:company, owner: owner_pc1_1) | ||
end | ||
let(:parent_company1_2) do | ||
create(:company, owner: owner_pc1_2).tap do |company| | ||
create(:share, active: false, parent: parent_company1_2_1, child: company) | ||
create(:share, active: true, parent: parent_company1_2_2, child: company) | ||
end | ||
end | ||
|
||
let(:parent_company1) do | ||
create(:company, owner: owner_pc1).tap do |company| | ||
create(:share, active: false, parent: parent_company1_1, child: company) | ||
create(:share, active: true, parent: parent_company1_2, child: company) | ||
end | ||
end | ||
|
||
let(:parent_company2_1_1) do | ||
create(:company, owner: owner_pc2_1_1) | ||
end | ||
|
||
let(:parent_company2_3_1) do | ||
create(:company, owner: owner_pc2_3_1) | ||
end | ||
|
||
let(:parent_company2_3_2) do | ||
create(:company, owner: owner_pc2_3_2) | ||
end | ||
|
||
let(:parent_company2_1) do | ||
create(:company, owner: owner_pc2_1).tap do |company| | ||
create(:share, active: true, parent: parent_company2_1_1, child: company) | ||
end | ||
end | ||
|
||
let(:parent_company2_2) do | ||
create(:company, owner: owner_pc2_2) | ||
end | ||
|
||
let(:parent_company2_3) do | ||
create(:company, owner: owner_pc2_3).tap do |company| | ||
create(:share, active: false, parent: parent_company2_3_1, child: company) | ||
create(:share, active: false, parent: parent_company2_3_2, child: company) | ||
end | ||
end | ||
|
||
let(:parent_company2) do | ||
create(:company, owner: owner_pc2).tap do |company| | ||
create(:share, active: false, parent: parent_company2_1, child: company) | ||
create(:share, active: true, parent: parent_company2_2, child: company) | ||
create(:share, active: true, parent: parent_company2_3, child: company) | ||
end | ||
end | ||
|
||
let(:company) do | ||
create(:company, owner:).tap do |company| | ||
create(:share, active: true, parent: parent_company1, child: company) | ||
create(:share, active: true, parent: parent_company2, child: company) | ||
end | ||
end | ||
|
||
let(:owner_pc2) { create(:user) } | ||
let(:owner_pc2_1) { create(:user) } | ||
let(:owner_pc2_2) { create(:user) } | ||
let(:owner_pc2_3) { create(:user) } | ||
let(:owner_pc2_3_1) { create(:user) } | ||
let(:owner_pc2_3_2) { create(:user) } | ||
let(:owner_pc2_1_1) { create(:user) } | ||
let(:owner_pc1) { create(:user) } | ||
let(:owner_pc1_1) { create(:user) } | ||
let(:owner_pc1_2) { create(:user) } | ||
let(:owner_pc1_2_1) { create(:user) } | ||
let(:owner_pc1_2_2) { create(:user) } | ||
|
||
let(:chairman) do | ||
create(:user, firstname: 'Big', lastname: 'Boss') | ||
Check notice on line 223 in spec/requests/api/v3/companies_resource_spec.rb GitHub Actions / rubocop[rubocop] spec/requests/api/v3/companies_resource_spec.rb#L223 <Style/StringLiterals>
Raw output
Check notice on line 223 in spec/requests/api/v3/companies_resource_spec.rb GitHub Actions / rubocop[rubocop] spec/requests/api/v3/companies_resource_spec.rb#L223 <Style/StringLiterals>
Raw output
|
||
end | ||
|
||
let(:expected_owners) do | ||
[owner_pc1_2_2, | ||
owner_pc2_2, | ||
owner_pc2_3] | ||
end | ||
|
||
it 'references the owning_users (only those not owners of a company owned actively by another company)' do | ||
Check notice on line 232 in spec/requests/api/v3/companies_resource_spec.rb GitHub Actions / rubocop[rubocop] spec/requests/api/v3/companies_resource_spec.rb#L232 <Style/StringLiterals>
Raw output
|
||
# References the owner of the holding | ||
expect(subject.body) | ||
.to have_json_path('_links/owningUsers') | ||
Check notice on line 235 in spec/requests/api/v3/companies_resource_spec.rb GitHub Actions / rubocop[rubocop] spec/requests/api/v3/companies_resource_spec.rb#L235 <Style/StringLiterals>
Raw output
|
||
|
||
expect(JSON.parse(subject.body).dig('_links', 'owningUsers').pluck('href')) | ||
Check notice on line 237 in spec/requests/api/v3/companies_resource_spec.rb GitHub Actions / rubocop[rubocop] spec/requests/api/v3/companies_resource_spec.rb#L237 <Style/StringLiterals>
Raw output
Check notice on line 237 in spec/requests/api/v3/companies_resource_spec.rb GitHub Actions / rubocop[rubocop] spec/requests/api/v3/companies_resource_spec.rb#L237 <Style/StringLiterals>
Raw output
Check notice on line 237 in spec/requests/api/v3/companies_resource_spec.rb GitHub Actions / rubocop[rubocop] spec/requests/api/v3/companies_resource_spec.rb#L237 <Style/StringLiterals>
Raw output
|
||
.to match_array(expected_owners.map { |o| api_v3_paths.user(o.id) }) | ||
|
||
expect(subject.body) | ||
.to have_json_path('_embedded/owningUsers') | ||
Check notice on line 241 in spec/requests/api/v3/companies_resource_spec.rb GitHub Actions / rubocop[rubocop] spec/requests/api/v3/companies_resource_spec.rb#L241 <Style/StringLiterals>
Raw output
|
||
|
||
expect(JSON.parse(subject.body).dig('_embedded', 'owningUsers').pluck('id')) | ||
Check notice on line 243 in spec/requests/api/v3/companies_resource_spec.rb GitHub Actions / rubocop[rubocop] spec/requests/api/v3/companies_resource_spec.rb#L243 <Style/StringLiterals>
Raw output
Check notice on line 243 in spec/requests/api/v3/companies_resource_spec.rb GitHub Actions / rubocop[rubocop] spec/requests/api/v3/companies_resource_spec.rb#L243 <Style/StringLiterals>
Raw output
Check notice on line 243 in spec/requests/api/v3/companies_resource_spec.rb GitHub Actions / rubocop[rubocop] spec/requests/api/v3/companies_resource_spec.rb#L243 <Style/StringLiterals>
Raw output
|
||
.to match_array(expected_owners.map(&:id)) | ||
end | ||
end | ||
|
||
context 'if querying a non existing company' do | ||
Check notice on line 248 in spec/requests/api/v3/companies_resource_spec.rb GitHub Actions / rubocop[rubocop] spec/requests/api/v3/companies_resource_spec.rb#L248 <Style/StringLiterals>
Raw output
|
||
let(:path) { api_v3_paths.company(company.id + 1) } | ||
|
||
it_behaves_like 'not found' | ||
Check notice on line 251 in spec/requests/api/v3/companies_resource_spec.rb GitHub Actions / rubocop[rubocop] spec/requests/api/v3/companies_resource_spec.rb#L251 <Style/StringLiterals>
Raw output
|
||
end | ||
|
||
context 'without begin logged in', with_settings: { login_required?: true } do | ||
Check notice on line 254 in spec/requests/api/v3/companies_resource_spec.rb GitHub Actions / rubocop[rubocop] spec/requests/api/v3/companies_resource_spec.rb#L254 <Style/StringLiterals>
Raw output
|
||
current_user { nil } | ||
|
||
it_behaves_like 'unauthenticated access' | ||
Check notice on line 257 in spec/requests/api/v3/companies_resource_spec.rb GitHub Actions / rubocop[rubocop] spec/requests/api/v3/companies_resource_spec.rb#L257 <Style/StringLiterals>
Raw output
|
||
end | ||
end | ||
end | ||
# rubocop:enable RSpec/IndexedLet |