diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-06-18 11:18:50 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-06-18 11:18:50 +0000 |
commit | 8c7f4e9d5f36cff46365a7f8c4b9c21578c1e781 (patch) | |
tree | a77e7fe7a93de11213032ed4ab1f33a3db51b738 /spec/graphql/resolvers/concerns/looks_ahead_spec.rb | |
parent | 00b35af3db1abfe813a778f643dad221aad51fca (diff) | |
download | gitlab-ce-8c7f4e9d5f36cff46365a7f8c4b9c21578c1e781.tar.gz |
Add latest changes from gitlab-org/gitlab@13-1-stable-ee
Diffstat (limited to 'spec/graphql/resolvers/concerns/looks_ahead_spec.rb')
-rw-r--r-- | spec/graphql/resolvers/concerns/looks_ahead_spec.rb | 177 |
1 files changed, 177 insertions, 0 deletions
diff --git a/spec/graphql/resolvers/concerns/looks_ahead_spec.rb b/spec/graphql/resolvers/concerns/looks_ahead_spec.rb new file mode 100644 index 00000000000..8b83f887846 --- /dev/null +++ b/spec/graphql/resolvers/concerns/looks_ahead_spec.rb @@ -0,0 +1,177 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe LooksAhead do + include GraphqlHelpers + + let_it_be(:the_user) { create(:user) } + let_it_be(:label_a) { create(:label) } + let_it_be(:label_b) { create(:label) } + let_it_be(:issue_a) { create(:issue, author: the_user, labels: [label_a, label_b]) } + let_it_be(:issue_b) { create(:issue, author: the_user, labels: [label_a]) } + let_it_be(:issue_c) { create(:issue, author: the_user, labels: [label_b]) } + + # Simplified schema to test lookahead + let_it_be(:schema) do + issues_resolver = Class.new(Resolvers::BaseResolver) do + include LooksAhead + + def resolve_with_lookahead(**args) + apply_lookahead(object.issues) + end + + def preloads + { labels: [:labels] } + end + end + + label = Class.new(GraphQL::Schema::Object) do + graphql_name 'Label' + field :id, Integer, null: false + end + issue = Class.new(GraphQL::Schema::Object) do + graphql_name 'Issue' + field :title, String, null: true + field :labels, label.connection_type, null: true + end + user = Class.new(GraphQL::Schema::Object) do + graphql_name 'User' + field :name, String, null: true + field :issues, issue.connection_type, + null: true + field :issues_with_lookahead, issue.connection_type, + extras: [:lookahead], + resolver: issues_resolver, + null: true + end + + Class.new(GraphQL::Schema) do + query(Class.new(GraphQL::Schema::Object) do + graphql_name 'Query' + field :find_user, user, null: true do + argument :username, String, required: true + end + + def find_user(username:) + context[:user_db].find { |u| u.username == username } + end + end) + end + end + + def query(doc = document) + GraphQL::Query.new(schema, + document: doc, + context: { user_db: [the_user] }, + variables: { username: the_user.username }) + end + + let(:document) do + GraphQL.parse <<-GRAPHQL + query($username: String!){ + findUser(username: $username) { + name + issues { + nodes { + title + labels { nodes { id } } + } + } + issuesWithLookahead { + nodes { + title + labels { nodes { id } } + } + } + } + } + GRAPHQL + end + + def run_query(gql_query) + query(GraphQL.parse(gql_query)).result + end + + shared_examples 'a working query on the test schema' do + it 'has a good test setup', :aggregate_failures do + expected_label_ids = [label_a, label_b].cycle.take(4).map(&:id) + issue_titles = [issue_a, issue_b, issue_c].map(&:title) + + res = query.result + + expect(res['errors']).to be_blank + expect(res.dig('data', 'findUser', 'name')).to eq(the_user.name) + %w(issues issuesWithLookahead).each do |field| + expect(all_issue_titles(res, field)).to match_array(issue_titles) + expect(all_label_ids(res, field)).to match_array(expected_label_ids) + end + end + end + + it_behaves_like 'a working query on the test schema' + + it 'preloads labels on issues' do + expect(the_user.issues).to receive(:preload).with(:labels) + + query.result + end + + context 'the feature flag is off' do + before do + stub_feature_flags(described_class::FEATURE_FLAG => false) + end + + it_behaves_like 'a working query on the test schema' + + it 'does not preload labels on issues' do + expect(the_user.issues).not_to receive(:preload).with(:labels) + + query.result + end + end + + it 'issues fewer queries than the naive approach' do + the_user.reload # ensure no attributes are loaded before we begin + naive = <<-GQL + query($username: String!){ + findUser(username: $username) { + name + issues { + nodes { + labels { nodes { id } } + } + } + } + } + GQL + with_lookahead = <<-GQL + query($username: String!){ + findUser(username: $username) { + name + issuesWithLookahead { + nodes { + labels { nodes { id } } + } + } + } + } + GQL + + expect { run_query(with_lookahead) }.to issue_fewer_queries_than { run_query(naive) } + end + + private + + def all_label_ids(result, field_name) + result.dig('data', 'findUser', field_name, 'nodes').flat_map do |node| + node.dig('labels', 'nodes').map { |n| n['id'] } + end + end + + def all_issue_titles(result, field_name) + result.dig('data', 'findUser', field_name, 'nodes').map do |node| + node['title'] + end + end +end |