Commit 89009fc7 authored by Alexandru Croitor's avatar Alexandru Croitor

Remove GraphQL deprecated fields

Cleanup graphql deprecations. Removed:
- Query.vulnerabilitiesCountByDayAndSeverity
- Group.vulnerabilitiesCountByDayAndSeverity
- Mutation.addAwardEmoji
- Mutation.removeAwardEmoji
- Mutation.toggleAwardEmoji
- (globalId field) on Mutation.dastScannerProfileCreate
- Mutation.runDastScan
- (updatedIds field) on Mutation.todoRestoreMany
- (updatedIds field) on Mutation.todosMarkAllDone
- Mutation.dismissVulnerability
- Mutation.revertVulnerabilityToDetected
- SnippetType.blob
- DastScannerProfileType.globalId

Changelog: removed
parent eeef2847
......@@ -7,12 +7,6 @@ module Mutations
authorize :update_user
field :updated_ids,
[::Types::GlobalIDType[::Todo]],
null: false,
deprecated: { reason: 'Use to-do items', milestone: '13.2' },
description: 'IDs of the updated to-do items.'
field :todos, [::Types::TodoType],
null: false,
description: 'Updated to-do items.'
......@@ -23,7 +17,6 @@ module Mutations
updated_ids = mark_all_todos_done
{
updated_ids: updated_ids,
todos: Todo.id_in(updated_ids),
errors: []
}
......
......@@ -12,11 +12,6 @@ module Mutations
required: true,
description: 'The global IDs of the to-do items to restore (a maximum of 50 is supported at once).'
field :updated_ids, [::Types::GlobalIDType[Todo]],
null: false,
description: 'The IDs of the updated to-do items.',
deprecated: { reason: 'Use to-do items', milestone: '13.2' }
field :todos, [::Types::TodoType],
null: false,
description: 'Updated to-do items.'
......
......@@ -5,15 +5,7 @@ module Types
extend ActiveSupport::Concern
prepended do
mount_aliased_mutation 'AddAwardEmoji',
Mutations::AwardEmojis::Add,
deprecated: { reason: 'Use awardEmojiAdd', milestone: '13.2' }
mount_aliased_mutation 'RemoveAwardEmoji',
Mutations::AwardEmojis::Remove,
deprecated: { reason: 'Use awardEmojiRemove', milestone: '13.2' }
mount_aliased_mutation 'ToggleAwardEmoji',
Mutations::AwardEmojis::Toggle,
deprecated: { reason: 'Use awardEmojiToggle', milestone: '13.2' }
# placeholder for any FOSS mutations to be deprecated
end
end
end
......@@ -61,12 +61,6 @@ module Types
description: 'Raw URL of the snippet.',
null: false
field :blob, type: Types::Snippets::BlobType,
description: 'Snippet blob.',
calls_gitaly: true,
null: false,
deprecated: { reason: 'Use `blobs`', milestone: '13.3' }
field :blobs, type: Types::Snippets::BlobType.connection_type,
description: 'Snippet blobs.',
calls_gitaly: true,
......
This diff is collapsed.
......@@ -10,6 +10,32 @@ GraphQL is a versionless API, unlike the REST API.
Occasionally, items have to be updated or removed from the GraphQL API.
According to our [process for removing items](index.md#deprecation-and-removal-process), here are the items that have been removed.
## GitLab 14.0
Fields removed in [GitLab 14.0](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/63293):
### GraphQL Mutations
| Argument name | Mutation | Deprecated in | Use instead |
| -------------------- | -------------------- | ------------- | -------------------------- |
| `updated_ids` | `todosMarkAllDone` | 13.2 | `todos` |
| `updated_ids` | `todoRestoreMany` | 13.2 | `todos` |
| `global_id` | `dastScannerProfileCreate`| 13.6 | `todos` |
| - | `addAwardEmoji` | 13.2 | `awardEmojiAdd` |
| - | `removeAwardEmoji` | 13.2 | `awardEmojiRemove` |
| - | `toggleAwardEmoji` | 13.2 | `ToggleAwardEmoji` |
| - | `runDastScan` | 13.5 | `dastOnDemandScanCreate` |
| - | `dismissVulnerability` | 13.5 | `vulnerabilityDismiss` |
| - | `revertVulnerabilityToDetected` | 13.5 | `vulnerabilityRevertToDetected` |
### GraphQL Types
| Field name | GraphQL type | Deprecated in | Use instead |
| -------------------- | -------------------- | ------------- | -------------------------- |
| `blob` | `SnippetType` | 13.3 | `blobs` |
| `global_id` | `DastScannerProfileType` | 13.6 | `blobs` |
| `vulnerabilities_count_by_day_and_severity` | `GroupType`, `QueryType` | 13.3 | None. Plaintext tokens no longer supported for security reasons. |
## GitLab 13.6
Fields removed in [GitLab 13.6](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/44866):
......
mutation runDastScan(
$projectPath: ID!
$targetUrl: String!
$branch: String!
$scanType: DastScanTypeEnum!
) {
runDastScan(
input: {
projectPath: $projectPath
targetUrl: $targetUrl
branch: $branch
scanType: $scanType
}
) {
pipelineUrl
errors
}
}
......@@ -6,15 +6,6 @@ module EE
extend ActiveSupport::Concern
prepended do
mount_mutation ::Mutations::Pipelines::RunDastScan,
deprecated: { reason: 'Use DastOnDemandScanCreate', milestone: '13.4' }
mount_aliased_mutation 'DismissVulnerability', ::Mutations::Vulnerabilities::Dismiss,
deprecated: { reason: 'Use vulnerabilityDismiss', milestone: '13.5' }
mount_aliased_mutation 'RevertVulnerabilityToDetected', ::Mutations::Vulnerabilities::RevertToDetected,
deprecated: { reason: 'Use vulnerabilityRevertToDetected', milestone: '13.5' }
mount_aliased_mutation 'CreateIteration', ::Mutations::Iterations::Create,
deprecated: { reason: 'Use iterationCreate', milestone: '14.0' }
end
......
......@@ -65,13 +65,6 @@ module EE
description: 'Number of vulnerabilities per day for the projects in the group and its subgroups.',
resolver: ::Resolvers::VulnerabilitiesCountPerDayResolver
field :vulnerabilities_count_by_day_and_severity,
::Types::VulnerabilitiesCountByDayAndSeverityType.connection_type,
null: true,
description: 'Number of vulnerabilities per severity level, per day, for the projects in the group and its subgroups.',
resolver: ::Resolvers::VulnerabilitiesHistoryResolver,
deprecated: { reason: 'Use `vulnerabilitiesCountByDay`', milestone: '13.3' }
field :vulnerability_grades,
[::Types::VulnerableProjectsByGradeType],
null: false,
......
......@@ -37,16 +37,6 @@ module EE
Number of vulnerabilities per day for the projects on the current user's instance security dashboard.
DESC
field :vulnerabilities_count_by_day_and_severity,
::Types::VulnerabilitiesCountByDayAndSeverityType.connection_type,
null: true,
resolver: ::Resolvers::VulnerabilitiesHistoryResolver,
deprecated: { reason: :discouraged, replacement: 'Query.vulnerabilitiesCountByDay', milestone: '13.3' },
description: <<~DESC
Number of vulnerabilities per severity level, per day, for the projects on the
current user's instance security dashboard.
DESC
field :geo_node, ::Types::Geo::GeoNodeType,
null: true,
resolver: ::Resolvers::Geo::GeoNodeResolver,
......
......@@ -11,11 +11,6 @@ module Mutations
null: true,
description: 'ID of the scanner profile.'
field :global_id, ::Types::GlobalIDType[::DastScannerProfile],
null: true,
description: 'ID of the scanner profile.',
deprecated: { reason: 'Use `id`', milestone: '13.6' }
argument :full_path, GraphQL::ID_TYPE,
required: true,
description: 'The project the scanner profile belongs to.'
......
# frozen_string_literal: true
module Mutations
module Pipelines
class RunDastScan < BaseMutation
include FindsProject
graphql_name 'RunDASTScan'
field :pipeline_url, GraphQL::STRING_TYPE,
null: true,
description: 'URL of the pipeline that was created.'
argument :project_path, GraphQL::ID_TYPE,
required: true,
description: 'The project the DAST scan belongs to.'
argument :target_url, GraphQL::STRING_TYPE,
required: true,
description: 'The URL of the target to be scanned.'
argument :branch, GraphQL::STRING_TYPE,
required: true,
description: 'The branch to be associated with the scan.'
argument :scan_type, Types::DastScanTypeEnum,
required: true,
description: 'The type of scan to be run.'
authorize :create_on_demand_dast_scan
def resolve(project_path:, target_url:, branch:, scan_type:)
project = authorized_find!(project_path)
result = ::DastOnDemandScans::CreateService.new(
container: project,
current_user: current_user,
params: {
branch: branch,
dast_site_profile: DastSiteProfile.new(dast_site: DastSite.new(url: target_url))
}
).execute
if result.success?
success_response(project: project, pipeline: result.payload[:pipeline])
else
error_response(result.message)
end
end
private
def success_response(project:, pipeline:)
pipeline_url = Rails.application.routes.url_helpers.project_pipeline_url(
project,
pipeline
)
{
errors: [],
pipeline_url: pipeline_url
}
end
def error_response(message)
{ errors: [message] }
end
end
end
end
# frozen_string_literal: true
module Resolvers
class VulnerabilitiesHistoryResolver < VulnerabilitiesBaseResolver
include Gitlab::Utils::StrongMemoize
MAX_DAYS = ::Vulnerability::MAX_DAYS_OF_HISTORY
type Types::VulnerabilitiesCountByDayAndSeverityType, null: true
argument :start_date, GraphQL::Types::ISO8601Date, required: true,
description: 'First day for which to fetch vulnerability history.'
argument :end_date, GraphQL::Types::ISO8601Date, required: true,
description: 'Last day for which to fetch vulnerability history.'
def resolve(**args)
return [] unless vulnerable
start_date = args[:start_date]
end_date = args[:end_date]
days = end_date - start_date + 1
if days > MAX_DAYS
raise ::Vulnerability::TooManyDaysError, "Cannot fetch counts for more than #{MAX_DAYS} days"
else
vulnerable.vulnerabilities.counts_by_day_and_severity(start_date, end_date).to_a
end
end
end
end
......@@ -10,11 +10,6 @@ module Types
field :id, ::Types::GlobalIDType[::DastScannerProfile], null: false,
description: 'ID of the DAST scanner profile.'
field :global_id, ::Types::GlobalIDType[::DastScannerProfile], null: false,
description: 'ID of the DAST scanner profile.',
deprecated: { reason: 'Use `id`', milestone: '13.6' },
method: :id
field :profile_name, GraphQL::STRING_TYPE, null: true,
description: 'Name of the DAST scanner profile.',
method: :name
......
# frozen_string_literal: true
module Types
# rubocop: disable Graphql/AuthorizeTypes
class VulnerabilitiesCountByDayAndSeverityType < BaseObject
graphql_name 'VulnerabilitiesCountByDayAndSeverity'
description 'Represents the number of vulnerabilities for a particular severity on a particular day. This data is retained for 365 days'
field :count, GraphQL::INT_TYPE, null: true,
description: 'Number of vulnerabilities.'
field :day, GraphQL::Types::ISO8601Date, null: true,
description: 'Date for the count.'
field :severity, VulnerabilitySeverityEnum, null: true,
description: 'Severity of the counted vulnerabilities.'
end
end
......@@ -16,7 +16,7 @@ RSpec.describe GitlabSchema.types['Group'] do
it { expect(described_class).to have_graphql_field(:timelogs, complexity: 5) }
it { expect(described_class).to have_graphql_field(:vulnerabilities) }
it { expect(described_class).to have_graphql_field(:vulnerability_scanners) }
it { expect(described_class).to have_graphql_field(:vulnerabilities_count_by_day_and_severity) }
it { expect(described_class).to have_graphql_field(:vulnerabilities_count_by_day) }
it { expect(described_class).to have_graphql_field(:vulnerability_grades) }
it { expect(described_class).to have_graphql_field(:code_coverage_activities) }
it { expect(described_class).to have_graphql_field(:stats) }
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Mutations::Pipelines::RunDastScan do
let(:group) { create(:group) }
let(:project) { create(:project, :repository, group: group) }
let(:user) { create(:user) }
let(:project_path) { project.full_path }
let(:target_url) { generate(:url) }
let(:branch) { project.default_branch }
let(:scan_type) { Types::DastScanTypeEnum.enum[:passive] }
subject(:mutation) { described_class.new(object: nil, context: { current_user: user }, field: nil) }
before do
stub_licensed_features(security_on_demand_scans: true)
end
describe '#resolve' do
subject do
mutation.resolve(
branch: branch,
project_path: project_path,
target_url: target_url,
scan_type: scan_type
)
end
context 'when on demand scan feature is not enabled' do
it 'raises an exception' do
expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
end
end
context 'when on demand scan feature is enabled' do
context 'when the project does not exist' do
let(:project_path) { SecureRandom.hex }
it 'raises an exception' do
expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
end
end
context 'when the user is not associated with the project' do
it 'raises an exception' do
expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
end
end
context 'when the user is an owner' do
it 'has no errors' do
group.add_owner(user)
expect(subject[:errors]).to be_empty
end
end
context 'when the user is a maintainer' do
it 'has no errors' do
project.add_maintainer(user)
expect(subject[:errors]).to be_empty
end
end
context 'when the user is a developer' do
it 'has no errors' do
project.add_developer(user)
expect(subject[:errors]).to be_empty
end
end
context 'when the user can run a dast scan' do
it 'returns a pipeline_url containing the correct path' do
project.add_developer(user)
actual_url = subject[:pipeline_url]
pipeline = Ci::Pipeline.last
expected_url = Rails.application.routes.url_helpers.project_pipeline_url(
project,
pipeline
)
expect(actual_url).to eq(expected_url)
end
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Resolvers::VulnerabilitiesHistoryResolver do
include GraphqlHelpers
subject { resolve(described_class, obj: group, args: args, ctx: { current_user: user }) }
let_it_be(:group) { create(:group) }
let_it_be(:project) { create(:project, namespace: group) }
let_it_be(:user) { create(:user) }
describe '#resolve' do
let(:args) { { start_date: Date.parse('2019-10-15'), end_date: Date.parse('2019-10-21') } }
it "fetches historical vulnerability data from the start date to the end date" do
travel_to(Date.parse('2019-10-31')) do
create(:vulnerability, :critical, created_at: 15.days.ago, dismissed_at: 10.days.ago, project: project)
create(:vulnerability, :high, created_at: 15.days.ago, dismissed_at: 11.days.ago, project: project)
create(:vulnerability, :critical, created_at: 14.days.ago, resolved_at: 12.days.ago, project: project)
ordered_history = subject.sort_by { |count| [count['day'], count['severity']] }
expect(ordered_history.to_json).to eq([
{ 'day' => '2019-10-16', 'severity' => 'critical', 'count' => 1, 'id' => nil },
{ 'day' => '2019-10-16', 'severity' => 'high', 'count' => 1, 'id' => nil },
{ 'day' => '2019-10-17', 'severity' => 'critical', 'count' => 2, 'id' => nil },
{ 'day' => '2019-10-17', 'severity' => 'high', 'count' => 1, 'id' => nil },
{ 'day' => '2019-10-18', 'severity' => 'critical', 'count' => 2, 'id' => nil },
{ 'day' => '2019-10-18', 'severity' => 'high', 'count' => 1, 'id' => nil },
{ 'day' => '2019-10-19', 'severity' => 'critical', 'count' => 1, 'id' => nil },
{ 'day' => '2019-10-19', 'severity' => 'high', 'count' => 1, 'id' => nil },
{ 'day' => '2019-10-20', 'severity' => 'critical', 'count' => 1, 'id' => nil }
].to_json)
end
end
context 'when given more than 10 days' do
let(:args) { { start_date: Date.parse('2019-10-11'), end_date: Date.parse('2019-10-21') } }
it 'raises an error stating that no more than 10 days can be requested' do
expect { subject }.to raise_error(::Vulnerability::TooManyDaysError, 'Cannot fetch counts for more than 10 days')
end
end
end
end
......@@ -8,7 +8,7 @@ RSpec.describe GitlabSchema.types['DastScannerProfile'] do
let_it_be(:dast_scanner_profile) { create(:dast_scanner_profile) }
let_it_be(:project) { dast_scanner_profile.project }
let_it_be(:user) { create(:user) }
let_it_be(:fields) { %i[id globalId profileName spiderTimeout targetTimeout editPath scanType useAjaxSpider showDebugMessages referencedInSecurityPolicies] }
let_it_be(:fields) { %i[id profileName spiderTimeout targetTimeout editPath scanType useAjaxSpider showDebugMessages referencedInSecurityPolicies] }
let(:response) do
GitlabSchema.execute(
......@@ -45,7 +45,6 @@ RSpec.describe GitlabSchema.types['DastScannerProfile'] do
dastScannerProfiles {
nodes {
id
globalId
profileName
targetTimeout
spiderTimeout
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe GitlabSchema.types['Mutation'] do
describe 'deprecated mutations' do
using RSpec::Parameterized::TableSyntax
where(:field_name, :reason, :milestone) do
'RunDastScan' | 'Use DastOnDemandScanCreate' | '13.4'
end
with_them do
let(:field) { get_field(field_name) }
let(:deprecation_reason) { "#{reason}. Deprecated in #{milestone}." }
it { expect(field).to be_present }
it { expect(field.deprecation_reason).to eq(deprecation_reason) }
end
end
describe 'aliased deprecated mutations' do
using RSpec::Parameterized::TableSyntax
where(:alias_name, :canonical_name) do
'DismissVulnerability' | 'VulnerabilityDismiss'
'RevertVulnerabilityToDetected' | 'VulnerabilityRevertToDetected'
end
with_them do
let(:alias_field) { get_field(alias_name) }
let(:canonical_field) { get_field(canonical_name) }
it { expect(alias_field).to be_present }
it { expect(canonical_field).to be_present }
it { expect(alias_field.deprecation_reason).to be_present }
it { expect(canonical_field.deprecation_reason).not_to be_present }
it { expect(alias_field.resolver.fields).to eq(canonical_field.resolver.fields) }
it { expect(alias_field.resolver.arguments).to eq(canonical_field.resolver.arguments) }
end
end
def get_field(name)
described_class.fields[GraphqlHelpers.fieldnamerize(name.camelize)]
end
end
......@@ -10,7 +10,7 @@ RSpec.describe GitlabSchema.types['Query'] do
:vulnerabilities,
:vulnerability,
:instance_security_dashboard,
:vulnerabilities_count_by_day_and_severity,
:vulnerabilities_count_by_day,
:current_license,
:license_history_entries
).at_least
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe GitlabSchema.types['VulnerabilitiesCountByDayAndSeverity'] do
it { expect(described_class).to have_graphql_fields(:count, :day, :severity) }
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'group(fullPath).vulnerabilitiesCountByDayAndSeverity' do
include GraphqlHelpers
let_it_be(:group) { create(:group) }
let_it_be(:project) { create(:project, namespace: group) }
let_it_be(:current_user) { create(:user) }
let(:query) { graphql_query_for(:group, { fullPath: group.full_path }, history_field) }
let(:query_result) { graphql_data.dig('group', 'vulnerabilitiesCountByDayAndSeverity', 'nodes') }
let(:history_field) do
query_graphql_field(
:vulnerabilitiesCountByDayAndSeverity,
{
start_date: Date.parse('2019-10-15').iso8601,
end_date: Date.parse('2019-10-21').iso8601
},
history_fields
)
end
let(:history_fields) do
query_graphql_field(:nodes, nil, <<~FIELDS)
count
day
severity
FIELDS
end
it "fetches historical vulnerability data from the start date to the end date for projects in the group and its subgroups" do
travel_to(Time.zone.parse('2019-10-31')) do
project.add_developer(current_user)
create(:vulnerability, :critical, created_at: 15.days.ago, dismissed_at: 10.days.ago, project: project)
create(:vulnerability, :high, created_at: 15.days.ago, dismissed_at: 11.days.ago, project: project)
create(:vulnerability, :critical, created_at: 14.days.ago, resolved_at: 12.days.ago, project: project)
post_graphql(query, current_user: current_user)
ordered_history = query_result.sort_by { |count| [count['day'], count['severity']] }
expect(ordered_history).to eq([
{ 'severity' => 'CRITICAL', 'day' => '2019-10-16', 'count' => 1 },
{ 'severity' => 'HIGH', 'day' => '2019-10-16', 'count' => 1 },
{ 'severity' => 'CRITICAL', 'day' => '2019-10-17', 'count' => 2 },
{ 'severity' => 'HIGH', 'day' => '2019-10-17', 'count' => 1 },
{ 'severity' => 'CRITICAL', 'day' => '2019-10-18', 'count' => 2 },
{ 'severity' => 'HIGH', 'day' => '2019-10-18', 'count' => 1 },
{ 'severity' => 'CRITICAL', 'day' => '2019-10-19', 'count' => 1 },
{ 'severity' => 'HIGH', 'day' => '2019-10-19', 'count' => 1 },
{ 'severity' => 'CRITICAL', 'day' => '2019-10-20', 'count' => 1 }
])
end
end
end
......@@ -25,12 +25,6 @@ RSpec.describe 'Creating a DAST Scanner Profile' do
expect(mutation_response['id']).to eq(dast_scanner_profile.to_global_id.to_s)
end
it 'returns the dast_scanner_profile global_id' do
post_graphql_mutation(mutation, current_user: current_user)
expect(mutation_response['globalId']).to eq(dast_scanner_profile.to_global_id.to_s)
end
it 'sets default values of omitted properties' do
post_graphql_mutation(mutation, current_user: current_user)
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'Running a DAST Scan' do
include GraphqlHelpers
let(:project) { create(:project, :repository, creator: current_user) }
let(:current_user) { create(:user) }
let(:project_path) { project.full_path }
let(:target_url) { generate(:url) }
let(:branch) { project.default_branch }
let(:scan_type) { Types::DastScanTypeEnum.enum[:passive].upcase }
let(:mutation) do
graphql_mutation(
:run_dast_scan,
branch: branch,
project_path: project_path,
target_url: target_url,
scan_type: scan_type
)
end
def mutation_response
graphql_mutation_response(:run_dast_scan)
end
before do
stub_licensed_features(security_on_demand_scans: true)
end
context 'when on demand scan feature is not enabled' do
it_behaves_like 'a mutation that returns top-level errors',
errors: ['The resource that you are attempting to access does not ' \
'exist or you don\'t have permission to perform this action']
end
context 'when on demand scan feature is enabled' do
context 'when the user does not have permission to run a dast scan' do
it_behaves_like 'a mutation that returns top-level errors',
errors: ['The resource that you are attempting to access does not ' \
'exist or you don\'t have permission to perform this action']
end
context 'when the user can run a dast scan' do
before do
project.add_developer(current_user)
end
it 'returns a pipeline_url containing the correct path' do
post_graphql_mutation(mutation, current_user: current_user)
pipeline = Ci::Pipeline.last
expected_url = Rails.application.routes.url_helpers.project_pipeline_url(
project,
pipeline
)
expect(mutation_response['pipelineUrl']).to eq(expected_url)
end
context 'when pipeline creation fails' do
before do
allow_any_instance_of(Ci::Pipeline).to receive(:created_successfully?).and_return(false)
allow_any_instance_of(Ci::Pipeline).to receive(:full_error_messages).and_return('error message')
end
it_behaves_like 'a mutation that returns errors in the response', errors: ['error message']
end
end
end
end
......@@ -87,11 +87,5 @@ RSpec.describe 'Query.project(fullPath).dastScannerProfiles' do
it { is_expected.to eq(dast_scanner_profile.to_global_id.to_s) }
end
describe 'first dast scanner profile globalId' do
subject { response_data.dig('project', 'dastScannerProfiles', 'nodes').first['globalId'] }
it { is_expected.to eq(dast_scanner_profile.to_global_id.to_s) }
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'Query' do
include GraphqlHelpers
describe '.vulnerabilitiesCountByDayAndSeverity' do
let(:query_result) { graphql_data.dig('vulnerabilitiesCountByDayAndSeverity', 'nodes') }
let(:query) do
graphql_query_for(
:vulnerabilitiesCountByDayAndSeverity,
{
start_date: Date.parse('2019-10-15').iso8601,
end_date: Date.parse('2019-10-21').iso8601
},
history_fields
)
end
let(:history_fields) do
query_graphql_field(:nodes, nil, <<~FIELDS)
count
day
severity
FIELDS
end
it "fetches historical vulnerability data from the start date to the end date for projects on the current user's instance security dashboard" do
travel_to(Time.zone.parse('2019-10-31')) do
project = create(:project)
current_user = create(:user)
current_user.security_dashboard_projects << project
project.add_developer(current_user)
create(:vulnerability, :critical, created_at: 15.days.ago, dismissed_at: 10.days.ago, project: project)
create(:vulnerability, :high, created_at: 15.days.ago, dismissed_at: 11.days.ago, project: project)
create(:vulnerability, :critical, created_at: 14.days.ago, resolved_at: 12.days.ago, project: project)
post_graphql(query, current_user: current_user)
ordered_history = query_result.sort_by { |count| [count['day'], count['severity']] }
expect(ordered_history).to eq([
{ 'severity' => 'CRITICAL', 'day' => '2019-10-16', 'count' => 1 },
{ 'severity' => 'HIGH', 'day' => '2019-10-16', 'count' => 1 },
{ 'severity' => 'CRITICAL', 'day' => '2019-10-17', 'count' => 2 },
{ 'severity' => 'HIGH', 'day' => '2019-10-17', 'count' => 1 },
{ 'severity' => 'CRITICAL', 'day' => '2019-10-18', 'count' => 2 },
{ 'severity' => 'HIGH', 'day' => '2019-10-18', 'count' => 1 },
{ 'severity' => 'CRITICAL', 'day' => '2019-10-19', 'count' => 1 },
{ 'severity' => 'HIGH', 'day' => '2019-10-19', 'count' => 1 },
{ 'severity' => 'CRITICAL', 'day' => '2019-10-20', 'count' => 1 }
])
end
end
end
end
......@@ -21,26 +21,25 @@ RSpec.describe Mutations::Todos::MarkAllDone do
describe '#resolve' do
it 'marks all pending todos as done' do
updated_todo_ids, todos = mutation_for(current_user).resolve.values_at(:updated_ids, :todos)
todos = mutation_for(current_user).resolve[:todos]
expect(todo1.reload.state).to eq('done')
expect(todo2.reload.state).to eq('done')
expect(todo3.reload.state).to eq('done')
expect(other_user_todo.reload.state).to eq('pending')
expect(updated_todo_ids).to contain_exactly(todo1.id, todo3.id)
expect(todos).to contain_exactly(todo1, todo3)
end
it 'behaves as expected if there are no todos for the requesting user' do
updated_todo_ids = mutation_for(user3).resolve.dig(:updated_ids)
todos = mutation_for(user3).resolve[:todos]
expect(todo1.reload.state).to eq('pending')
expect(todo2.reload.state).to eq('done')
expect(todo3.reload.state).to eq('pending')
expect(other_user_todo.reload.state).to eq('pending')
expect(updated_todo_ids).to be_empty
expect(todos).to be_empty
end
context 'when user is not logged in' do
......
......@@ -15,28 +15,6 @@ RSpec.describe Types::MutationType do
expect(described_class).to have_graphql_mutation(Mutations::MergeRequests::SetDraft)
end
describe 'deprecated and aliased mutations' do
using RSpec::Parameterized::TableSyntax
where(:alias_name, :canonical_name) do
'AddAwardEmoji' | 'AwardEmojiAdd'
'RemoveAwardEmoji' | 'AwardEmojiRemove'
'ToggleAwardEmoji' | 'AwardEmojiToggle'
end
with_them do
let(:alias_field) { get_field(alias_name) }
let(:canonical_field) { get_field(canonical_name) }
it { expect(alias_field).to be_present }
it { expect(canonical_field).to be_present }
it { expect(alias_field.deprecation_reason).to be_present }
it { expect(canonical_field.deprecation_reason).not_to be_present }
it { expect(alias_field.resolver.fields).to eq(canonical_field.resolver.fields) }
it { expect(alias_field.resolver.arguments).to eq(canonical_field.resolver.arguments) }
end
end
def get_field(name)
described_class.fields[GraphqlHelpers.fieldnamerize(name)]
end
......
......@@ -13,7 +13,7 @@ RSpec.describe GitlabSchema.types['Snippet'] do
:visibility_level, :created_at, :updated_at,
:web_url, :raw_url, :ssh_url_to_repo, :http_url_to_repo,
:notes, :discussions, :user_permissions,
:description_html, :blob, :blobs]
:description_html, :blobs]
expect(described_class).to have_graphql_fields(*expected_fields)
end
......@@ -133,32 +133,6 @@ RSpec.describe GitlabSchema.types['Snippet'] do
end
end
describe '#blob' do
let(:query_blob) { subject.dig('data', 'snippets', 'nodes')[0]['blob'] }
subject { GitlabSchema.execute(snippet_query_for(field: 'blob'), context: { current_user: user }).as_json }
context 'when snippet has repository' do
let!(:snippet) { create(:personal_snippet, :repository, :public, author: user) }
let(:blob) { snippet.blobs.first }
it 'returns the first blob from the repository' do
expect(query_blob['name']).to eq blob.name
expect(query_blob['path']).to eq blob.path
end
end
context 'when snippet does not have a repository' do
let!(:snippet) { create(:personal_snippet, :public, author: user) }
let(:blob) { snippet.blob }
it 'returns SnippetBlob type' do
expect(query_blob['name']).to eq blob.name
expect(query_blob['path']).to eq blob.path
end
end
end
describe '#blobs' do
let_it_be(:snippet) { create(:personal_snippet, :public, author: user) }
......
......@@ -31,7 +31,7 @@ RSpec.describe GitlabSchema.types['SnippetBlobViewer'] do
end
it 'returns false' do
snippet_blob = subject.dig('data', 'snippets', 'edges')[0].dig('node', 'blob')
snippet_blob = subject.dig('data', 'snippets', 'edges').first.dig('node', 'blobs', 'nodes').find { |b| b['path'] == blob.path }
expect(snippet_blob['path']).to eq blob.path
expect(blob_attribute).to be_nil
......@@ -47,10 +47,12 @@ RSpec.describe GitlabSchema.types['SnippetBlobViewer'] do
snippets(ids: "#{snippet.to_global_id}") {
edges {
node {
blob {
path
simpleViewer {
collapsed
blobs {
nodes {
path
simpleViewer {
collapsed
}
}
}
}
......@@ -73,10 +75,12 @@ RSpec.describe GitlabSchema.types['SnippetBlobViewer'] do
snippets(ids: "#{snippet.to_global_id}") {
edges {
node {
blob {
path
simpleViewer {
tooLarge
blobs {
nodes {
path
simpleViewer {
tooLarge
}
}
}
}
......
......@@ -22,8 +22,8 @@ RSpec.describe 'Marking all todos done' do
graphql_mutation(:todos_mark_all_done, input,
<<-QL.strip_heredoc
clientMutationId
todos { id }
errors
updatedIds
QL
)
end
......@@ -40,7 +40,7 @@ RSpec.describe 'Marking all todos done' do
expect(todo3.reload.state).to eq('done')
expect(other_user_todo.reload.state).to eq('pending')
updated_todo_ids = mutation_response['updatedIds']
updated_todo_ids = mutation_response['todos'].map { |todo| todo['id'] }
expect(updated_todo_ids).to contain_exactly(global_id_of(todo1), global_id_of(todo3))
end
......@@ -52,7 +52,7 @@ RSpec.describe 'Marking all todos done' do
expect(todo3.reload.state).to eq('pending')
expect(other_user_todo.reload.state).to eq('pending')
updated_todo_ids = mutation_response['updatedIds']
updated_todo_ids = mutation_response['todos']
expect(updated_todo_ids).to be_empty
end
......
......@@ -22,7 +22,6 @@ RSpec.describe 'Restoring many Todos' do
<<-QL.strip_heredoc
clientMutationId
errors
updatedIds
todos {
id
state
......@@ -44,7 +43,6 @@ RSpec.describe 'Restoring many Todos' do
expect(mutation_response).to include(
'errors' => be_empty,
'updatedIds' => match_array(input_ids),
'todos' => contain_exactly(
{ 'id' => global_id_of(todo1), 'state' => 'pending' },
{ 'id' => global_id_of(todo2), 'state' => 'pending' }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment