summaryrefslogtreecommitdiff
path: root/spec/graphql/resolvers/design_management
diff options
context:
space:
mode:
Diffstat (limited to 'spec/graphql/resolvers/design_management')
-rw-r--r--spec/graphql/resolvers/design_management/design_at_version_resolver_spec.rb69
-rw-r--r--spec/graphql/resolvers/design_management/design_resolver_spec.rb88
-rw-r--r--spec/graphql/resolvers/design_management/designs_resolver_spec.rb93
-rw-r--r--spec/graphql/resolvers/design_management/version/design_at_version_resolver_spec.rb93
-rw-r--r--spec/graphql/resolvers/design_management/version/designs_at_version_resolver_spec.rb86
-rw-r--r--spec/graphql/resolvers/design_management/version_in_collection_resolver_spec.rb64
-rw-r--r--spec/graphql/resolvers/design_management/version_resolver_spec.rb43
-rw-r--r--spec/graphql/resolvers/design_management/versions_resolver_spec.rb117
8 files changed, 653 insertions, 0 deletions
diff --git a/spec/graphql/resolvers/design_management/design_at_version_resolver_spec.rb b/spec/graphql/resolvers/design_management/design_at_version_resolver_spec.rb
new file mode 100644
index 00000000000..a5054ae3ebf
--- /dev/null
+++ b/spec/graphql/resolvers/design_management/design_at_version_resolver_spec.rb
@@ -0,0 +1,69 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Resolvers::DesignManagement::DesignAtVersionResolver do
+ include GraphqlHelpers
+ include DesignManagementTestHelpers
+
+ let_it_be(:issue) { create(:issue) }
+ let_it_be(:project) { issue.project }
+ let_it_be(:user) { create(:user) }
+ let_it_be(:design_a) { create(:design, issue: issue) }
+ let_it_be(:version_a) { create(:design_version, issue: issue, created_designs: [design_a]) }
+
+ let(:current_user) { user }
+ let(:object) { issue.design_collection }
+ let(:global_id) { GitlabSchema.id_from_object(design_at_version).to_s }
+
+ let(:design_at_version) { ::DesignManagement::DesignAtVersion.new(design: design_a, version: version_a) }
+
+ let(:resource_not_available) { ::Gitlab::Graphql::Errors::ResourceNotAvailable }
+
+ before do
+ enable_design_management
+ project.add_developer(user)
+ end
+
+ describe '#resolve' do
+ context 'when the user cannot see designs' do
+ let(:current_user) { create(:user) }
+
+ it 'raises ResourceNotAvailable' do
+ expect { resolve_design }.to raise_error(resource_not_available)
+ end
+ end
+
+ it 'returns the specified design' do
+ expect(resolve_design).to eq(design_at_version)
+ end
+
+ context 'the ID belongs to a design on another issue' do
+ let(:other_dav) do
+ create(:design_at_version, issue: create(:issue, project: project))
+ end
+
+ let(:global_id) { global_id_of(other_dav) }
+
+ it 'raises ResourceNotAvailable' do
+ expect { resolve_design }.to raise_error(resource_not_available)
+ end
+
+ context 'the current object does not constrain the issue' do
+ let(:object) { nil }
+
+ it 'returns the object' do
+ expect(resolve_design).to eq(other_dav)
+ end
+ end
+ end
+ end
+
+ private
+
+ def resolve_design
+ args = { id: global_id }
+ ctx = { current_user: current_user }
+ eager_resolve(described_class, obj: object, args: args, ctx: ctx)
+ end
+end
diff --git a/spec/graphql/resolvers/design_management/design_resolver_spec.rb b/spec/graphql/resolvers/design_management/design_resolver_spec.rb
new file mode 100644
index 00000000000..857acc3d371
--- /dev/null
+++ b/spec/graphql/resolvers/design_management/design_resolver_spec.rb
@@ -0,0 +1,88 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Resolvers::DesignManagement::DesignResolver do
+ include GraphqlHelpers
+ include DesignManagementTestHelpers
+
+ before do
+ enable_design_management
+ end
+
+ describe '#resolve' do
+ let_it_be(:issue) { create(:issue) }
+ let_it_be(:project) { issue.project }
+ let_it_be(:first_version) { create(:design_version) }
+ let_it_be(:first_design) { create(:design, issue: issue, versions: [first_version]) }
+ let_it_be(:current_user) { create(:user) }
+ let_it_be(:design_on_other_issue) do
+ create(:design, issue: create(:issue, project: project), versions: [create(:design_version)])
+ end
+
+ let(:args) { { id: GitlabSchema.id_from_object(first_design).to_s } }
+ let(:gql_context) { { current_user: current_user } }
+
+ before do
+ project.add_developer(current_user)
+ end
+
+ context 'when the user cannot see designs' do
+ let(:gql_context) { { current_user: create(:user) } }
+
+ it 'returns nothing' do
+ expect(resolve_design).to be_nil
+ end
+ end
+
+ context 'when no argument has been passed' do
+ let(:args) { {} }
+
+ it 'raises an error' do
+ expect { resolve_design }.to raise_error(::Gitlab::Graphql::Errors::ArgumentError, /must/)
+ end
+ end
+
+ context 'when both arguments have been passed' do
+ let(:args) { { filename: first_design.filename, id: GitlabSchema.id_from_object(first_design).to_s } }
+
+ it 'raises an error' do
+ expect { resolve_design }.to raise_error(::Gitlab::Graphql::Errors::ArgumentError, /may/)
+ end
+ end
+
+ context 'by ID' do
+ it 'returns the specified design' do
+ expect(resolve_design).to eq(first_design)
+ end
+
+ context 'the ID belongs to a design on another issue' do
+ let(:args) { { id: GitlabSchema.id_from_object(design_on_other_issue).to_s } }
+
+ it 'returns nothing' do
+ expect(resolve_design).to be_nil
+ end
+ end
+ end
+
+ context 'by filename' do
+ let(:args) { { filename: first_design.filename } }
+
+ it 'returns the specified design' do
+ expect(resolve_design).to eq(first_design)
+ end
+
+ context 'the filename belongs to a design on another issue' do
+ let(:args) { { filename: design_on_other_issue.filename } }
+
+ it 'returns nothing' do
+ expect(resolve_design).to be_nil
+ end
+ end
+ end
+ end
+
+ def resolve_design
+ resolve(described_class, obj: issue.design_collection, args: args, ctx: gql_context)
+ end
+end
diff --git a/spec/graphql/resolvers/design_management/designs_resolver_spec.rb b/spec/graphql/resolvers/design_management/designs_resolver_spec.rb
new file mode 100644
index 00000000000..28fc9e2151d
--- /dev/null
+++ b/spec/graphql/resolvers/design_management/designs_resolver_spec.rb
@@ -0,0 +1,93 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Resolvers::DesignManagement::DesignsResolver do
+ include GraphqlHelpers
+ include DesignManagementTestHelpers
+
+ before do
+ enable_design_management
+ end
+
+ describe '#resolve' do
+ let_it_be(:issue) { create(:issue) }
+ let_it_be(:project) { issue.project }
+ let_it_be(:first_version) { create(:design_version) }
+ let_it_be(:first_design) { create(:design, issue: issue, versions: [first_version]) }
+ let_it_be(:current_user) { create(:user) }
+ let(:gql_context) { { current_user: current_user } }
+ let(:args) { {} }
+
+ before do
+ project.add_developer(current_user)
+ end
+
+ context 'when the user cannot see designs' do
+ let(:gql_context) { { current_user: create(:user) } }
+
+ it 'returns nothing' do
+ expect(resolve_designs).to be_empty
+ end
+ end
+
+ context 'for a design collection' do
+ context 'which contains just a single design' do
+ it 'returns just that design' do
+ expect(resolve_designs).to contain_exactly(first_design)
+ end
+ end
+
+ context 'which contains another design' do
+ it 'returns all designs' do
+ second_version = create(:design_version)
+ second_design = create(:design, issue: issue, versions: [second_version])
+
+ expect(resolve_designs).to contain_exactly(first_design, second_design)
+ end
+ end
+ end
+
+ describe 'filtering' do
+ describe 'by filename' do
+ let(:second_version) { create(:design_version) }
+ let(:second_design) { create(:design, issue: issue, versions: [second_version]) }
+ let(:args) { { filenames: [second_design.filename] } }
+
+ it 'resolves to just the relevant design, ignoring designs with the same filename on different issues' do
+ create(:design, issue: create(:issue, project: project), filename: second_design.filename)
+
+ expect(resolve_designs).to contain_exactly(second_design)
+ end
+ end
+
+ describe 'by id' do
+ let(:second_version) { create(:design_version) }
+ let(:second_design) { create(:design, issue: issue, versions: [second_version]) }
+
+ context 'the ID is on the current issue' do
+ let(:args) { { ids: [GitlabSchema.id_from_object(second_design).to_s] } }
+
+ it 'resolves to just the relevant design' do
+ expect(resolve_designs).to contain_exactly(second_design)
+ end
+ end
+
+ context 'the ID is on a different issue' do
+ let(:third_version) { create(:design_version) }
+ let(:third_design) { create(:design, issue: create(:issue, project: project), versions: [third_version]) }
+
+ let(:args) { { ids: [GitlabSchema.id_from_object(third_design).to_s] } }
+
+ it 'ignores it' do
+ expect(resolve_designs).to be_empty
+ end
+ end
+ end
+ end
+ end
+
+ def resolve_designs
+ resolve(described_class, obj: issue.design_collection, args: args, ctx: gql_context)
+ end
+end
diff --git a/spec/graphql/resolvers/design_management/version/design_at_version_resolver_spec.rb b/spec/graphql/resolvers/design_management/version/design_at_version_resolver_spec.rb
new file mode 100644
index 00000000000..cc9c0436885
--- /dev/null
+++ b/spec/graphql/resolvers/design_management/version/design_at_version_resolver_spec.rb
@@ -0,0 +1,93 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Resolvers::DesignManagement::Version::DesignAtVersionResolver do
+ include GraphqlHelpers
+
+ include_context 'four designs in three versions'
+
+ let(:current_user) { authorized_user }
+ let(:gql_context) { { current_user: current_user } }
+
+ let(:version) { third_version }
+ let(:design) { design_a }
+
+ let(:all_singular_args) do
+ {
+ design_at_version_id: global_id_of(dav(design)),
+ design_id: global_id_of(design),
+ filename: design.filename
+ }
+ end
+
+ shared_examples 'a bad argument' do
+ let(:err_class) { ::Gitlab::Graphql::Errors::ArgumentError }
+
+ it 'raises an appropriate error' do
+ expect { resolve_objects }.to raise_error(err_class)
+ end
+ end
+
+ describe '#resolve' do
+ describe 'passing combinations of arguments' do
+ context 'passing no arguments' do
+ let(:args) { {} }
+
+ it_behaves_like 'a bad argument'
+ end
+
+ context 'passing all arguments' do
+ let(:args) { all_singular_args }
+
+ it_behaves_like 'a bad argument'
+ end
+
+ context 'passing any two arguments' do
+ let(:args) { all_singular_args.slice(*all_singular_args.keys.sample(2)) }
+
+ it_behaves_like 'a bad argument'
+ end
+ end
+
+ %i[design_at_version_id design_id filename].each do |arg|
+ describe "passing #{arg}" do
+ let(:args) { all_singular_args.slice(arg) }
+
+ it 'finds the design' do
+ expect(resolve_objects).to eq(dav(design))
+ end
+
+ context 'when the user cannot see designs' do
+ let(:current_user) { create(:user) }
+
+ it 'returns nothing' do
+ expect(resolve_objects).to be_nil
+ end
+ end
+ end
+ end
+
+ describe 'attempting to retrieve an object not visible at this version' do
+ let(:design) { design_d }
+
+ %i[design_at_version_id design_id filename].each do |arg|
+ describe "passing #{arg}" do
+ let(:args) { all_singular_args.slice(arg) }
+
+ it 'does not find the design' do
+ expect(resolve_objects).to be_nil
+ end
+ end
+ end
+ end
+ end
+
+ def resolve_objects
+ resolve(described_class, obj: version, args: args, ctx: gql_context)
+ end
+
+ def dav(design)
+ build(:design_at_version, design: design, version: version)
+ end
+end
diff --git a/spec/graphql/resolvers/design_management/version/designs_at_version_resolver_spec.rb b/spec/graphql/resolvers/design_management/version/designs_at_version_resolver_spec.rb
new file mode 100644
index 00000000000..123b26862d0
--- /dev/null
+++ b/spec/graphql/resolvers/design_management/version/designs_at_version_resolver_spec.rb
@@ -0,0 +1,86 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Resolvers::DesignManagement::Version::DesignsAtVersionResolver do
+ include GraphqlHelpers
+
+ include_context 'four designs in three versions'
+
+ let_it_be(:current_user) { authorized_user }
+ let(:gql_context) { { current_user: current_user } }
+
+ let(:version) { third_version }
+
+ describe '.single' do
+ let(:single) { ::Resolvers::DesignManagement::Version::DesignAtVersionResolver }
+
+ it 'returns the single context resolver' do
+ expect(described_class.single).to eq(single)
+ end
+ end
+
+ describe '#resolve' do
+ let(:args) { {} }
+
+ context 'when the user cannot see designs' do
+ let(:current_user) { create(:user) }
+
+ it 'returns nothing' do
+ expect(resolve_objects).to be_empty
+ end
+ end
+
+ context 'for the current version' do
+ it 'returns all designs visible at that version' do
+ expect(resolve_objects).to contain_exactly(dav(design_a), dav(design_b), dav(design_c))
+ end
+ end
+
+ context 'for a previous version with more objects' do
+ let(:version) { second_version }
+
+ it 'returns objects that were later deleted' do
+ expect(resolve_objects).to contain_exactly(dav(design_a), dav(design_b), dav(design_c), dav(design_d))
+ end
+ end
+
+ context 'for a previous version with fewer objects' do
+ let(:version) { first_version }
+
+ it 'does not return objects that were later created' do
+ expect(resolve_objects).to contain_exactly(dav(design_a))
+ end
+ end
+
+ describe 'filtering' do
+ describe 'by filename' do
+ let(:red_herring) { create(:design, issue: create(:issue, project: project)) }
+ let(:args) { { filenames: [design_b.filename, red_herring.filename] } }
+
+ it 'resolves to just the relevant design' do
+ create(:design, issue: create(:issue, project: project), filename: design_b.filename)
+
+ expect(resolve_objects).to contain_exactly(dav(design_b))
+ end
+ end
+
+ describe 'by id' do
+ let(:red_herring) { create(:design, issue: create(:issue, project: project)) }
+ let(:args) { { ids: [design_a, red_herring].map { |x| global_id_of(x) } } }
+
+ it 'resolves to just the relevant design, ignoring objects on other issues' do
+ expect(resolve_objects).to contain_exactly(dav(design_a))
+ end
+ end
+ end
+ end
+
+ def resolve_objects
+ resolve(described_class, obj: version, args: args, ctx: gql_context)
+ end
+
+ def dav(design)
+ build(:design_at_version, design: design, version: version)
+ end
+end
diff --git a/spec/graphql/resolvers/design_management/version_in_collection_resolver_spec.rb b/spec/graphql/resolvers/design_management/version_in_collection_resolver_spec.rb
new file mode 100644
index 00000000000..ef50598d241
--- /dev/null
+++ b/spec/graphql/resolvers/design_management/version_in_collection_resolver_spec.rb
@@ -0,0 +1,64 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Resolvers::DesignManagement::VersionInCollectionResolver do
+ include GraphqlHelpers
+ include DesignManagementTestHelpers
+
+ let(:resolver) { described_class }
+
+ describe '#resolve' do
+ let_it_be(:issue) { create(:issue) }
+ let_it_be(:current_user) { create(:user) }
+ let_it_be(:first_version) { create(:design_version, issue: issue) }
+
+ let(:project) { issue.project }
+ let(:params) { {} }
+
+ before do
+ enable_design_management
+ project.add_developer(current_user)
+ end
+
+ let(:appropriate_error) { ::Gitlab::Graphql::Errors::ArgumentError }
+
+ subject(:result) { resolve_version(issue.design_collection) }
+
+ context 'Neither id nor sha is passed as parameters' do
+ it 'raises an appropriate error' do
+ expect { result }.to raise_error(appropriate_error)
+ end
+ end
+
+ context 'we pass an id' do
+ let(:params) { { id: global_id_of(first_version) } }
+
+ it { is_expected.to eq(first_version) }
+ end
+
+ context 'we pass a sha' do
+ let(:params) { { sha: first_version.sha } }
+
+ it { is_expected.to eq(first_version) }
+ end
+
+ context 'we pass an inconsistent mixture of sha and version id' do
+ let(:params) { { sha: first_version.sha, id: global_id_of(create(:design_version)) } }
+
+ it { is_expected.to be_nil }
+ end
+
+ context 'we pass the id of something that is not a design_version' do
+ let(:params) { { id: global_id_of(project) } }
+
+ it 'raises an appropriate error' do
+ expect { result }.to raise_error(appropriate_error)
+ end
+ end
+ end
+
+ def resolve_version(obj, context = { current_user: current_user })
+ resolve(resolver, obj: obj, args: params, ctx: context)
+ end
+end
diff --git a/spec/graphql/resolvers/design_management/version_resolver_spec.rb b/spec/graphql/resolvers/design_management/version_resolver_spec.rb
new file mode 100644
index 00000000000..e7c09351204
--- /dev/null
+++ b/spec/graphql/resolvers/design_management/version_resolver_spec.rb
@@ -0,0 +1,43 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Resolvers::DesignManagement::VersionResolver do
+ include GraphqlHelpers
+ include DesignManagementTestHelpers
+
+ let_it_be(:issue) { create(:issue) }
+ let_it_be(:current_user) { create(:user) }
+ let_it_be(:version) { create(:design_version, issue: issue) }
+ let_it_be(:developer) { create(:user) }
+
+ let(:project) { issue.project }
+ let(:params) { { id: global_id_of(version) } }
+
+ before do
+ enable_design_management
+ project.add_developer(developer)
+ end
+
+ context 'the current user is not authorized' do
+ let(:current_user) { create(:user) }
+
+ it 'raises an error on resolution' do
+ expect { resolve_version }.to raise_error(::Gitlab::Graphql::Errors::ResourceNotAvailable)
+ end
+ end
+
+ context 'the current user is authorized' do
+ let(:current_user) { developer }
+
+ context 'the id parameter is provided' do
+ it 'returns the specified version' do
+ expect(resolve_version).to eq(version)
+ end
+ end
+ end
+
+ def resolve_version
+ resolve(described_class, obj: nil, args: params, ctx: { current_user: current_user })
+ end
+end
diff --git a/spec/graphql/resolvers/design_management/versions_resolver_spec.rb b/spec/graphql/resolvers/design_management/versions_resolver_spec.rb
new file mode 100644
index 00000000000..d5bab025e45
--- /dev/null
+++ b/spec/graphql/resolvers/design_management/versions_resolver_spec.rb
@@ -0,0 +1,117 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Resolvers::DesignManagement::VersionsResolver do
+ include GraphqlHelpers
+ include DesignManagementTestHelpers
+
+ describe '#resolve' do
+ let(:resolver) { described_class }
+ let_it_be(:issue) { create(:issue) }
+ let_it_be(:authorized_user) { create(:user) }
+ let_it_be(:first_version) { create(:design_version, issue: issue) }
+ let_it_be(:other_version) { create(:design_version, issue: issue) }
+ let_it_be(:first_design) { create(:design, issue: issue, versions: [first_version, other_version]) }
+ let_it_be(:other_design) { create(:design, :with_versions, issue: issue) }
+
+ let(:project) { issue.project }
+ let(:params) { {} }
+ let(:current_user) { authorized_user }
+ let(:parent_args) { { irrelevant: 1.2 } }
+ let(:parent) { double('Parent', parent: nil, irep_node: double(arguments: parent_args)) }
+
+ before do
+ enable_design_management
+ project.add_developer(authorized_user)
+ end
+
+ shared_examples 'a source of versions' do
+ subject(:result) { resolve_versions(object) }
+
+ let_it_be(:all_versions) { object.versions.ordered }
+
+ context 'when the user is not authorized' do
+ let(:current_user) { create(:user) }
+
+ it { is_expected.to be_empty }
+ end
+
+ context 'without constraints' do
+ it 'returns the ordered versions' do
+ expect(result).to eq(all_versions)
+ end
+ end
+
+ context 'when constrained' do
+ let_it_be(:matching) { all_versions.earlier_or_equal_to(first_version) }
+
+ shared_examples 'a query for all_versions up to the first_version' do
+ it { is_expected.to eq(matching) }
+ end
+
+ context 'by earlier_or_equal_to_id' do
+ let(:params) { { id: global_id_of(first_version) } }
+
+ it_behaves_like 'a query for all_versions up to the first_version'
+ end
+
+ context 'by earlier_or_equal_to_sha' do
+ let(:params) { { sha: first_version.sha } }
+
+ it_behaves_like 'a query for all_versions up to the first_version'
+ end
+
+ context 'by earlier_or_equal_to_sha AND earlier_or_equal_to_id' do
+ context 'and they match' do
+ # This usage is rather dumb, but so long as they match, this will
+ # return successfully
+ let(:params) do
+ {
+ sha: first_version.sha,
+ id: global_id_of(first_version)
+ }
+ end
+
+ it_behaves_like 'a query for all_versions up to the first_version'
+ end
+
+ context 'and they do not match' do
+ let(:params) do
+ {
+ sha: first_version.sha,
+ id: global_id_of(other_version)
+ }
+ end
+
+ it 'raises a suitable error' do
+ expect { result }.to raise_error(GraphQL::ExecutionError)
+ end
+ end
+ end
+
+ context 'by at_version in parent' do
+ let(:parent_args) { { atVersion: global_id_of(first_version) } }
+
+ it_behaves_like 'a query for all_versions up to the first_version'
+ end
+ end
+ end
+
+ describe 'a design collection' do
+ let_it_be(:object) { DesignManagement::DesignCollection.new(issue) }
+
+ it_behaves_like 'a source of versions'
+ end
+
+ describe 'a design' do
+ let_it_be(:object) { first_design }
+
+ it_behaves_like 'a source of versions'
+ end
+
+ def resolve_versions(obj, context = { current_user: current_user })
+ eager_resolve(resolver, obj: obj, args: params.merge(parent: parent), ctx: context)
+ end
+ end
+end