diff options
Diffstat (limited to 'spec/graphql/resolvers')
7 files changed, 263 insertions, 18 deletions
diff --git a/spec/graphql/resolvers/admin/analytics/instance_statistics/measurements_resolver_spec.rb b/spec/graphql/resolvers/admin/analytics/instance_statistics/measurements_resolver_spec.rb index 76854be2daa..c5637d43382 100644 --- a/spec/graphql/resolvers/admin/analytics/instance_statistics/measurements_resolver_spec.rb +++ b/spec/graphql/resolvers/admin/analytics/instance_statistics/measurements_resolver_spec.rb @@ -5,9 +5,11 @@ require 'spec_helper' RSpec.describe Resolvers::Admin::Analytics::InstanceStatistics::MeasurementsResolver do include GraphqlHelpers + let_it_be(:admin_user) { create(:user, :admin) } + let(:current_user) { admin_user } + describe '#resolve' do let_it_be(:user) { create(:user) } - let_it_be(:admin_user) { create(:user, :admin) } let_it_be(:project_measurement_new) { create(:instance_statistics_measurement, :project_count, recorded_at: 2.days.ago) } let_it_be(:project_measurement_old) { create(:instance_statistics_measurement, :project_count, recorded_at: 10.days.ago) } @@ -39,6 +41,37 @@ RSpec.describe Resolvers::Admin::Analytics::InstanceStatistics::MeasurementsReso end end end + + context 'when requesting pipeline counts by pipeline status' do + let_it_be(:pipelines_succeeded_measurement) { create(:instance_statistics_measurement, :pipelines_succeeded_count, recorded_at: 2.days.ago) } + let_it_be(:pipelines_skipped_measurement) { create(:instance_statistics_measurement, :pipelines_skipped_count, recorded_at: 2.days.ago) } + + subject { resolve_measurements({ identifier: identifier }, { current_user: current_user }) } + + context 'filter for pipelines_succeeded' do + let(:identifier) { 'pipelines_succeeded' } + + it { is_expected.to eq([pipelines_succeeded_measurement]) } + end + + context 'filter for pipelines_skipped' do + let(:identifier) { 'pipelines_skipped' } + + it { is_expected.to eq([pipelines_skipped_measurement]) } + end + + context 'filter for pipelines_failed' do + let(:identifier) { 'pipelines_failed' } + + it { is_expected.to be_empty } + end + + context 'filter for pipelines_canceled' do + let(:identifier) { 'pipelines_canceled' } + + it { is_expected.to be_empty } + end + end end def resolve_measurements(args = {}, context = {}) diff --git a/spec/graphql/resolvers/board_resolver_spec.rb b/spec/graphql/resolvers/board_resolver_spec.rb new file mode 100644 index 00000000000..c70c696005f --- /dev/null +++ b/spec/graphql/resolvers/board_resolver_spec.rb @@ -0,0 +1,72 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Resolvers::BoardResolver do + include GraphqlHelpers + + let_it_be(:user) { create(:user) } + + let(:dummy_gid) { 'gid://gitlab/Board/1' } + + shared_examples_for 'group and project boards resolver' do + it 'does not create a default board' do + expect(resolve_board(id: dummy_gid)).to eq nil + end + + it 'calls Boards::ListService' do + expect_next_instance_of(Boards::ListService) do |service| + expect(service).to receive(:execute).and_return([]) + end + + resolve_board(id: dummy_gid) + end + + it 'requires an ID' do + expect do + resolve(described_class, obj: board_parent, args: {}, ctx: { current_user: user }) + end.to raise_error(Gitlab::Graphql::Errors::ArgumentError) + end + + context 'when querying for a single board' do + let(:board1) { create(:board, name: 'One', resource_parent: board_parent) } + + it 'returns specified board' do + expect(resolve_board(id: global_id_of(board1))).to eq board1 + end + + it 'returns nil if board not found' do + outside_parent = create(board_parent.class.underscore.to_sym) # rubocop:disable Rails/SaveBang + outside_board = create(:board, name: 'outside board', resource_parent: outside_parent) + + expect(resolve_board(id: global_id_of(outside_board))).to eq nil + end + end + end + + describe '#resolve' do + context 'when there is no parent' do + let(:board_parent) { nil } + + it 'returns nil if parent is nil' do + expect(resolve_board(id: dummy_gid)).to eq(nil) + end + end + + context 'when project boards' do + let(:board_parent) { create(:project, :public, creator_id: user.id, namespace: user.namespace ) } + + it_behaves_like 'group and project boards resolver' + end + + context 'when group boards' do + let(:board_parent) { create(:group) } + + it_behaves_like 'group and project boards resolver' + end + end + + def resolve_board(id:) + resolve(described_class, obj: board_parent, args: { id: id }, ctx: { current_user: user }) + end +end diff --git a/spec/graphql/resolvers/concerns/looks_ahead_spec.rb b/spec/graphql/resolvers/concerns/looks_ahead_spec.rb index f13823085b8..ebea9e5522b 100644 --- a/spec/graphql/resolvers/concerns/looks_ahead_spec.rb +++ b/spec/graphql/resolvers/concerns/looks_ahead_spec.rb @@ -117,20 +117,6 @@ RSpec.describe LooksAhead do query.result end - context 'the feature flag is off' do - before do - stub_feature_flags(described_class::FEATURE_FLAG => false) - end - - it_behaves_like 'a working query on the test schema' - - it 'does not preload labels on issues' do - expect(the_user.issues).not_to receive(:preload).with(:labels) - - query.result - end - end - it 'issues fewer queries than the naive approach' do the_user.reload # ensure no attributes are loaded before we begin naive = <<-GQL diff --git a/spec/graphql/resolvers/issues_resolver_spec.rb b/spec/graphql/resolvers/issues_resolver_spec.rb index db5d009f0e7..3a6507f906c 100644 --- a/spec/graphql/resolvers/issues_resolver_spec.rb +++ b/spec/graphql/resolvers/issues_resolver_spec.rb @@ -46,6 +46,13 @@ RSpec.describe Resolvers::IssuesResolver do expect(resolve_issues(assignee_username: assignee.username)).to contain_exactly(issue2) end + it 'filters by two assignees' do + assignee2 = create(:user) + issue2.update!(assignees: [assignee, assignee2]) + + expect(resolve_issues(assignee_id: [assignee.id, assignee2.id])).to contain_exactly(issue2) + end + it 'filters by assignee_id' do expect(resolve_issues(assignee_id: assignee.id)).to contain_exactly(issue2) end @@ -58,6 +65,10 @@ RSpec.describe Resolvers::IssuesResolver do expect(resolve_issues(assignee_id: IssuableFinder::Params::FILTER_NONE)).to contain_exactly(issue1) end + it 'filters by author' do + expect(resolve_issues(author_username: issue1.author.username)).to contain_exactly(issue1, issue2) + end + it 'filters by labels' do expect(resolve_issues(label_name: [label1.title])).to contain_exactly(issue1, issue2) expect(resolve_issues(label_name: [label1.title, label2.title])).to contain_exactly(issue2) @@ -219,6 +230,21 @@ RSpec.describe Resolvers::IssuesResolver do expect(resolve_issues(sort: :milestone_due_desc).items).to eq([milestone_issue3, milestone_issue2, milestone_issue1]) end end + + context 'when sorting by severity' do + let_it_be(:project) { create(:project) } + let_it_be(:issue_high_severity) { create_issue_with_severity(project, severity: :high) } + let_it_be(:issue_low_severity) { create_issue_with_severity(project, severity: :low) } + let_it_be(:issue_no_severity) { create(:incident, project: project) } + + it 'sorts issues ascending' do + expect(resolve_issues(sort: :severity_asc)).to eq([issue_no_severity, issue_low_severity, issue_high_severity]) + end + + it 'sorts issues descending' do + expect(resolve_issues(sort: :severity_desc)).to eq([issue_high_severity, issue_low_severity, issue_no_severity]) + end + end end it 'returns issues user can see' do @@ -304,6 +330,13 @@ RSpec.describe Resolvers::IssuesResolver do expect(field.to_graphql.complexity.call({}, { labelName: 'foo' }, 1)).to eq 8 end + def create_issue_with_severity(project, severity:) + issue = create(:incident, project: project) + create(:issuable_severity, issue: issue, severity: severity) + + issue + end + def resolve_issues(args = {}, context = { current_user: current_user }) resolve(described_class, obj: project, args: args, ctx: context) end diff --git a/spec/graphql/resolvers/projects_resolver_spec.rb b/spec/graphql/resolvers/projects_resolver_spec.rb index d22ffeed740..07069bb1b06 100644 --- a/spec/graphql/resolvers/projects_resolver_spec.rb +++ b/spec/graphql/resolvers/projects_resolver_spec.rb @@ -8,10 +8,15 @@ RSpec.describe Resolvers::ProjectsResolver do describe '#resolve' do subject { resolve(described_class, obj: nil, args: filters, ctx: { current_user: current_user }) } + let_it_be(:group) { create(:group, name: 'public-group') } + let_it_be(:private_group) { create(:group, name: 'private-group') } let_it_be(:project) { create(:project, :public) } let_it_be(:other_project) { create(:project, :public) } + let_it_be(:group_project) { create(:project, :public, group: group) } let_it_be(:private_project) { create(:project, :private) } let_it_be(:other_private_project) { create(:project, :private) } + let_it_be(:other_private_project) { create(:project, :private) } + let_it_be(:private_group_project) { create(:project, :private, group: private_group) } let_it_be(:user) { create(:user) } @@ -20,6 +25,7 @@ RSpec.describe Resolvers::ProjectsResolver do before_all do project.add_developer(user) private_project.add_developer(user) + private_group.add_developer(user) end context 'when user is not logged in' do @@ -27,7 +33,7 @@ RSpec.describe Resolvers::ProjectsResolver do context 'when no filters are applied' do it 'returns all public projects' do - is_expected.to contain_exactly(project, other_project) + is_expected.to contain_exactly(project, other_project, group_project) end context 'when search filter is provided' do @@ -45,6 +51,22 @@ RSpec.describe Resolvers::ProjectsResolver do is_expected.to be_empty end end + + context 'when searchNamespaces filter is provided' do + let(:filters) { { search: 'group', search_namespaces: true } } + + it 'returns projects in a matching namespace' do + is_expected.to contain_exactly(group_project) + end + end + + context 'when searchNamespaces filter false' do + let(:filters) { { search: 'group', search_namespaces: false } } + + it 'returns ignores namespace matches' do + is_expected.to be_empty + end + end end end @@ -53,7 +75,7 @@ RSpec.describe Resolvers::ProjectsResolver do context 'when no filters are applied' do it 'returns all visible projects for the user' do - is_expected.to contain_exactly(project, other_project, private_project) + is_expected.to contain_exactly(project, other_project, group_project, private_project, private_group_project) end context 'when search filter is provided' do @@ -68,7 +90,23 @@ RSpec.describe Resolvers::ProjectsResolver do let(:filters) { { membership: true } } it 'returns projects that user is member of' do - is_expected.to contain_exactly(project, private_project) + is_expected.to contain_exactly(project, private_project, private_group_project) + end + end + + context 'when searchNamespaces filter is provided' do + let(:filters) { { search: 'group', search_namespaces: true } } + + it 'returns projects from matching group' do + is_expected.to contain_exactly(group_project, private_group_project) + end + end + + context 'when searchNamespaces filter false' do + let(:filters) { { search: 'group', search_namespaces: false } } + + it 'returns ignores namespace matches' do + is_expected.to be_empty end end diff --git a/spec/graphql/resolvers/snippets/blobs_resolver_spec.rb b/spec/graphql/resolvers/snippets/blobs_resolver_spec.rb new file mode 100644 index 00000000000..fdbd87c32be --- /dev/null +++ b/spec/graphql/resolvers/snippets/blobs_resolver_spec.rb @@ -0,0 +1,50 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Resolvers::Snippets::BlobsResolver do + include GraphqlHelpers + + describe '#resolve' do + let_it_be(:current_user) { create(:user) } + let_it_be(:snippet) { create(:personal_snippet, :private, :repository, author: current_user) } + + context 'when user is not authorized' do + let(:other_user) { create(:user) } + + it 'raises an error' do + expect do + resolve_blobs(snippet, user: other_user) + end.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable) + end + end + + context 'when using no filter' do + it 'returns all snippet blobs' do + expect(resolve_blobs(snippet).map(&:path)).to contain_exactly(*snippet.list_files) + end + end + + context 'when using filters' do + context 'when paths is a single string' do + it 'returns an array of files' do + path = 'CHANGELOG' + + expect(resolve_blobs(snippet, args: { paths: path }).first.path).to eq(path) + end + end + + context 'when paths is an array of string' do + it 'returns an array of files' do + paths = ['CHANGELOG', 'README.md'] + + expect(resolve_blobs(snippet, args: { paths: paths }).map(&:path)).to contain_exactly(*paths) + end + end + end + end + + def resolve_blobs(snippet, user: current_user, args: {}) + resolve(described_class, args: args, ctx: { current_user: user }, obj: snippet) + end +end diff --git a/spec/graphql/resolvers/terraform/states_resolver_spec.rb b/spec/graphql/resolvers/terraform/states_resolver_spec.rb new file mode 100644 index 00000000000..64b515528cd --- /dev/null +++ b/spec/graphql/resolvers/terraform/states_resolver_spec.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Resolvers::Terraform::StatesResolver do + include GraphqlHelpers + + it { expect(described_class.type).to eq(Types::Terraform::StateType) } + it { expect(described_class.null).to be_truthy } + + describe '#resolve' do + let_it_be(:project) { create(:project) } + + let_it_be(:production_state) { create(:terraform_state, project: project) } + let_it_be(:staging_state) { create(:terraform_state, project: project) } + let_it_be(:other_state) { create(:terraform_state) } + + let(:ctx) { Hash(current_user: user) } + let(:user) { create(:user, developer_projects: [project]) } + + subject { resolve(described_class, obj: project, ctx: ctx) } + + it 'returns states associated with the agent' do + expect(subject).to contain_exactly(production_state, staging_state) + end + + context 'user does not have permission' do + let(:user) { create(:user) } + + it { is_expected.to be_empty } + end + end +end |