summaryrefslogtreecommitdiff
path: root/spec/lib/gitlab/graphql
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-10-21 07:08:36 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2020-10-21 07:08:36 +0000
commit48aff82709769b098321c738f3444b9bdaa694c6 (patch)
treee00c7c43e2d9b603a5a6af576b1685e400410dee /spec/lib/gitlab/graphql
parent879f5329ee916a948223f8f43d77fba4da6cd028 (diff)
downloadgitlab-ce-48aff82709769b098321c738f3444b9bdaa694c6.tar.gz
Add latest changes from gitlab-org/gitlab@13-5-stable-eev13.5.0-rc42
Diffstat (limited to 'spec/lib/gitlab/graphql')
-rw-r--r--spec/lib/gitlab/graphql/authorize/authorize_field_service_spec.rb49
-rw-r--r--spec/lib/gitlab/graphql/markdown_field/resolver_spec.rb33
-rw-r--r--spec/lib/gitlab/graphql/markdown_field_spec.rb59
-rw-r--r--spec/lib/gitlab/graphql/pagination/keyset/last_items_spec.rb26
-rw-r--r--spec/lib/gitlab/graphql/pagination/keyset/order_info_spec.rb23
-rw-r--r--spec/lib/gitlab/graphql/pagination/keyset/query_builder_spec.rb7
-rw-r--r--spec/lib/gitlab/graphql/query_analyzers/logger_analyzer_spec.rb2
7 files changed, 130 insertions, 69 deletions
diff --git a/spec/lib/gitlab/graphql/authorize/authorize_field_service_spec.rb b/spec/lib/gitlab/graphql/authorize/authorize_field_service_spec.rb
index efe6c27c463..7576523ce52 100644
--- a/spec/lib/gitlab/graphql/authorize/authorize_field_service_spec.rb
+++ b/spec/lib/gitlab/graphql/authorize/authorize_field_service_spec.rb
@@ -19,24 +19,29 @@ RSpec.describe Gitlab::Graphql::Authorize::AuthorizeFieldService do
options.reverse_merge!(null: true)
field :test_field, field_type,
authorize: field_authorizations,
- resolve: -> (_, _, _) { resolved_value },
**options
+
+ define_method :test_field do
+ resolved_value
+ end
end
end
- let(:current_user) { double(:current_user) }
-
subject(:service) { described_class.new(field) }
describe '#authorized_resolve' do
- let(:presented_object) { double('presented object') }
- let(:presented_type) { double('parent type', object: presented_object) }
- let(:query_type) { GraphQL::ObjectType.new }
- let(:schema) { GraphQL::Schema.define(query: query_type, mutation: nil)}
- let(:query_context) { OpenStruct.new(schema: schema) }
- let(:context) { GraphQL::Query::Context.new(query: OpenStruct.new(schema: schema, context: query_context), values: { current_user: current_user }, object: nil) }
+ let_it_be(:current_user) { build(:user) }
+ let_it_be(:presented_object) { 'presented object' }
+ let_it_be(:query_type) { GraphQL::ObjectType.new }
+ let_it_be(:schema) { GraphQL::Schema.define(query: query_type, mutation: nil)}
+ let_it_be(:query) { GraphQL::Query.new(schema, document: nil, context: {}, variables: {}) }
+ let_it_be(:context) { GraphQL::Query::Context.new(query: query, values: { current_user: current_user }, object: nil) }
+
+ let(:type_class) { type_with_field(custom_type, :read_field, presented_object) }
+ let(:type_instance) { type_class.authorized_new(presented_object, context) }
+ let(:field) { type_class.fields['testField'].to_graphql }
- subject(:resolved) { service.authorized_resolve.call(presented_type, {}, context) }
+ subject(:resolved) { service.authorized_resolve.call(type_instance, {}, context) }
context 'scalar types' do
shared_examples 'checking permissions on the presented object' do
@@ -48,7 +53,7 @@ RSpec.describe Gitlab::Graphql::Authorize::AuthorizeFieldService do
expect(resolved).to eq('Resolved value')
end
- it "returns nil if the value wasn't authorized" do
+ it 'returns nil if the value was not authorized' do
allow(Ability).to receive(:allowed?).and_return false
expect(resolved).to be_nil
@@ -56,28 +61,28 @@ RSpec.describe Gitlab::Graphql::Authorize::AuthorizeFieldService do
end
context 'when the field is a built-in scalar type' do
- let(:field) { type_with_field(GraphQL::STRING_TYPE, :read_field).fields['testField'].to_graphql }
+ let(:type_class) { type_with_field(GraphQL::STRING_TYPE, :read_field) }
let(:expected_permissions) { [:read_field] }
it_behaves_like 'checking permissions on the presented object'
end
context 'when the field is a list of scalar types' do
- let(:field) { type_with_field([GraphQL::STRING_TYPE], :read_field).fields['testField'].to_graphql }
+ let(:type_class) { type_with_field([GraphQL::STRING_TYPE], :read_field) }
let(:expected_permissions) { [:read_field] }
it_behaves_like 'checking permissions on the presented object'
end
context 'when the field is sub-classed scalar type' do
- let(:field) { type_with_field(Types::TimeType, :read_field).fields['testField'].to_graphql }
+ let(:type_class) { type_with_field(Types::TimeType, :read_field) }
let(:expected_permissions) { [:read_field] }
it_behaves_like 'checking permissions on the presented object'
end
context 'when the field is a list of sub-classed scalar types' do
- let(:field) { type_with_field([Types::TimeType], :read_field).fields['testField'].to_graphql }
+ let(:type_class) { type_with_field([Types::TimeType], :read_field) }
let(:expected_permissions) { [:read_field] }
it_behaves_like 'checking permissions on the presented object'
@@ -86,7 +91,7 @@ RSpec.describe Gitlab::Graphql::Authorize::AuthorizeFieldService do
context 'when the field is a connection' do
context 'when it resolves to nil' do
- let(:field) { type_with_field(Types::QueryType.connection_type, :read_field, nil).fields['testField'].to_graphql }
+ let(:type_class) { type_with_field(Types::QueryType.connection_type, :read_field, nil) }
it 'does not fail when authorizing' do
expect(resolved).to be_nil
@@ -97,7 +102,11 @@ RSpec.describe Gitlab::Graphql::Authorize::AuthorizeFieldService do
context 'when the field is a specific type' do
let(:custom_type) { type(:read_type) }
let(:object_in_field) { double('presented in field') }
- let(:field) { type_with_field(custom_type, :read_field, object_in_field).fields['testField'].to_graphql }
+
+ let(:type_class) { type_with_field(custom_type, :read_field, object_in_field) }
+ let(:type_instance) { type_class.authorized_new(object_in_field, context) }
+
+ subject(:resolved) { service.authorized_resolve.call(type_instance, {}, context) }
it 'checks both field & type permissions' do
spy_ability_check_for(:read_field, object_in_field, passed: true)
@@ -114,7 +123,7 @@ RSpec.describe Gitlab::Graphql::Authorize::AuthorizeFieldService do
end
context 'when the field is not nullable' do
- let(:field) { type_with_field(custom_type, [], object_in_field, null: false).fields['testField'].to_graphql }
+ let(:type_class) { type_with_field(custom_type, :read_field, object_in_field, null: false) }
it 'returns nil when viewing is not allowed' do
spy_ability_check_for(:read_type, object_in_field, passed: false)
@@ -127,7 +136,9 @@ RSpec.describe Gitlab::Graphql::Authorize::AuthorizeFieldService do
let(:object_1) { double('presented in field 1') }
let(:object_2) { double('presented in field 2') }
let(:presented_types) { [double(object: object_1), double(object: object_2)] }
- let(:field) { type_with_field([custom_type], :read_field, presented_types).fields['testField'].to_graphql }
+
+ let(:type_class) { type_with_field([custom_type], :read_field, presented_types) }
+ let(:type_instance) { type_class.authorized_new(presented_types, context) }
it 'checks all permissions' do
allow(Ability).to receive(:allowed?) { true }
diff --git a/spec/lib/gitlab/graphql/markdown_field/resolver_spec.rb b/spec/lib/gitlab/graphql/markdown_field/resolver_spec.rb
deleted file mode 100644
index af604e1c7d5..00000000000
--- a/spec/lib/gitlab/graphql/markdown_field/resolver_spec.rb
+++ /dev/null
@@ -1,33 +0,0 @@
-# frozen_string_literal: true
-require 'spec_helper'
-
-RSpec.describe Gitlab::Graphql::MarkdownField::Resolver do
- include Gitlab::Routing
- let(:resolver) { described_class.new(:note) }
-
- describe '#proc' do
- let(:project) { create(:project, :public) }
- let(:issue) { create(:issue, project: project) }
- let(:note) do
- create(:note,
- note: "Referencing #{issue.to_reference(full: true)}")
- end
-
- it 'renders markdown correctly' do
- expect(resolver.proc.call(note, {}, {})).to include(issue_path(issue))
- end
-
- context 'when the issue is not publicly accessible' do
- let(:project) { create(:project, :private) }
-
- it 'hides the references from users that are not allowed to see the reference' do
- expect(resolver.proc.call(note, {}, {})).not_to include(issue_path(issue))
- end
-
- it 'shows the reference to users that are allowed to see it' do
- expect(resolver.proc.call(note, {}, { current_user: project.owner }))
- .to include(issue_path(issue))
- end
- end
- end
-end
diff --git a/spec/lib/gitlab/graphql/markdown_field_spec.rb b/spec/lib/gitlab/graphql/markdown_field_spec.rb
index e3da925376e..82090f992eb 100644
--- a/spec/lib/gitlab/graphql/markdown_field_spec.rb
+++ b/spec/lib/gitlab/graphql/markdown_field_spec.rb
@@ -2,6 +2,8 @@
require 'spec_helper'
RSpec.describe Gitlab::Graphql::MarkdownField do
+ include Gitlab::Routing
+
describe '.markdown_field' do
it 'creates the field with some default attributes' do
field = class_with_markdown_field(:test_html, null: true, method: :hello).fields['testHtml']
@@ -13,7 +15,7 @@ RSpec.describe Gitlab::Graphql::MarkdownField do
end
context 'developer warnings' do
- let(:expected_error) { /Only `method` is allowed to specify the markdown field/ }
+ let_it_be(:expected_error) { /Only `method` is allowed to specify the markdown field/ }
it 'raises when passing a resolver' do
expect { class_with_markdown_field(:test_html, null: true, resolver: 'not really') }
@@ -27,30 +29,61 @@ RSpec.describe Gitlab::Graphql::MarkdownField do
end
context 'resolving markdown' do
- let(:note) { build(:note, note: '# Markdown!') }
- let(:thing_with_markdown) { double('markdown thing', object: note) }
- let(:expected_markdown) { '<h1 data-sourcepos="1:1-1:11" dir="auto">Markdown!</h1>' }
- let(:query_type) { GraphQL::ObjectType.new }
- let(:schema) { GraphQL::Schema.define(query: query_type, mutation: nil)}
- let(:context) { GraphQL::Query::Context.new(query: OpenStruct.new(schema: schema), values: nil, object: nil) }
+ let_it_be(:note) { build(:note, note: '# Markdown!') }
+ let_it_be(:expected_markdown) { '<h1 data-sourcepos="1:1-1:11" dir="auto">Markdown!</h1>' }
+ let_it_be(:query_type) { GraphQL::ObjectType.new }
+ let_it_be(:schema) { GraphQL::Schema.define(query: query_type, mutation: nil)}
+ let_it_be(:query) { GraphQL::Query.new(schema, document: nil, context: {}, variables: {}) }
+ let_it_be(:context) { GraphQL::Query::Context.new(query: query, values: {}, object: nil) }
+
+ let(:type_class) { class_with_markdown_field(:note_html, null: false) }
+ let(:type_instance) { type_class.authorized_new(note, context) }
+ let(:field) { type_class.fields['noteHtml'] }
it 'renders markdown from the same property as the field name without the `_html` suffix' do
- field = class_with_markdown_field(:note_html, null: false).fields['noteHtml']
+ expect(field.to_graphql.resolve(type_instance, {}, context)).to eq(expected_markdown)
+ end
+
+ context 'when a `method` argument is passed' do
+ let(:type_class) { class_with_markdown_field(:test_html, null: false, method: :note) }
+ let(:field) { type_class.fields['testHtml'] }
- expect(field.to_graphql.resolve(thing_with_markdown, {}, context)).to eq(expected_markdown)
+ it 'renders markdown from a specific property' do
+ expect(field.to_graphql.resolve(type_instance, {}, context)).to eq(expected_markdown)
+ end
end
- it 'renders markdown from a specific property when a `method` argument is passed' do
- field = class_with_markdown_field(:test_html, null: false, method: :note).fields['testHtml']
+ describe 'basic verification that references work' do
+ let_it_be(:project) { create(:project, :public) }
+ let(:issue) { create(:issue, project: project) }
+ let(:note) { build(:note, note: "Referencing #{issue.to_reference(full: true)}") }
+
+ it 'renders markdown correctly' do
+ expect(field.to_graphql.resolve(type_instance, {}, context)).to include(issue_path(issue))
+ end
+
+ context 'when the issue is not publicly accessible' do
+ let_it_be(:project) { create(:project, :private) }
+
+ it 'hides the references from users that are not allowed to see the reference' do
+ expect(field.to_graphql.resolve(type_instance, {}, context)).not_to include(issue_path(issue))
+ end
+
+ it 'shows the reference to users that are allowed to see it' do
+ context = GraphQL::Query::Context.new(query: query, values: { current_user: project.owner }, object: nil)
+ type_instance = type_class.authorized_new(note, context)
- expect(field.to_graphql.resolve(thing_with_markdown, {}, context)).to eq(expected_markdown)
+ expect(field.to_graphql.resolve(type_instance, {}, context)).to include(issue_path(issue))
+ end
+ end
end
end
end
def class_with_markdown_field(name, **args)
- Class.new(GraphQL::Schema::Object) do
+ Class.new(Types::BaseObject) do
prepend Gitlab::Graphql::MarkdownField
+ graphql_name 'MarkdownFieldTest'
markdown_field name, **args
end
diff --git a/spec/lib/gitlab/graphql/pagination/keyset/last_items_spec.rb b/spec/lib/gitlab/graphql/pagination/keyset/last_items_spec.rb
new file mode 100644
index 00000000000..b45bb8b79d9
--- /dev/null
+++ b/spec/lib/gitlab/graphql/pagination/keyset/last_items_spec.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Graphql::Pagination::Keyset::LastItems do
+ let_it_be(:merge_request) { create(:merge_request) }
+ let(:scope) { MergeRequest.order_merged_at_asc.with_order_id_desc }
+
+ subject { described_class.take_items(*args) }
+
+ context 'when the `count` parameter is nil' do
+ let(:args) { [scope, nil] }
+
+ it 'returns a single record' do
+ expect(subject).to eq(merge_request)
+ end
+ end
+
+ context 'when the `count` parameter is given' do
+ let(:args) { [scope, 1] }
+
+ it 'returns an array' do
+ expect(subject).to eq([merge_request])
+ end
+ end
+end
diff --git a/spec/lib/gitlab/graphql/pagination/keyset/order_info_spec.rb b/spec/lib/gitlab/graphql/pagination/keyset/order_info_spec.rb
index 444c10074a0..eb28e6c8c0a 100644
--- a/spec/lib/gitlab/graphql/pagination/keyset/order_info_spec.rb
+++ b/spec/lib/gitlab/graphql/pagination/keyset/order_info_spec.rb
@@ -63,6 +63,29 @@ RSpec.describe Gitlab::Graphql::Pagination::Keyset::OrderInfo do
expect(order_list.first.sort_direction).to eq :desc
end
end
+
+ context 'when ordering by CASE', :aggregate_failuers do
+ let(:relation) { Project.order(Arel::Nodes::Case.new(Project.arel_table[:pending_delete]).when(true).then(100).else(1000).asc) }
+
+ it 'assigns the right attribute name, named function, and direction' do
+ expect(order_list.count).to eq 1
+ expect(order_list.first.attribute_name).to eq 'case_order_value'
+ expect(order_list.first.named_function).to be_kind_of(Arel::Nodes::Case)
+ expect(order_list.first.sort_direction).to eq :asc
+ end
+ end
+
+ context 'when ordering by ARRAY_POSITION', :aggregate_failuers do
+ let(:array_position) { Arel::Nodes::NamedFunction.new('ARRAY_POSITION', [Arel.sql("ARRAY[1,0]::smallint[]"), Project.arel_table[:auto_cancel_pending_pipelines]]) }
+ let(:relation) { Project.order(array_position.asc) }
+
+ it 'assigns the right attribute name, named function, and direction' do
+ expect(order_list.count).to eq 1
+ expect(order_list.first.attribute_name).to eq 'array_position'
+ expect(order_list.first.named_function).to be_kind_of(Arel::Nodes::NamedFunction)
+ expect(order_list.first.sort_direction).to eq :asc
+ end
+ end
end
describe '#validate_ordering' do
diff --git a/spec/lib/gitlab/graphql/pagination/keyset/query_builder_spec.rb b/spec/lib/gitlab/graphql/pagination/keyset/query_builder_spec.rb
index c7e7db4d535..fa631aa5666 100644
--- a/spec/lib/gitlab/graphql/pagination/keyset/query_builder_spec.rb
+++ b/spec/lib/gitlab/graphql/pagination/keyset/query_builder_spec.rb
@@ -136,11 +136,12 @@ RSpec.describe Gitlab::Graphql::Pagination::Keyset::QueryBuilder do
let(:relation) { Project.sorted_by_similarity_desc('test', include_in_select: true) }
let(:arel_table) { Project.arel_table }
let(:decoded_cursor) { { 'similarity' => 0.5, 'id' => 100 } }
+ let(:similarity_function_call) { Gitlab::Database::SimilarityScore::SIMILARITY_FUNCTION_CALL_WITH_ANNOTATION }
let(:similarity_sql) do
[
- '(SIMILARITY(COALESCE("projects"."path", \'\'), \'test\') * CAST(\'1\' AS numeric))',
- '(SIMILARITY(COALESCE("projects"."name", \'\'), \'test\') * CAST(\'0.7\' AS numeric))',
- '(SIMILARITY(COALESCE("projects"."description", \'\'), \'test\') * CAST(\'0.2\' AS numeric))'
+ "(#{similarity_function_call}(COALESCE(\"projects\".\"path\", ''), 'test') * CAST('1' AS numeric))",
+ "(#{similarity_function_call}(COALESCE(\"projects\".\"name\", ''), 'test') * CAST('0.7' AS numeric))",
+ "(#{similarity_function_call}(COALESCE(\"projects\".\"description\", ''), 'test') * CAST('0.2' AS numeric))"
].join(' + ')
end
diff --git a/spec/lib/gitlab/graphql/query_analyzers/logger_analyzer_spec.rb b/spec/lib/gitlab/graphql/query_analyzers/logger_analyzer_spec.rb
index 89d2ab8bb87..c8432513185 100644
--- a/spec/lib/gitlab/graphql/query_analyzers/logger_analyzer_spec.rb
+++ b/spec/lib/gitlab/graphql/query_analyzers/logger_analyzer_spec.rb
@@ -26,7 +26,7 @@ RSpec.describe Gitlab::Graphql::QueryAnalyzers::LoggerAnalyzer do
end
it 'returns a duration in seconds' do
- allow(GraphQL::Analysis).to receive(:analyze_query).and_return([4, 2])
+ allow(GraphQL::Analysis).to receive(:analyze_query).and_return([4, 2, [[], []]])
allow(Gitlab::Metrics::System).to receive(:monotonic_time).and_return(monotonic_time_before, monotonic_time_after)
allow(Gitlab::GraphqlLogger).to receive(:info)