diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-12-20 17:22:11 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-12-20 17:22:11 +0300 |
commit | 0c872e02b2c822e3397515ec324051ff540f0cd5 (patch) | |
tree | ce2fb6ce7030e4dad0f4118d21ab6453e5938cdd /spec/graphql | |
parent | f7e05a6853b12f02911494c4b3fe53d9540d74fc (diff) |
Add latest changes from gitlab-org/gitlab@15-7-stable-eev15.7.0-rc42
Diffstat (limited to 'spec/graphql')
59 files changed, 876 insertions, 113 deletions
diff --git a/spec/graphql/graphql_triggers_spec.rb b/spec/graphql/graphql_triggers_spec.rb index a54cb8a7988..00b5aec366e 100644 --- a/spec/graphql/graphql_triggers_spec.rb +++ b/spec/graphql/graphql_triggers_spec.rb @@ -116,4 +116,18 @@ RSpec.describe GraphqlTriggers do GraphqlTriggers.merge_request_merge_status_updated(merge_request) end end + + describe '.merge_request_approval_state_updated' do + it 'triggers the mergeRequestApprovalStateUpdated subscription' do + merge_request = build_stubbed(:merge_request) + + expect(GitlabSchema.subscriptions).to receive(:trigger).with( + 'mergeRequestApprovalStateUpdated', + { issuable_id: merge_request.to_gid }, + merge_request + ).and_call_original + + GraphqlTriggers.merge_request_approval_state_updated(merge_request) + end + end end diff --git a/spec/graphql/mutations/alert_management/alerts/set_assignees_spec.rb b/spec/graphql/mutations/alert_management/alerts/set_assignees_spec.rb index 31abbabe385..125e15b70cf 100644 --- a/spec/graphql/mutations/alert_management/alerts/set_assignees_spec.rb +++ b/spec/graphql/mutations/alert_management/alerts/set_assignees_spec.rb @@ -56,6 +56,15 @@ RSpec.describe Mutations::AlertManagement::Alerts::SetAssignees do context 'when operation mode is not specified' do it_behaves_like 'successful resolution' it_behaves_like 'an incident management tracked event', :incident_management_alert_assigned + + it_behaves_like 'Snowplow event tracking with RedisHLL context' do + let(:feature_flag_name) { :route_hll_to_snowplow_phase2 } + let(:namespace) { project.namespace.reload } + let(:category) { described_class.to_s } + let(:user) { current_user } + let(:action) { 'incident_management_alert_assigned' } + let(:label) { 'redis_hll_counters.incident_management.incident_management_total_unique_counts_monthly' } + end end context 'when user does not have permission to update alerts' do diff --git a/spec/graphql/mutations/alert_management/alerts/todo/create_spec.rb b/spec/graphql/mutations/alert_management/alerts/todo/create_spec.rb index ea5e21ec4b8..bcb7c74fa09 100644 --- a/spec/graphql/mutations/alert_management/alerts/todo/create_spec.rb +++ b/spec/graphql/mutations/alert_management/alerts/todo/create_spec.rb @@ -19,6 +19,15 @@ RSpec.describe Mutations::AlertManagement::Alerts::Todo::Create do it_behaves_like 'an incident management tracked event', :incident_management_alert_todo + it_behaves_like 'Snowplow event tracking with RedisHLL context' do + let(:feature_flag_name) { :route_hll_to_snowplow_phase2 } + let(:namespace) { project.namespace.reload } + let(:category) { described_class.to_s } + let(:user) { current_user } + let(:action) { 'incident_management_alert_todo' } + let(:label) { 'redis_hll_counters.incident_management.incident_management_total_unique_counts_monthly' } + end + context 'when user does not have permissions' do let(:current_user) { nil } diff --git a/spec/graphql/mutations/alert_management/create_alert_issue_spec.rb b/spec/graphql/mutations/alert_management/create_alert_issue_spec.rb index 4758ac526a5..e49596b37c9 100644 --- a/spec/graphql/mutations/alert_management/create_alert_issue_spec.rb +++ b/spec/graphql/mutations/alert_management/create_alert_issue_spec.rb @@ -30,6 +30,15 @@ RSpec.describe Mutations::AlertManagement::CreateAlertIssue do it_behaves_like 'an incident management tracked event', :incident_management_incident_created it_behaves_like 'an incident management tracked event', :incident_management_alert_create_incident + + it_behaves_like 'Snowplow event tracking with RedisHLL context' do + let(:feature_flag_name) { :route_hll_to_snowplow_phase2 } + let(:namespace) { project.namespace.reload } + let(:category) { described_class.to_s } + let(:user) { current_user } + let(:action) { 'incident_management_incident_created' } + let(:label) { 'redis_hll_counters.incident_management.incident_management_total_unique_counts_monthly' } + end end context 'when CreateAlertIssue responds with an error' do @@ -46,6 +55,15 @@ RSpec.describe Mutations::AlertManagement::CreateAlertIssue do errors: ['An issue already exists'] ) end + + it_behaves_like 'Snowplow event tracking with RedisHLL context' do + let(:feature_flag_name) { :route_hll_to_snowplow_phase2 } + let(:namespace) { project.namespace.reload } + let(:category) { described_class.to_s } + let(:user) { current_user } + let(:action) { 'incident_management_incident_created' } + let(:label) { 'redis_hll_counters.incident_management.incident_management_total_unique_counts_monthly' } + end end end diff --git a/spec/graphql/mutations/alert_management/update_alert_status_spec.rb b/spec/graphql/mutations/alert_management/update_alert_status_spec.rb index 2c2518e046a..22ad93df79b 100644 --- a/spec/graphql/mutations/alert_management/update_alert_status_spec.rb +++ b/spec/graphql/mutations/alert_management/update_alert_status_spec.rb @@ -35,6 +35,15 @@ RSpec.describe Mutations::AlertManagement::UpdateAlertStatus do let(:user) { current_user } end + it_behaves_like 'Snowplow event tracking with RedisHLL context' do + let(:feature_flag_name) { :route_hll_to_snowplow_phase2 } + let(:namespace) { project.namespace } + let(:category) { described_class.to_s } + let(:user) { current_user } + let(:action) { 'incident_management_alert_status_changed' } + let(:label) { 'redis_hll_counters.incident_management.incident_management_total_unique_counts_monthly' } + end + context 'error occurs when updating' do it 'returns the alert with errors' do # Stub an error on the alert diff --git a/spec/graphql/mutations/ci/runner/bulk_delete_spec.rb b/spec/graphql/mutations/ci/runner/bulk_delete_spec.rb index 2eccfd3409f..aaa74fa78aa 100644 --- a/spec/graphql/mutations/ci/runner/bulk_delete_spec.rb +++ b/spec/graphql/mutations/ci/runner/bulk_delete_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Mutations::Ci::Runner::BulkDelete do +RSpec.describe Mutations::Ci::Runner::BulkDelete, feature_category: :runner_fleet do include GraphqlHelpers let_it_be(:admin_user) { create(:user, :admin) } diff --git a/spec/graphql/mutations/ci/runner/delete_spec.rb b/spec/graphql/mutations/ci/runner/delete_spec.rb index 06d360430f8..f19fa7c34a9 100644 --- a/spec/graphql/mutations/ci/runner/delete_spec.rb +++ b/spec/graphql/mutations/ci/runner/delete_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Mutations::Ci::Runner::Delete do +RSpec.describe Mutations::Ci::Runner::Delete, feature_category: :runner_fleet do include GraphqlHelpers let_it_be(:runner) { create(:ci_runner) } diff --git a/spec/graphql/mutations/ci/runner/update_spec.rb b/spec/graphql/mutations/ci/runner/update_spec.rb index 098b7ac6aa4..e0c8219e0f6 100644 --- a/spec/graphql/mutations/ci/runner/update_spec.rb +++ b/spec/graphql/mutations/ci/runner/update_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Mutations::Ci::Runner::Update do +RSpec.describe Mutations::Ci::Runner::Update, feature_category: :runner_fleet do include GraphqlHelpers let_it_be(:user) { create(:user) } diff --git a/spec/graphql/mutations/container_repositories/destroy_spec.rb b/spec/graphql/mutations/container_repositories/destroy_spec.rb index 9f3ff8da80b..50e83ccdd30 100644 --- a/spec/graphql/mutations/container_repositories/destroy_spec.rb +++ b/spec/graphql/mutations/container_repositories/destroy_spec.rb @@ -55,23 +55,6 @@ RSpec.describe Mutations::ContainerRepositories::Destroy do it_behaves_like params[:shared_examples_name] end - - context 'with container_registry_delete_repository_with_cron_worker disabled' do - before do - project.add_maintainer(user) - stub_feature_flags(container_registry_delete_repository_with_cron_worker: false) - end - - it 'enqueues a removal job' do - expect(::Packages::CreateEventService) - .to receive(:new).with(nil, user, event_name: :delete_repository, scope: :container).and_call_original - expect(DeleteContainerRepositoryWorker) - .to receive(:perform_async).with(user.id, container_repository.id) - - expect { subject }.to change { ::Packages::Event.count }.by(1) - expect(container_repository.reload.delete_scheduled?).to be true - end - end end end end diff --git a/spec/graphql/mutations/incident_management/timeline_event/update_spec.rb b/spec/graphql/mutations/incident_management/timeline_event/update_spec.rb index 7081fb7117e..317e8f5fcb6 100644 --- a/spec/graphql/mutations/incident_management/timeline_event/update_spec.rb +++ b/spec/graphql/mutations/incident_management/timeline_event/update_spec.rb @@ -7,21 +7,33 @@ RSpec.describe Mutations::IncidentManagement::TimelineEvent::Update do let_it_be(:reporter) { create(:user) } let_it_be(:project) { create(:project) } let_it_be(:incident) { create(:incident, project: project) } + let_it_be(:tag1) { create(:incident_management_timeline_event_tag, project: project, name: 'Tag 1') } + let_it_be(:tag2) { create(:incident_management_timeline_event_tag, project: project, name: 'Tag 2') } let_it_be_with_reload(:timeline_event) do create(:incident_management_timeline_event, project: project, incident: incident) end + # Pre-attach a tag to the event + let_it_be(:tag_link1) do + create(:incident_management_timeline_event_tag_link, + timeline_event: timeline_event, + timeline_event_tag: tag1 + ) + end + let(:args) do { id: timeline_event_id, note: note, - occurred_at: occurred_at + occurred_at: occurred_at, + timeline_event_tag_names: tag_names } end let(:note) { 'Updated Note' } let(:timeline_event_id) { GitlabSchema.id_from_object(timeline_event).to_s } let(:occurred_at) { 1.minute.ago } + let(:tag_names) { [] } before do project.add_developer(developer) @@ -92,6 +104,36 @@ RSpec.describe Mutations::IncidentManagement::TimelineEvent::Update do expect(resolve).to eq(timeline_event: nil, errors: ["Occurred at can't be blank"]) end end + + context 'when timeline event tag do not exist' do + let(:tag_names) { ['some other tag'] } + + it 'does not update the timeline event' do + expect { resolve }.not_to change { timeline_event.reload.updated_at } + end + + it 'responds with error' do + expect(resolve).to eq(timeline_event: nil, errors: ["Following tags don't exist: [\"some other tag\"]"]) + end + end + end + + context 'when timeline event tags are passed' do + let(:tag_names) { [tag2.name] } + + it 'returns updated timeline event' do + expect(resolve).to eq( + timeline_event: timeline_event.reload, + errors: [] + ) + end + + it 'removes tag1 and assigns tag2 to the event' do + response = resolve + timeline_event = response[:timeline_event] + + expect(timeline_event.timeline_event_tags).to contain_exactly(tag2) + end end end diff --git a/spec/graphql/mutations/issues/link_alerts_spec.rb b/spec/graphql/mutations/issues/link_alerts_spec.rb new file mode 100644 index 00000000000..a6ce5cdd7ab --- /dev/null +++ b/spec/graphql/mutations/issues/link_alerts_spec.rb @@ -0,0 +1,84 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Mutations::Issues::LinkAlerts, feature_category: :incident_management do + let_it_be(:project) { create(:project) } + let_it_be(:guest) { create(:user) } + let_it_be(:developer) { create(:user) } + let_it_be(:issue) { create(:incident, project: project) } + let_it_be(:alert1) { create(:alert_management_alert, project: project) } + let_it_be(:alert2) { create(:alert_management_alert, project: project) } + + let(:mutation) { described_class.new(object: nil, context: { current_user: user }, field: nil) } + + specify { expect(described_class).to require_graphql_authorizations(:update_issue, :admin_issue) } + + before_all do + project.add_guest(guest) + project.add_developer(developer) + end + + describe '#resolve' do + let(:alert_references) { [alert1.to_reference, alert2.details_url, 'invalid-reference'] } + + subject(:resolve) do + mutation.resolve( + project_path: issue.project.full_path, + iid: issue.iid, + alert_references: alert_references + ) + end + + context 'when the user is a guest' do + let(:user) { guest } + + it 'raises an error' do + expect { resolve }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable) + end + + context 'when a user is also an author' do + let!(:issue) { create(:incident, project: project, author: user) } + + it 'raises an error' do + expect { resolve }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable) + end + end + + context 'when a user is also an assignee' do + let!(:issue) { create(:incident, project: project, assignee_ids: [user.id]) } + + it 'raises an error' do + expect { resolve }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable) + end + end + end + + context 'when the user is a developer' do + let(:user) { developer } + + context 'when issue type is an incident' do + it 'calls LinkAlerts::CreateService with correct arguments' do + expect(::IncidentManagement::LinkAlerts::CreateService) + .to receive(:new) + .with(issue, user, alert_references) + .and_call_original + + resolve + end + + it 'returns no errors' do + expect(resolve[:errors]).to be_empty + end + end + + context 'when issue type is not an incident' do + let!(:issue) { create(:issue, project: project) } + + it 'does not update alert_management_alerts' do + expect { resolve }.not_to change { issue.alert_management_alerts } + end + end + end + end +end diff --git a/spec/graphql/mutations/issues/unlink_alert_spec.rb b/spec/graphql/mutations/issues/unlink_alert_spec.rb new file mode 100644 index 00000000000..2f1d5084faf --- /dev/null +++ b/spec/graphql/mutations/issues/unlink_alert_spec.rb @@ -0,0 +1,83 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Mutations::Issues::UnlinkAlert, feature_category: :incident_management do + let_it_be(:project) { create(:project) } + let_it_be(:another_project) { create(:project) } + let_it_be(:guest) { create(:user) } + let_it_be(:developer) { create(:user) } + let_it_be(:internal_alert) { create(:alert_management_alert, project: project) } + let_it_be(:external_alert) { create(:alert_management_alert, project: another_project) } + let_it_be(:issue) { create(:incident, project: project, alert_management_alerts: [internal_alert, external_alert]) } + + let(:mutation) { described_class.new(object: nil, context: { current_user: user }, field: nil) } + + specify { expect(described_class).to require_graphql_authorizations(:update_issue, :admin_issue) } + + before_all do + project.add_guest(guest) + project.add_developer(developer) + end + + describe '#resolve' do + let(:alert_to_unlink) { internal_alert } + + subject(:resolve) do + mutation.resolve( + project_path: issue.project.full_path, + iid: issue.iid, + alert_id: alert_to_unlink.to_global_id.to_s + ) + end + + context 'when the user is a guest' do + let(:user) { guest } + + it 'raises an error' do + expect { resolve }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable) + end + end + + context 'when the user is a developer' do + let(:user) { developer } + + shared_examples 'unlinking an alert' do + it 'unlinks the alert' do + expect { resolve }.to change { issue.reload.alert_management_alerts }.to match_array(remainded_alerts) + end + + it 'returns no errors' do + expect(resolve[:errors]).to be_empty + end + end + + context 'when unlinking internal alert' do + let(:alert_to_unlink) { internal_alert } + let(:remainded_alerts) { [external_alert] } + + it_behaves_like 'unlinking an alert' + end + + context 'when unlinking external alert' do + let(:alert_to_unlink) { external_alert } + let(:remainded_alerts) { [internal_alert] } + + it_behaves_like 'unlinking an alert' + end + + context 'when LinkAlerts::DestroyService responds with an error' do + it 'returns the error' do + service_instance = instance_double( + ::IncidentManagement::LinkAlerts::DestroyService, + execute: ServiceResponse.error(message: 'some error message') + ) + + allow(::IncidentManagement::LinkAlerts::DestroyService).to receive(:new).and_return(service_instance) + + expect(resolve[:errors]).to match_array(['some error message']) + end + end + end + end +end diff --git a/spec/graphql/resolvers/ci/all_jobs_resolver_spec.rb b/spec/graphql/resolvers/ci/all_jobs_resolver_spec.rb index 2a7d0a8171b..5c632ed3443 100644 --- a/spec/graphql/resolvers/ci/all_jobs_resolver_spec.rb +++ b/spec/graphql/resolvers/ci/all_jobs_resolver_spec.rb @@ -11,29 +11,46 @@ RSpec.describe Resolvers::Ci::AllJobsResolver do let_it_be(:pending_job) { create(:ci_build, :pending, name: 'Job Three') } let(:args) { {} } - let(:current_user) { create(:admin) } subject { resolve_jobs(args) } describe '#resolve' do - context 'with authorized user' do - context 'with statuses argument' do - let(:args) { { statuses: [Types::Ci::JobStatusEnum.coerce_isolated_input('SUCCESS')] } } + context 'with admin' do + let(:current_user) { create(:admin) } - it { is_expected.to contain_exactly(successful_job, successful_job_two) } - end + shared_examples 'executes as admin' do + context 'with statuses argument' do + let(:args) { { statuses: [Types::Ci::JobStatusEnum.coerce_isolated_input('SUCCESS')] } } + + it { is_expected.to contain_exactly(successful_job, successful_job_two) } + end + + context 'with multiple statuses' do + let(:args) do + { statuses: [Types::Ci::JobStatusEnum.coerce_isolated_input('SUCCESS'), + Types::Ci::JobStatusEnum.coerce_isolated_input('FAILED')] } + end + + it { is_expected.to contain_exactly(successful_job, successful_job_two, failed_job) } + end - context 'with multiple statuses' do - let(:args) do - { statuses: [Types::Ci::JobStatusEnum.coerce_isolated_input('SUCCESS'), - Types::Ci::JobStatusEnum.coerce_isolated_input('FAILED')] } + context 'without statuses argument' do + it { is_expected.to contain_exactly(successful_job, successful_job_two, failed_job, pending_job) } end + end - it { is_expected.to contain_exactly(successful_job, successful_job_two, failed_job) } + context 'when admin mode setting is disabled', :do_not_mock_admin_mode_setting do + it_behaves_like 'executes as admin' end - context 'without statuses argument' do - it { is_expected.to contain_exactly(successful_job, successful_job_two, failed_job, pending_job) } + context 'when admin mode setting is enabled' do + context 'when in admin mode', :enable_admin_mode do + it_behaves_like 'executes as admin' + end + + context 'when not in admin mode' do + it { is_expected.to be_empty } + end end end diff --git a/spec/graphql/resolvers/ci/group_runners_resolver_spec.rb b/spec/graphql/resolvers/ci/group_runners_resolver_spec.rb index 57b2fcbea63..5d06db904d5 100644 --- a/spec/graphql/resolvers/ci/group_runners_resolver_spec.rb +++ b/spec/graphql/resolvers/ci/group_runners_resolver_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Resolvers::Ci::GroupRunnersResolver do +RSpec.describe Resolvers::Ci::GroupRunnersResolver, feature_category: :runner_fleet do include GraphqlHelpers describe '#resolve' do @@ -78,7 +78,7 @@ RSpec.describe Resolvers::Ci::GroupRunnersResolver do status_status: 'active', type_type: :group_type, tag_name: ['active_runner'], - preload: { tag_name: nil }, + preload: { tag_name: false }, search: 'abc', sort: 'contacted_asc', membership: :descendants, diff --git a/spec/graphql/resolvers/ci/project_runners_resolver_spec.rb b/spec/graphql/resolvers/ci/project_runners_resolver_spec.rb new file mode 100644 index 00000000000..4cc00ced104 --- /dev/null +++ b/spec/graphql/resolvers/ci/project_runners_resolver_spec.rb @@ -0,0 +1,86 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Resolvers::Ci::ProjectRunnersResolver, feature_category: :runner_fleet do + include GraphqlHelpers + + describe '#resolve' do + subject do + resolve(described_class, obj: obj, ctx: { current_user: user }, args: args, + arg_style: :internal) + end + + include_context 'runners resolver setup' + + let(:obj) { project } + let(:args) { {} } + + context 'when user cannot see runners' do + it 'returns no runners' do + expect(subject.items.to_a).to eq([]) + end + end + + context 'with user as project admin' do + before do + project.add_maintainer(user) + end + + let(:available_runners) { [inactive_project_runner, offline_project_runner, group_runner, instance_runner] } + + it 'returns all runners available to the project' do + expect(subject.items.to_a).to match_array(available_runners) + end + end + + context 'with obj set to nil' do + let(:obj) { nil } + + it 'raises an error' do + expect { subject }.to raise_error('Expected project missing') + end + end + + context 'with obj not set to project' do + let(:obj) { build(:group) } + + it 'raises an error' do + expect { subject }.to raise_error('Expected project missing') + end + end + + describe 'Allowed query arguments' do + let(:finder) { instance_double(::Ci::RunnersFinder) } + let(:args) do + { + status: 'active', + type: :group_type, + tag_list: ['active_runner'], + search: 'abc', + sort: :contacted_asc + } + end + + let(:expected_params) do + { + status_status: 'active', + type_type: :group_type, + tag_name: ['active_runner'], + preload: { tag_name: false }, + search: 'abc', + sort: 'contacted_asc', + project: project + } + end + + it 'calls RunnersFinder with expected arguments' do + allow(::Ci::RunnersFinder).to receive(:new).with(current_user: user, + params: expected_params).once.and_return(finder) + allow(finder).to receive(:execute).once.and_return([:execute_return_value]) + + expect(subject.items.to_a).to eq([:execute_return_value]) + end + end + end +end diff --git a/spec/graphql/resolvers/ci/runner_groups_resolver_spec.rb b/spec/graphql/resolvers/ci/runner_groups_resolver_spec.rb new file mode 100644 index 00000000000..9272689ef0b --- /dev/null +++ b/spec/graphql/resolvers/ci/runner_groups_resolver_spec.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Resolvers::Ci::RunnerGroupsResolver, feature_category: :runner_fleet do + include GraphqlHelpers + + let_it_be(:group1) { create(:group) } + let_it_be(:runner) { create(:ci_runner, :group, groups: [group1]) } + + let(:args) { {} } + + subject(:response) { resolve_groups(args) } + + describe '#resolve' do + context 'with authorized user', :enable_admin_mode do + let(:current_user) { create(:user, :admin) } + + it 'returns a lazy value with all groups' do + expect(response).to be_a(GraphQL::Execution::Lazy) + expect(response.value).to contain_exactly(group1) + end + end + + context 'with unauthorized user' do + let(:current_user) { create(:user) } + + it { is_expected.to be_nil } + end + end + + private + + def resolve_groups(args = {}, context = { current_user: current_user }) + resolve(described_class, obj: runner, args: args, ctx: context) + end +end diff --git a/spec/graphql/resolvers/ci/runner_jobs_resolver_spec.rb b/spec/graphql/resolvers/ci/runner_jobs_resolver_spec.rb index ba8a127bec5..963a642fa4e 100644 --- a/spec/graphql/resolvers/ci/runner_jobs_resolver_spec.rb +++ b/spec/graphql/resolvers/ci/runner_jobs_resolver_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Resolvers::Ci::RunnerJobsResolver do +RSpec.describe Resolvers::Ci::RunnerJobsResolver, feature_category: :runner_fleet do include GraphqlHelpers let_it_be(:project) { create(:project, :repository) } diff --git a/spec/graphql/resolvers/ci/runner_platforms_resolver_spec.rb b/spec/graphql/resolvers/ci/runner_platforms_resolver_spec.rb index 3cb6e94e81e..1d1fb4a9967 100644 --- a/spec/graphql/resolvers/ci/runner_platforms_resolver_spec.rb +++ b/spec/graphql/resolvers/ci/runner_platforms_resolver_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Resolvers::Ci::RunnerPlatformsResolver do +RSpec.describe Resolvers::Ci::RunnerPlatformsResolver, feature_category: :runner_fleet do include GraphqlHelpers describe '#resolve' do diff --git a/spec/graphql/resolvers/ci/runner_projects_resolver_spec.rb b/spec/graphql/resolvers/ci/runner_projects_resolver_spec.rb index 952c7337d65..6c69cdc19cc 100644 --- a/spec/graphql/resolvers/ci/runner_projects_resolver_spec.rb +++ b/spec/graphql/resolvers/ci/runner_projects_resolver_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Resolvers::Ci::RunnerProjectsResolver do +RSpec.describe Resolvers::Ci::RunnerProjectsResolver, feature_category: :runner_fleet do include GraphqlHelpers let_it_be(:project1) { create(:project, description: 'Project1.1') } diff --git a/spec/graphql/resolvers/ci/runner_setup_resolver_spec.rb b/spec/graphql/resolvers/ci/runner_setup_resolver_spec.rb index 13ef89023d9..734337f7c92 100644 --- a/spec/graphql/resolvers/ci/runner_setup_resolver_spec.rb +++ b/spec/graphql/resolvers/ci/runner_setup_resolver_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Resolvers::Ci::RunnerSetupResolver do +RSpec.describe Resolvers::Ci::RunnerSetupResolver, feature_category: :runner_fleet do include GraphqlHelpers describe '#resolve' do diff --git a/spec/graphql/resolvers/ci/runner_status_resolver_spec.rb b/spec/graphql/resolvers/ci/runner_status_resolver_spec.rb index fbef07b72e6..2bea256856d 100644 --- a/spec/graphql/resolvers/ci/runner_status_resolver_spec.rb +++ b/spec/graphql/resolvers/ci/runner_status_resolver_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Resolvers::Ci::RunnerStatusResolver do +RSpec.describe Resolvers::Ci::RunnerStatusResolver, feature_category: :runner_fleet do include GraphqlHelpers describe '#resolve' do diff --git a/spec/graphql/resolvers/ci/runners_resolver_spec.rb b/spec/graphql/resolvers/ci/runners_resolver_spec.rb index 4038192a68a..d6da8222234 100644 --- a/spec/graphql/resolvers/ci/runners_resolver_spec.rb +++ b/spec/graphql/resolvers/ci/runners_resolver_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Resolvers::Ci::RunnersResolver do +RSpec.describe Resolvers::Ci::RunnersResolver, feature_category: :runner_fleet do include GraphqlHelpers describe '#resolve' do @@ -28,8 +28,24 @@ RSpec.describe Resolvers::Ci::RunnersResolver do context 'when user can see runners' do let(:obj) { nil } - it 'returns all the runners' do - expect(subject.items.to_a).to contain_exactly(inactive_project_runner, offline_project_runner, group_runner, subgroup_runner, instance_runner) + context 'when admin mode setting is disabled', :do_not_mock_admin_mode_setting do + it 'returns all the runners' do + expect(subject.items.to_a).to contain_exactly(inactive_project_runner, offline_project_runner, group_runner, subgroup_runner, instance_runner) + end + end + + context 'when admin mode setting is enabled' do + context 'when in admin mode', :enable_admin_mode do + it 'returns all the runners' do + expect(subject.items.to_a).to contain_exactly(inactive_project_runner, offline_project_runner, group_runner, subgroup_runner, instance_runner) + end + end + + context 'when not in admin mode' do + it 'returns no runners' do + expect(subject.items.to_a).to eq([]) + end + end end end @@ -67,7 +83,7 @@ RSpec.describe Resolvers::Ci::RunnersResolver do upgrade_status: 'recommended', type_type: :instance_type, tag_name: ['active_runner'], - preload: { tag_name: nil }, + preload: { tag_name: false }, search: 'abc', sort: 'contacted_asc' } @@ -92,7 +108,7 @@ RSpec.describe Resolvers::Ci::RunnersResolver do let(:expected_params) do { active: false, - preload: { tag_name: nil } + preload: { tag_name: false } } end @@ -112,7 +128,7 @@ RSpec.describe Resolvers::Ci::RunnersResolver do let(:expected_params) do { active: false, - preload: { tag_name: nil } + preload: { tag_name: false } } end @@ -131,7 +147,7 @@ RSpec.describe Resolvers::Ci::RunnersResolver do let(:expected_params) do { - preload: { tag_name: nil } + preload: { tag_name: false } } end diff --git a/spec/graphql/resolvers/design_management/design_resolver_spec.rb b/spec/graphql/resolvers/design_management/design_resolver_spec.rb index 0915dddf438..3a62f24993a 100644 --- a/spec/graphql/resolvers/design_management/design_resolver_spec.rb +++ b/spec/graphql/resolvers/design_management/design_resolver_spec.rb @@ -6,14 +6,14 @@ RSpec.describe Resolvers::DesignManagement::DesignResolver do include GraphqlHelpers include DesignManagementTestHelpers - specify do - expect(described_class).to have_nullable_graphql_type(::Types::DesignManagement::DesignType) - end - before do enable_design_management end + specify do + expect(described_class).to have_nullable_graphql_type(::Types::DesignManagement::DesignType) + end + describe '#resolve' do let_it_be(:issue) { create(:issue) } let_it_be(:project) { issue.project } diff --git a/spec/graphql/resolvers/design_management/designs_resolver_spec.rb b/spec/graphql/resolvers/design_management/designs_resolver_spec.rb index 64eae14d888..7024e62c670 100644 --- a/spec/graphql/resolvers/design_management/designs_resolver_spec.rb +++ b/spec/graphql/resolvers/design_management/designs_resolver_spec.rb @@ -6,14 +6,14 @@ RSpec.describe Resolvers::DesignManagement::DesignsResolver do include GraphqlHelpers include DesignManagementTestHelpers - specify do - expect(described_class).to have_nullable_graphql_type(::Types::DesignManagement::DesignType.connection_type) - end - before do enable_design_management end + specify do + expect(described_class).to have_nullable_graphql_type(::Types::DesignManagement::DesignType.connection_type) + end + describe '#resolve' do let_it_be(:issue) { create(:issue) } let_it_be(:project) { issue.project } diff --git a/spec/graphql/resolvers/environments/nested_environments_resolver_spec.rb b/spec/graphql/resolvers/environments/nested_environments_resolver_spec.rb new file mode 100644 index 00000000000..07197b1838f --- /dev/null +++ b/spec/graphql/resolvers/environments/nested_environments_resolver_spec.rb @@ -0,0 +1,47 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Resolvers::Environments::NestedEnvironmentsResolver, feature_category: :continuous_delivery do + include GraphqlHelpers + include Gitlab::Graphql::Laziness + + let_it_be(:project) { create(:project, :repository, :private) } + let_it_be(:environment) { create(:environment, project: project, name: 'test') } + let_it_be(:environment2) { create(:environment, project: project, name: 'folder1/test') } + let_it_be(:environment3) { create(:environment, project: project, name: 'folder1/test2') } + let_it_be(:environment4) { create(:environment, project: project, name: 'folder2/test') } + + let_it_be(:developer) { create(:user).tap { |u| project.add_developer(u) } } + + let(:current_user) { developer } + + describe '#resolve' do + it 'finds the nested environments when status matches' do + expect(resolve_nested_environments(status: :created).to_a.pluck(:name, :size)) + .to match_array([ + ['test', 1], + ['folder1', 2], + ['folder2', 1] + ]) + end + + it 'finds the nested environments when searching by name' do + expect(resolve_nested_environments(search: 'folder2').to_a.pluck(:name, :size)) + .to match_array([ + ['folder2', 1] + ]) + end + + it 'finds the nested environments when name matches exactly' do + expect(resolve_nested_environments(name: 'test').to_a.pluck(:name, :size)) + .to match_array([ + ['test', 1] + ]) + end + end + + def resolve_nested_environments(args = {}, context = { current_user: current_user }) + resolve(described_class, obj: project, ctx: context, args: args) + end +end diff --git a/spec/graphql/resolvers/environments_resolver_spec.rb b/spec/graphql/resolvers/environments_resolver_spec.rb index 9f4c4716de0..b1f7dc1673e 100644 --- a/spec/graphql/resolvers/environments_resolver_spec.rb +++ b/spec/graphql/resolvers/environments_resolver_spec.rb @@ -13,6 +13,9 @@ RSpec.describe Resolvers::EnvironmentsResolver do let!(:environment1) { create(:environment, :available, name: 'production', project: project) } let!(:environment2) { create(:environment, :stopped, name: 'test', project: project) } let!(:environment3) { create(:environment, :available, name: 'test2', project: project) } + let!(:environment4) { create(:environment, :available, name: 'folder1/test1', project: project) } + let!(:environment5) { create(:environment, :available, name: 'folder1/test2', project: project) } + let!(:environment6) { create(:environment, :available, name: 'folder2/test3', project: project) } before do group.add_developer(current_user) @@ -20,7 +23,12 @@ RSpec.describe Resolvers::EnvironmentsResolver do describe '#resolve' do it 'finds all environments' do - expect(resolve_environments).to contain_exactly(environment1, environment2, environment3) + expect(resolve_environments).to contain_exactly(environment1, + environment2, + environment3, + environment4, + environment5, + environment6) end context 'with name' do @@ -31,7 +39,7 @@ RSpec.describe Resolvers::EnvironmentsResolver do context 'with search' do it 'searches environment by name' do - expect(resolve_environments(search: 'test')).to contain_exactly(environment2, environment3) + expect(resolve_environments(search: 'production')).to contain_exactly(environment1) end context 'when the search term does not match any environments' do @@ -43,7 +51,11 @@ RSpec.describe Resolvers::EnvironmentsResolver do context 'with states' do it 'searches environments by state' do - expect(resolve_environments(states: ['available'])).to contain_exactly(environment1, environment3) + expect(resolve_environments(states: ['available'])).to contain_exactly(environment1, + environment3, + environment4, + environment5, + environment6) end it 'generates an error if requested state is invalid' do @@ -53,6 +65,16 @@ RSpec.describe Resolvers::EnvironmentsResolver do end end + context 'with environment_type' do + it 'searches environments by type' do + expect(resolve_environments(type: 'folder1')).to contain_exactly(environment4, environment5) + end + + it 'returns an empty result' do + expect(resolve_environments(type: 'folder3')).to be_empty + end + end + context 'when project is nil' do subject { resolve(described_class, obj: nil, args: {}, ctx: { current_user: current_user }) } diff --git a/spec/graphql/resolvers/namespace_projects_resolver_spec.rb b/spec/graphql/resolvers/namespace_projects_resolver_spec.rb index 78dd5173449..07ea98f00c7 100644 --- a/spec/graphql/resolvers/namespace_projects_resolver_spec.rb +++ b/spec/graphql/resolvers/namespace_projects_resolver_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Resolvers::NamespaceProjectsResolver do +RSpec.describe Resolvers::NamespaceProjectsResolver, feature_category: :subgroups do include GraphqlHelpers let(:current_user) { create(:user) } diff --git a/spec/graphql/resolvers/paginated_tree_resolver_spec.rb b/spec/graphql/resolvers/paginated_tree_resolver_spec.rb index 4b05e9076d7..9a04b716001 100644 --- a/spec/graphql/resolvers/paginated_tree_resolver_spec.rb +++ b/spec/graphql/resolvers/paginated_tree_resolver_spec.rb @@ -66,9 +66,8 @@ RSpec.describe Resolvers::PaginatedTreeResolver do let(:args) { super().merge(after: 'invalid') } it 'generates an error' do - expect_graphql_error_to_be_created(Gitlab::Graphql::Errors::ArgumentError) do - subject - end + expect_graphql_error_to_be_created(Gitlab::Graphql::Errors::BaseError) { subject } + expect(subject.extensions.keys).to match_array([:code, :gitaly_code, :service]) end end @@ -92,6 +91,22 @@ RSpec.describe Resolvers::PaginatedTreeResolver do expect(collected_entries).to match_array(expected_entries) end end + + describe 'Custom error handling' do + before do + grpc_err = GRPC::Unavailable.new + allow(repository).to receive(:tree).and_raise(Gitlab::Git::CommandError, grpc_err) + end + + context 'when gitaly is not available' do + let(:request) { get :index, format: :html, params: { namespace_id: project.namespace, project_id: project } } + + it 'generates an unavailable error' do + expect_graphql_error_to_be_created(Gitlab::Graphql::Errors::BaseError) { subject } + expect(subject.extensions).to eq(code: 'unavailable', gitaly_code: 14, service: 'git') + end + end + end end def resolve_repository(args, opts = {}) diff --git a/spec/graphql/resolvers/project_pipeline_resolver_spec.rb b/spec/graphql/resolvers/project_pipeline_resolver_spec.rb index 398f8f52269..9250485e4c8 100644 --- a/spec/graphql/resolvers/project_pipeline_resolver_spec.rb +++ b/spec/graphql/resolvers/project_pipeline_resolver_spec.rb @@ -12,6 +12,10 @@ RSpec.describe Resolvers::ProjectPipelineResolver do let(:current_user) { create(:user) } + before do + project.add_developer(current_user) + end + specify do expect(described_class).to have_nullable_graphql_type(::Types::Ci::PipelineType) end @@ -20,10 +24,6 @@ RSpec.describe Resolvers::ProjectPipelineResolver do resolve(described_class, obj: project, args: args, ctx: { current_user: current_user }) end - before do - project.add_developer(current_user) - end - it 'resolves pipeline for the passed iid' do expect(Ci::PipelinesFinder) .to receive(:new) diff --git a/spec/graphql/resolvers/users/participants_resolver_spec.rb b/spec/graphql/resolvers/users/participants_resolver_spec.rb index eb2418b63f4..27c3b9643ce 100644 --- a/spec/graphql/resolvers/users/participants_resolver_spec.rb +++ b/spec/graphql/resolvers/users/participants_resolver_spec.rb @@ -115,7 +115,8 @@ RSpec.describe Resolvers::Users::ParticipantsResolver do create(:award_emoji, name: 'thumbsup', awardable: public_note) # 1 extra query per source (3 emojis + 2 notes) to fetch participables collection - expect { query.call }.not_to exceed_query_limit(control_count).with_threshold(5) + # 1 extra query to load work item widgets collection + expect { query.call }.not_to exceed_query_limit(control_count).with_threshold(6) end it 'does not execute N+1 for system note metadata relation' do diff --git a/spec/graphql/types/alert_management/alert_type_spec.rb b/spec/graphql/types/alert_management/alert_type_spec.rb index 69cbdb998eb..c1df24ccb5c 100644 --- a/spec/graphql/types/alert_management/alert_type_spec.rb +++ b/spec/graphql/types/alert_management/alert_type_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe GitlabSchema.types['AlertManagementAlert'] do +RSpec.describe GitlabSchema.types['AlertManagementAlert'], feature_category: :incident_management do specify { expect(described_class.graphql_name).to eq('AlertManagementAlert') } specify { expect(described_class).to require_graphql_authorizations(:read_alert_management_alert) } @@ -11,6 +11,7 @@ RSpec.describe GitlabSchema.types['AlertManagementAlert'] do it 'exposes the expected fields' do expected_fields = %i[ + id iid issueIid issue diff --git a/spec/graphql/types/ci/detailed_status_type_spec.rb b/spec/graphql/types/ci/detailed_status_type_spec.rb index 686461cb9a5..81ab1b52552 100644 --- a/spec/graphql/types/ci/detailed_status_type_spec.rb +++ b/spec/graphql/types/ci/detailed_status_type_spec.rb @@ -5,6 +5,8 @@ require 'spec_helper' RSpec.describe Types::Ci::DetailedStatusType do include GraphqlHelpers + let_it_be(:stage) { create(:ci_stage, status: :skipped) } + specify { expect(described_class.graphql_name).to eq('DetailedStatus') } it 'has all fields' do @@ -13,8 +15,6 @@ RSpec.describe Types::Ci::DetailedStatusType do :label, :text, :tooltip, :action) end - let_it_be(:stage) { create(:ci_stage, status: :skipped) } - describe 'id field' do it 'correctly renders the field' do status = stage.detailed_status(stage.pipeline.user) diff --git a/spec/graphql/types/ci/freeze_period_status_enum_spec.rb b/spec/graphql/types/ci/freeze_period_status_enum_spec.rb new file mode 100644 index 00000000000..2d9c7071392 --- /dev/null +++ b/spec/graphql/types/ci/freeze_period_status_enum_spec.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe GitlabSchema.types['CiFreezePeriodStatus'], feature_category: :release_orchestration do + it 'exposes all freeze period statuses' do + expect(described_class.values.keys).to contain_exactly(*%w[ACTIVE INACTIVE]) + end +end diff --git a/spec/graphql/types/ci/freeze_period_type_spec.rb b/spec/graphql/types/ci/freeze_period_type_spec.rb new file mode 100644 index 00000000000..a7f7c2f9dc8 --- /dev/null +++ b/spec/graphql/types/ci/freeze_period_type_spec.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe GitlabSchema.types['CiFreezePeriod'], feature_category: :release_orchestration do + specify { expect(described_class.graphql_name).to eq('CiFreezePeriod') } + + it 'has the expected fields' do + expected_fields = %w[ + status start_cron end_cron cron_timezone start_time end_time + ] + + expect(described_class).to have_graphql_fields(*expected_fields) + end + + specify { expect(described_class).to require_graphql_authorizations(:read_freeze_period) } +end diff --git a/spec/graphql/types/ci/pipeline_counts_type_spec.rb b/spec/graphql/types/ci/pipeline_counts_type_spec.rb index 7fdb286d253..6452827dc7b 100644 --- a/spec/graphql/types/ci/pipeline_counts_type_spec.rb +++ b/spec/graphql/types/ci/pipeline_counts_type_spec.rb @@ -32,7 +32,7 @@ RSpec.describe GitlabSchema.types['PipelineCounts'] do expect(described_class).to include_graphql_fields(*expected_fields) end - shared_examples 'pipeline counts query' do |args: "", expected_counts:| + shared_examples 'pipeline counts query' do |expected_counts:, args: ""| let_it_be(:query) do %( query { diff --git a/spec/graphql/types/ci/pipeline_schedule_type_spec.rb b/spec/graphql/types/ci/pipeline_schedule_type_spec.rb index bf1413ef657..6e6c6c63969 100644 --- a/spec/graphql/types/ci/pipeline_schedule_type_spec.rb +++ b/spec/graphql/types/ci/pipeline_schedule_type_spec.rb @@ -14,6 +14,7 @@ RSpec.describe Types::Ci::PipelineScheduleType do description owner active + project lastPipeline refForDisplay refPath @@ -23,6 +24,13 @@ RSpec.describe Types::Ci::PipelineScheduleType do cron cronTimezone userPermissions + editPath + cron + cronTimezone + ref + variables + createdAt + updatedAt ] expect(described_class).to have_graphql_fields(*expected_fields) diff --git a/spec/graphql/types/ci/pipeline_schedule_variable_type_spec.rb b/spec/graphql/types/ci/pipeline_schedule_variable_type_spec.rb new file mode 100644 index 00000000000..1c98539e308 --- /dev/null +++ b/spec/graphql/types/ci/pipeline_schedule_variable_type_spec.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Types::Ci::PipelineScheduleVariableType do + specify { expect(described_class.graphql_name).to eq('PipelineScheduleVariable') } + specify { expect(described_class.interfaces).to contain_exactly(Types::Ci::VariableInterface) } + specify { expect(described_class).to require_graphql_authorizations(:read_pipeline_schedule_variables) } + + it 'contains attributes related to a pipeline message' do + expected_fields = %w[ + id key raw value variable_type + ] + + expect(described_class).to have_graphql_fields(*expected_fields) + end +end diff --git a/spec/graphql/types/ci/runner_type_spec.rb b/spec/graphql/types/ci/runner_type_spec.rb index 4ec35db13fb..b078d7f5fac 100644 --- a/spec/graphql/types/ci/runner_type_spec.rb +++ b/spec/graphql/types/ci/runner_type_spec.rb @@ -12,7 +12,7 @@ RSpec.describe GitlabSchema.types['CiRunner'] do id description created_at contacted_at maximum_timeout access_level active paused status version short_sha revision locked run_untagged ip_address runner_type tag_list project_count job_count admin_url edit_admin_url user_permissions executor_name architecture_name platform_name - maintenance_note maintenance_note_html groups projects jobs token_expires_at owner_project + maintenance_note maintenance_note_html groups projects jobs token_expires_at owner_project job_execution_status ] expect(described_class).to include_graphql_fields(*expected_fields) diff --git a/spec/graphql/types/commit_signatures/ssh_signature_type_spec.rb b/spec/graphql/types/commit_signatures/ssh_signature_type_spec.rb new file mode 100644 index 00000000000..4ffb70a0b22 --- /dev/null +++ b/spec/graphql/types/commit_signatures/ssh_signature_type_spec.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe GitlabSchema.types['SshSignature'], feature_category: :source_code_management do + specify { expect(described_class.graphql_name).to eq('SshSignature') } + + specify { expect(described_class).to require_graphql_authorizations(:download_code) } + + specify { expect(described_class).to include(Types::CommitSignatureInterface) } + + it 'contains attributes related to SSH signatures' do + expect(described_class).to have_graphql_fields( + :user, :verification_status, :commit_sha, :project, :key + ) + end +end diff --git a/spec/graphql/types/deployment_details_type_spec.rb b/spec/graphql/types/deployment_details_type_spec.rb deleted file mode 100644 index 7dc0c8f97ac..00000000000 --- a/spec/graphql/types/deployment_details_type_spec.rb +++ /dev/null @@ -1,17 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe GitlabSchema.types['DeploymentDetails'] do - specify { expect(described_class.graphql_name).to eq('DeploymentDetails') } - - it 'has the expected fields' do - expected_fields = %w[ - id iid ref tag tags sha created_at updated_at finished_at status commit job triggerer - ] - - expect(described_class).to include_graphql_fields(*expected_fields) - end - - specify { expect(described_class).to require_graphql_authorizations(:read_deployment) } -end diff --git a/spec/graphql/types/deployment_type_spec.rb b/spec/graphql/types/deployment_type_spec.rb index bf4be0523c6..4c49391d7a8 100644 --- a/spec/graphql/types/deployment_type_spec.rb +++ b/spec/graphql/types/deployment_type_spec.rb @@ -2,15 +2,16 @@ require 'spec_helper' -RSpec.describe GitlabSchema.types['Deployment'] do +RSpec.describe GitlabSchema.types['Deployment'], feature_category: :continuous_delivery do specify { expect(described_class.graphql_name).to eq('Deployment') } + specify { expect(described_class).to expose_permissions_using(Types::PermissionTypes::Deployment) } it 'has the expected fields' do expected_fields = %w[ - id iid ref tag sha created_at updated_at finished_at status commit job triggerer + id iid ref tag tags sha created_at updated_at finished_at status commit job triggerer userPermissions ] - expect(described_class).to have_graphql_fields(*expected_fields) + expect(described_class).to include_graphql_fields(*expected_fields) end specify { expect(described_class).to require_graphql_authorizations(:read_deployment) } diff --git a/spec/graphql/types/environment_type_spec.rb b/spec/graphql/types/environment_type_spec.rb index 2605beac95a..4471735876a 100644 --- a/spec/graphql/types/environment_type_spec.rb +++ b/spec/graphql/types/environment_type_spec.rb @@ -4,11 +4,12 @@ require 'spec_helper' RSpec.describe GitlabSchema.types['Environment'] do specify { expect(described_class.graphql_name).to eq('Environment') } + specify { expect(described_class).to expose_permissions_using(Types::PermissionTypes::Environment) } it 'includes the expected fields' do expected_fields = %w[ name id state metrics_dashboard latest_opened_most_severe_alert path external_url deployments - slug createdAt updatedAt autoStopAt autoDeleteAt tier environmentType lastDeployment + slug createdAt updatedAt autoStopAt autoDeleteAt tier environmentType lastDeployment deployFreezes ] expect(described_class).to include_graphql_fields(*expected_fields) diff --git a/spec/graphql/types/issue_type_enum_spec.rb b/spec/graphql/types/issue_type_enum_spec.rb index cd1737c3ebb..33a3a9cf8ce 100644 --- a/spec/graphql/types/issue_type_enum_spec.rb +++ b/spec/graphql/types/issue_type_enum_spec.rb @@ -2,12 +2,12 @@ require 'spec_helper' -RSpec.describe Types::IssueTypeEnum do +RSpec.describe Types::IssueTypeEnum, feature_category: :team_planning do specify { expect(described_class.graphql_name).to eq('IssueType') } it 'exposes all the existing issue type values except key_result' do expect(described_class.values.keys).to match_array( - %w[ISSUE INCIDENT TEST_CASE REQUIREMENT TASK OBJECTIVE] + %w[ISSUE INCIDENT TEST_CASE REQUIREMENT TASK OBJECTIVE KEY_RESULT] ) end end diff --git a/spec/graphql/types/key_type_spec.rb b/spec/graphql/types/key_type_spec.rb new file mode 100644 index 00000000000..78144076467 --- /dev/null +++ b/spec/graphql/types/key_type_spec.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe GitlabSchema.types['Key'], feature_category: :authentication_and_authorization do + specify { expect(described_class.graphql_name).to eq('Key') } + + it 'contains attributes for SSH keys' do + expect(described_class).to have_graphql_fields( + :id, :title, :created_at, :expires_at, :key + ) + end +end diff --git a/spec/graphql/types/merge_request_type_spec.rb b/spec/graphql/types/merge_request_type_spec.rb index 7ab254238fb..8a4c89fc340 100644 --- a/spec/graphql/types/merge_request_type_spec.rb +++ b/spec/graphql/types/merge_request_type_spec.rb @@ -116,12 +116,12 @@ RSpec.describe GitlabSchema.types['MergeRequest'] do describe 'merge_status_enum' do let(:type) { GitlabSchema.types['MergeStatus'] } + let_it_be(:project) { create(:project, :public) } + it 'has the type MergeStatus' do expect(described_class.fields['mergeStatusEnum']).to have_graphql_type(type) end - let_it_be(:project) { create(:project, :public) } - %i[preparing unchecked cannot_be_merged_recheck checking cannot_be_merged_rechecking can_be_merged cannot_be_merged].each do |state| context "when the the DB value is #{state}" do let(:merge_request) { create(:merge_request, :unique_branches, source_project: project, merge_status: state.to_s) } diff --git a/spec/graphql/types/permission_types/base_permission_type_spec.rb b/spec/graphql/types/permission_types/base_permission_type_spec.rb index e4726ad0e6e..f437c3778c6 100644 --- a/spec/graphql/types/permission_types/base_permission_type_spec.rb +++ b/spec/graphql/types/permission_types/base_permission_type_spec.rb @@ -51,4 +51,25 @@ RSpec.describe Types::PermissionTypes::BasePermissionType do expect(test_type).to have_graphql_field(:admin_issue) end end + + describe 'extensions' do + subject(:test_type) do + Class.new(described_class) do + graphql_name 'TestClass' + + permission_field :read_entity_a do + extension ::Gitlab::Graphql::Limit::FieldCallCount, limit: 1 + end + + ability_field(:read_entity_b) do + extension ::Gitlab::Graphql::Limit::FieldCallCount, limit: 1 + end + end + end + + it 'has the extension' do + expect(test_type.fields['readEntityA'].extensions).to include(a_kind_of(::Gitlab::Graphql::Limit::FieldCallCount)) + expect(test_type.fields['readEntityB'].extensions).to include(a_kind_of(::Gitlab::Graphql::Limit::FieldCallCount)) + end + end end diff --git a/spec/graphql/types/permission_types/deployment_spec.rb b/spec/graphql/types/permission_types/deployment_spec.rb new file mode 100644 index 00000000000..ccf5798984c --- /dev/null +++ b/spec/graphql/types/permission_types/deployment_spec.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Types::PermissionTypes::Deployment, feature_category: :continuous_delivery do + it do + expected_permissions = %i[update_deployment destroy_deployment] + + expect(described_class).to include_graphql_fields(*expected_permissions) + end +end diff --git a/spec/graphql/types/permission_types/environment_spec.rb b/spec/graphql/types/permission_types/environment_spec.rb new file mode 100644 index 00000000000..944699c972a --- /dev/null +++ b/spec/graphql/types/permission_types/environment_spec.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Types::PermissionTypes::Environment, feature_category: :continuous_delivery do + it do + expected_permissions = [ + :update_environment, :destroy_environment, :stop_environment + ] + + expected_permissions.each do |permission| + expect(described_class).to have_graphql_field(permission) + end + end +end diff --git a/spec/graphql/types/permission_types/project_spec.rb b/spec/graphql/types/permission_types/project_spec.rb index c6853a0eadc..645fc6c68d1 100644 --- a/spec/graphql/types/permission_types/project_spec.rb +++ b/spec/graphql/types/permission_types/project_spec.rb @@ -13,7 +13,7 @@ RSpec.describe Types::PermissionTypes::Project do :create_merge_request_from, :create_wiki, :push_code, :create_deployment, :push_to_delete_protected_branch, :admin_wiki, :admin_project, :update_pages, :admin_remote_mirror, :create_label, :update_wiki, :destroy_wiki, :create_pages, :destroy_pages, :read_pages_content, - :read_merge_request, :read_design, :create_design, :destroy_design + :read_merge_request, :read_design, :create_design, :destroy_design, :read_environment ] expected_permissions.each do |permission| diff --git a/spec/graphql/types/project_type_spec.rb b/spec/graphql/types/project_type_spec.rb index 30fabb8e9e2..4151789372b 100644 --- a/spec/graphql/types/project_type_spec.rb +++ b/spec/graphql/types/project_type_spec.rb @@ -492,7 +492,7 @@ RSpec.describe GitlabSchema.types['Project'] do subject { described_class.fields['jobs'] } it { is_expected.to have_graphql_type(Types::Ci::JobType.connection_type) } - it { is_expected.to have_graphql_arguments(:statuses) } + it { is_expected.to have_graphql_arguments(:statuses, :with_artifacts) } end describe 'ci_template field' do diff --git a/spec/graphql/types/projects/fork_details_type_spec.rb b/spec/graphql/types/projects/fork_details_type_spec.rb new file mode 100644 index 00000000000..8e20e2c8299 --- /dev/null +++ b/spec/graphql/types/projects/fork_details_type_spec.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe GitlabSchema.types['ForkDetails'], feature_category: :source_code_management do + specify { expect(described_class.graphql_name).to eq('ForkDetails') } + + it 'has specific fields' do + fields = %i[ + ahead + behind + ] + + expect(described_class).to have_graphql_fields(*fields) + end +end diff --git a/spec/graphql/types/projects/service_type_enum_spec.rb b/spec/graphql/types/projects/service_type_enum_spec.rb index f7256910bb0..8b444a08c3b 100644 --- a/spec/graphql/types/projects/service_type_enum_spec.rb +++ b/spec/graphql/types/projects/service_type_enum_spec.rb @@ -23,7 +23,6 @@ RSpec.describe GitlabSchema.types['ServiceType'] do EMAILS_ON_PUSH_SERVICE EWM_SERVICE EXTERNAL_WIKI_SERVICE - FLOWDOCK_SERVICE HANGOUTS_CHAT_SERVICE IRKER_SERVICE JENKINS_SERVICE diff --git a/spec/graphql/types/snippets/blob_type_spec.rb b/spec/graphql/types/snippets/blob_type_spec.rb index e20b001ba7f..9eef6ac4cdc 100644 --- a/spec/graphql/types/snippets/blob_type_spec.rb +++ b/spec/graphql/types/snippets/blob_type_spec.rb @@ -5,15 +5,7 @@ require 'spec_helper' RSpec.describe GitlabSchema.types['SnippetBlob'] do include GraphqlHelpers - it 'has the correct fields' do - expected_fields = [:rich_data, :plain_data, :raw_plain_data, - :raw_path, :size, :binary, :name, :path, - :simple_viewer, :rich_viewer, :mode, :external_storage, - :rendered_as_text] - - expect(described_class).to have_graphql_fields(*expected_fields) - end - + let_it_be(:blob) { create(:snippet, :public, :repository).blobs.first } let_it_be(:nullity) do { 'richData' => be_nullable, @@ -32,7 +24,14 @@ RSpec.describe GitlabSchema.types['SnippetBlob'] do } end - let_it_be(:blob) { create(:snippet, :public, :repository).blobs.first } + it 'has the correct fields' do + expected_fields = [:rich_data, :plain_data, :raw_plain_data, + :raw_path, :size, :binary, :name, :path, + :simple_viewer, :rich_viewer, :mode, :external_storage, + :rendered_as_text] + + expect(described_class).to have_graphql_fields(*expected_fields) + end shared_examples 'a field from the snippet blob presenter' do |field| it "resolves using the presenter", :request_store do diff --git a/spec/graphql/types/subscription_type_spec.rb b/spec/graphql/types/subscription_type_spec.rb index 04f0c72b06f..a57a8e751ac 100644 --- a/spec/graphql/types/subscription_type_spec.rb +++ b/spec/graphql/types/subscription_type_spec.rb @@ -14,6 +14,7 @@ RSpec.describe GitlabSchema.types['Subscription'] do issuable_milestone_updated merge_request_reviewers_updated merge_request_merge_status_updated + merge_request_approval_state_updated ] expect(described_class).to include_graphql_fields(*expected_fields) diff --git a/spec/graphql/types/todo_type_spec.rb b/spec/graphql/types/todo_type_spec.rb index c7bb7c67959..2118a777a45 100644 --- a/spec/graphql/types/todo_type_spec.rb +++ b/spec/graphql/types/todo_type_spec.rb @@ -3,6 +3,11 @@ require 'spec_helper' RSpec.describe GitlabSchema.types['Todo'] do + let_it_be(:current_user) { create(:user) } + let_it_be(:author) { create(:user) } + + let(:issue) { create(:issue, project: project) } + it 'has the correct fields' do expected_fields = [ :id, @@ -22,4 +27,116 @@ RSpec.describe GitlabSchema.types['Todo'] do end specify { expect(described_class).to require_graphql_authorizations(:read_todo) } + + subject { GitlabSchema.execute(query, context: { current_user: current_user }).as_json } + + describe 'project field' do + let(:todo) do + create(:todo, + user: current_user, + project: project, + state: :done, + action: Todo::ASSIGNED, + author: author, + target: issue) + end + + let(:query) do + %( + query { + todo(id: "#{todo.to_global_id}") { + project { + id + } + } + } + ) + end + + context 'when the project is public' do + let_it_be(:project) { create(:project, :public) } + + context 'when the user does not have access' do + it 'returns the project' do + expect(subject.dig('data', 'todo', 'project', 'id')).to eq(project.to_global_id.to_s) + end + end + end + + context 'when the project is not public' do + let_it_be(:project) { create(:project) } + + context 'when the user does not have access' do + it 'returns null' do + expect(subject.dig('data', 'todo', 'project')).to be_nil + end + end + + context 'when the user does have access' do + before do + project.add_guest(current_user) + end + + it 'returns the project' do + expect(subject.dig('data', 'todo', 'project', 'id')).to eq(project.to_global_id.to_s) + end + end + end + end + + describe 'group field' do + let(:todo) do + create(:todo, + user: current_user, + group: group, + state: :done, + action: Todo::MENTIONED, + author: author, + target: issue) + end + + let(:query) do + %( + query { + todo(id: "#{todo.to_global_id}") { + group { + id + } + } + } + ) + end + + context 'when the group is public' do + let_it_be(:group) { create(:group, :public) } + let_it_be(:project) { create(:project, :public, group: group) } + + context 'when the user does not have access' do + it 'returns the group' do + expect(subject.dig('data', 'todo', 'group', 'id')).to eq(group.to_global_id.to_s) + end + end + end + + context 'when the group is not public' do + let_it_be(:group) { create(:group) } + let_it_be(:project) { create(:project, group: group) } + + context 'when the user does not have access' do + it 'returns null' do + expect(subject.dig('data', 'todo', 'group')).to be_nil + end + end + + context 'when the user does have access' do + before do + group.add_guest(current_user) + end + + it 'returns the group' do + expect(subject.dig('data', 'todo', 'group', 'id')).to eq(group.to_global_id.to_s) + end + end + end + end end diff --git a/spec/graphql/types/work_items/notes_filter_type_enum_spec.rb b/spec/graphql/types/work_items/notes_filter_type_enum_spec.rb new file mode 100644 index 00000000000..13ce559c529 --- /dev/null +++ b/spec/graphql/types/work_items/notes_filter_type_enum_spec.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe GitlabSchema.types['NotesFilterType'], feature_category: :team_planning do + specify { expect(described_class.graphql_name).to eq('NotesFilterType') } + + it 'exposes all the existing widget type values' do + expect(described_class.values.transform_values(&:value)).to include( + "ALL_NOTES" => 0, "ONLY_ACTIVITY" => 2, "ONLY_COMMENTS" => 1 + ) + end +end diff --git a/spec/graphql/types/work_items/widget_interface_spec.rb b/spec/graphql/types/work_items/widget_interface_spec.rb index b9e8edacf15..a2b12ed52dc 100644 --- a/spec/graphql/types/work_items/widget_interface_spec.rb +++ b/spec/graphql/types/work_items/widget_interface_spec.rb @@ -19,6 +19,7 @@ RSpec.describe Types::WorkItems::WidgetInterface do WorkItems::Widgets::Hierarchy | Types::WorkItems::Widgets::HierarchyType WorkItems::Widgets::Assignees | Types::WorkItems::Widgets::AssigneesType WorkItems::Widgets::Labels | Types::WorkItems::Widgets::LabelsType + WorkItems::Widgets::Notes | Types::WorkItems::Widgets::NotesType end with_them do diff --git a/spec/graphql/types/work_items/widgets/hierarchy_type_spec.rb b/spec/graphql/types/work_items/widgets/hierarchy_type_spec.rb index 1722a07c5f4..20413a35c58 100644 --- a/spec/graphql/types/work_items/widgets/hierarchy_type_spec.rb +++ b/spec/graphql/types/work_items/widgets/hierarchy_type_spec.rb @@ -2,9 +2,9 @@ require 'spec_helper' -RSpec.describe Types::WorkItems::Widgets::HierarchyType do +RSpec.describe Types::WorkItems::Widgets::HierarchyType, feature_category: :team_planning do it 'exposes the expected fields' do - expected_fields = %i[parent children type] + expected_fields = %i[parent children has_children type] expect(described_class).to have_graphql_fields(*expected_fields) end diff --git a/spec/graphql/types/work_items/widgets/notes_type_spec.rb b/spec/graphql/types/work_items/widgets/notes_type_spec.rb new file mode 100644 index 00000000000..3ac61a59a9c --- /dev/null +++ b/spec/graphql/types/work_items/widgets/notes_type_spec.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Types::WorkItems::Widgets::NotesType, feature_category: :team_planning do + it 'exposes the expected fields' do + expected_fields = %i[discussions type] + + expect(described_class).to have_graphql_fields(*expected_fields) + end +end |