diff options
Diffstat (limited to 'spec/requests/api/graphql/project')
8 files changed, 273 insertions, 39 deletions
diff --git a/spec/requests/api/graphql/project/container_repositories_spec.rb b/spec/requests/api/graphql/project/container_repositories_spec.rb index 6b1c8689515..2087d8c2cc3 100644 --- a/spec/requests/api/graphql/project/container_repositories_spec.rb +++ b/spec/requests/api/graphql/project/container_repositories_spec.rb @@ -156,4 +156,51 @@ RSpec.describe 'getting container repositories in a project' do expect(container_repositories_count_response).to eq(container_repositories.size) end + + describe 'sorting and pagination' do + let_it_be(:data_path) { [:project, :container_repositories] } + let_it_be(:sort_project) { create(:project, :public) } + let_it_be(:current_user) { create(:user) } + let_it_be(:container_repository1) { create(:container_repository, name: 'b', project: sort_project) } + let_it_be(:container_repository2) { create(:container_repository, name: 'a', project: sort_project) } + let_it_be(:container_repository3) { create(:container_repository, name: 'd', project: sort_project) } + let_it_be(:container_repository4) { create(:container_repository, name: 'c', project: sort_project) } + let_it_be(:container_repository5) { create(:container_repository, name: 'e', project: sort_project) } + + before do + stub_container_registry_tags(repository: container_repository1.path, tags: %w(tag1 tag1 tag3), with_manifest: false) + stub_container_registry_tags(repository: container_repository2.path, tags: %w(tag4 tag5 tag6), with_manifest: false) + stub_container_registry_tags(repository: container_repository3.path, tags: %w(tag7 tag8), with_manifest: false) + stub_container_registry_tags(repository: container_repository4.path, tags: %w(tag9), with_manifest: false) + stub_container_registry_tags(repository: container_repository5.path, tags: %w(tag10 tag11), with_manifest: false) + end + + def pagination_query(params) + graphql_query_for(:project, { full_path: sort_project.full_path }, + query_nodes(:container_repositories, :name, include_pagination_info: true, args: params) + ) + end + + def pagination_results_data(data) + data.map { |container_repository| container_repository.dig('name') } + end + + context 'when sorting by name' do + context 'when ascending' do + it_behaves_like 'sorted paginated query' do + let(:sort_param) { :NAME_ASC } + let(:first_param) { 2 } + let(:expected_results) { [container_repository2.name, container_repository1.name, container_repository4.name, container_repository3.name, container_repository5.name] } + end + end + + context 'when descending' do + it_behaves_like 'sorted paginated query' do + let(:sort_param) { :NAME_DESC } + let(:first_param) { 2 } + let(:expected_results) { [container_repository5.name, container_repository3.name, container_repository4.name, container_repository1.name, container_repository2.name] } + end + end + end + end end diff --git a/spec/requests/api/graphql/project/issue/designs/notes_spec.rb b/spec/requests/api/graphql/project/issue/designs/notes_spec.rb index a671ddc7ab1..7148750b6cb 100644 --- a/spec/requests/api/graphql/project/issue/designs/notes_spec.rb +++ b/spec/requests/api/graphql/project/issue/designs/notes_spec.rb @@ -22,6 +22,23 @@ RSpec.describe 'Getting designs related to an issue' do end end + it_behaves_like 'a noteable graphql type we can query' do + let(:noteable) { design } + let(:note_factory) { :diff_note_on_design } + let(:discussion_factory) { :diff_note_on_design } + let(:path_to_noteable) { [:issue, :design_collection, :designs, :nodes, 0] } + + before do + project.add_developer(current_user) + end + + def query(fields) + graphql_query_for(:issue, { id: global_id_of(issue) }, <<~FIELDS) + designCollection { designs { nodes { #{fields} } } } + FIELDS + end + end + it 'is not too deep for anonymous users' do note_fields = <<~FIELDS id @@ -37,7 +54,7 @@ RSpec.describe 'Getting designs related to an issue' do expect(note_data['id']).to eq(note.to_global_id.to_s) end - def query(note_fields = all_graphql_fields_for(Note)) + def query(note_fields = all_graphql_fields_for(Note, max_depth: 1)) design_node = <<~NODE designs { nodes { diff --git a/spec/requests/api/graphql/project/merge_request/pipelines_spec.rb b/spec/requests/api/graphql/project/merge_request/pipelines_spec.rb index ac0b18a37d6..70c5bda35e1 100644 --- a/spec/requests/api/graphql/project/merge_request/pipelines_spec.rb +++ b/spec/requests/api/graphql/project/merge_request/pipelines_spec.rb @@ -8,9 +8,11 @@ RSpec.describe 'Query.project.mergeRequests.pipelines' do let_it_be(:project) { create(:project, :public, :repository) } let_it_be(:author) { create(:user) } let_it_be(:merge_requests) do - %i[with_diffs with_image_diffs conflict].map do |trait| - create(:merge_request, trait, author: author, source_project: project) - end + [ + create(:merge_request, author: author, source_project: project), + create(:merge_request, :with_image_diffs, author: author, source_project: project), + create(:merge_request, :conflict, author: author, source_project: project) + ] end describe '.count' do diff --git a/spec/requests/api/graphql/project/merge_request_spec.rb b/spec/requests/api/graphql/project/merge_request_spec.rb index e1b867ad097..a4e8d0bc35e 100644 --- a/spec/requests/api/graphql/project/merge_request_spec.rb +++ b/spec/requests/api/graphql/project/merge_request_spec.rb @@ -66,14 +66,6 @@ RSpec.describe 'getting merge request information nested in a project' do expect(graphql_data_at(:project, :merge_request, :reviewers, :nodes)).to match_array(expected) expect(graphql_data_at(:project, :merge_request, :participants, :nodes)).to include(*expected) end - - it 'suppresses reviewers if reviewers are not allowed' do - stub_feature_flags(merge_request_reviewers: false) - - post_graphql(query, current_user: current_user) - - expect(graphql_data_at(:project, :merge_request, :reviewers)).to be_nil - end end it 'includes diff stats' do diff --git a/spec/requests/api/graphql/project/merge_requests_spec.rb b/spec/requests/api/graphql/project/merge_requests_spec.rb index c85cb8b2ffe..d684be91dc9 100644 --- a/spec/requests/api/graphql/project/merge_requests_spec.rb +++ b/spec/requests/api/graphql/project/merge_requests_spec.rb @@ -196,17 +196,18 @@ RSpec.describe 'getting merge request listings nested in a project' do end context 'when requesting `commit_count`' do - let(:requested_fields) { [:commit_count] } + let(:merge_request_with_commits) { create(:merge_request, source_project: project) } + let(:search_params) { { iids: [merge_request_a.iid.to_s, merge_request_with_commits.iid.to_s] } } + let(:requested_fields) { [:iid, :commit_count] } it 'exposes `commit_count`' do - merge_request_a.metrics.update!(commits_count: 5) - execute_query - expect(results).to include(a_hash_including('commitCount' => 5)) + expect(results).to match_array([ + { "iid" => merge_request_a.iid.to_s, "commitCount" => 0 }, + { "iid" => merge_request_with_commits.iid.to_s, "commitCount" => 29 } + ]) end - - include_examples 'N+1 query check' end context 'when requesting `merged_at`' do @@ -264,18 +265,6 @@ RSpec.describe 'getting merge request listings nested in a project' do }) end - context 'the feature flag is disabled' do - before do - stub_feature_flags(merge_request_reviewers: false) - end - - it 'does not return reviewers' do - execute_query - - expect(results).to all(match a_hash_including('reviewers' => be_nil)) - end - end - include_examples 'N+1 query check' end end @@ -396,4 +385,87 @@ RSpec.describe 'getting merge request listings nested in a project' do end end end + + context 'when only the count is requested' do + context 'when merged at filter is present' do + let_it_be(:merge_request) do + create(:merge_request, :unique_branches, source_project: project).tap do |mr| + mr.metrics.update!(merged_at: Time.new(2020, 1, 3)) + end + end + + let(:query) do + # Note: __typename meta field is always requested by the FE + graphql_query_for(:project, { full_path: project.full_path }, + <<~QUERY + mergeRequests(mergedAfter: "2020-01-01", mergedBefore: "2020-01-05", first: 0, sourceBranches: null, labels: null) { + count + __typename + } + QUERY + ) + end + + shared_examples 'count examples' do + it 'returns the correct count' do + post_graphql(query, current_user: current_user) + + count = graphql_data.dig('project', 'mergeRequests', 'count') + expect(count).to eq(1) + end + end + + context 'when "optimized_merge_request_count_with_merged_at_filter" feature flag is enabled' do + before do + stub_feature_flags(optimized_merge_request_count_with_merged_at_filter: true) + end + + it 'does not query the merge requests table for the count' do + query_recorder = ActiveRecord::QueryRecorder.new { post_graphql(query, current_user: current_user) } + + queries = query_recorder.data.each_value.first[:occurrences] + expect(queries).not_to include(match(/SELECT COUNT\(\*\) FROM "merge_requests"/)) + expect(queries).to include(match(/SELECT COUNT\(\*\) FROM "merge_request_metrics"/)) + end + + context 'when total_time_to_merge and count is queried' do + let(:query) do + graphql_query_for(:project, { full_path: project.full_path }, + <<~QUERY + mergeRequests(mergedAfter: "2020-01-01", mergedBefore: "2020-01-05", first: 0) { + totalTimeToMerge + count + } + QUERY + ) + end + + it 'does not query the merge requests table for the total_time_to_merge' do + query_recorder = ActiveRecord::QueryRecorder.new { post_graphql(query, current_user: current_user) } + + queries = query_recorder.data.each_value.first[:occurrences] + expect(queries).to include(match(/SELECT.+SUM.+FROM "merge_request_metrics" WHERE/)) + end + end + + it_behaves_like 'count examples' + + context 'when "optimized_merge_request_count_with_merged_at_filter" feature flag is disabled' do + before do + stub_feature_flags(optimized_merge_request_count_with_merged_at_filter: false) + end + + it 'queries the merge requests table for the count' do + query_recorder = ActiveRecord::QueryRecorder.new { post_graphql(query, current_user: current_user) } + + queries = query_recorder.data.each_value.first[:occurrences] + expect(queries).to include(match(/SELECT COUNT\(\*\) FROM "merge_requests"/)) + expect(queries).not_to include(match(/SELECT COUNT\(\*\) FROM "merge_request_metrics"/)) + end + + it_behaves_like 'count examples' + end + end + end + end end diff --git a/spec/requests/api/graphql/project/packages_spec.rb b/spec/requests/api/graphql/project/packages_spec.rb index 5df98ed1e6b..b20c96d54c8 100644 --- a/spec/requests/api/graphql/project/packages_spec.rb +++ b/spec/requests/api/graphql/project/packages_spec.rb @@ -5,16 +5,27 @@ require 'spec_helper' RSpec.describe 'getting a package list for a project' do include GraphqlHelpers - let_it_be(:project) { create(:project) } + let_it_be(:project) { create(:project, :repository) } let_it_be(:current_user) { create(:user) } + let_it_be(:package) { create(:package, project: project) } - let(:packages_data) { graphql_data['project']['packages']['edges'] } + let_it_be(:maven_package) { create(:maven_package, project: project) } + let_it_be(:debian_package) { create(:debian_package, project: project) } + let_it_be(:composer_package) { create(:composer_package, project: project) } + let_it_be(:composer_metadatum) do + create(:composer_metadatum, package: composer_package, + target_sha: 'afdeh', + composer_json: { name: 'x', type: 'y', license: 'z', version: 1 }) + end + + let(:package_names) { graphql_data_at(:project, :packages, :edges, :node, :name) } let(:fields) do <<~QUERY edges { node { - #{all_graphql_fields_for('packages'.classify)} + #{all_graphql_fields_for('packages'.classify, excluded: ['project'])} + metadata { #{query_graphql_fragment('ComposerMetadata')} } } } QUERY @@ -37,7 +48,17 @@ RSpec.describe 'getting a package list for a project' do it_behaves_like 'a working graphql query' it 'returns packages successfully' do - expect(packages_data[0]['node']['name']).to eq package.name + expect(package_names).to contain_exactly( + package.name, + maven_package.name, + debian_package.name, + composer_package.name + ) + end + + it 'deals with metadata' do + target_shas = graphql_data_at(:project, :packages, :edges, :node, :metadata, :target_sha) + expect(target_shas).to contain_exactly(composer_metadatum.target_sha) end end @@ -53,7 +74,7 @@ RSpec.describe 'getting a package list for a project' do end end - context 'when the user is not autenthicated' do + context 'when the user is not authenticated' do before do post_graphql(query) end diff --git a/spec/requests/api/graphql/project/release_spec.rb b/spec/requests/api/graphql/project/release_spec.rb index ccc2825da25..72197f00df4 100644 --- a/spec/requests/api/graphql/project/release_spec.rb +++ b/spec/requests/api/graphql/project/release_spec.rb @@ -283,7 +283,7 @@ RSpec.describe 'Query.project(fullPath).release(tagName)' do let_it_be(:project) { create(:project, :repository, :private) } let_it_be(:milestone_1) { create(:milestone, project: project) } let_it_be(:milestone_2) { create(:milestone, project: project) } - let_it_be(:release) { create(:release, :with_evidence, project: project, milestones: [milestone_1, milestone_2], released_at: released_at) } + let_it_be(:release, reload: true) { create(:release, :with_evidence, project: project, milestones: [milestone_1, milestone_2], released_at: released_at) } let_it_be(:release_link_1) { create(:release_link, release: release) } let_it_be(:release_link_2) { create(:release_link, release: release, filepath: link_filepath) } @@ -324,7 +324,7 @@ RSpec.describe 'Query.project(fullPath).release(tagName)' do let_it_be(:project) { create(:project, :repository, :public) } let_it_be(:milestone_1) { create(:milestone, project: project) } let_it_be(:milestone_2) { create(:milestone, project: project) } - let_it_be(:release) { create(:release, :with_evidence, project: project, milestones: [milestone_1, milestone_2], released_at: released_at) } + let_it_be(:release, reload: true) { create(:release, :with_evidence, project: project, milestones: [milestone_1, milestone_2], released_at: released_at) } let_it_be(:release_link_1) { create(:release_link, release: release) } let_it_be(:release_link_2) { create(:release_link, release: release, filepath: link_filepath) } @@ -435,13 +435,13 @@ RSpec.describe 'Query.project(fullPath).release(tagName)' do let_it_be_with_reload(:release) { create(:release, project: project) } let(:release_fields) do - query_graphql_field(%{ + %{ milestones { nodes { title } } - }) + } end let(:actual_milestone_title_order) do diff --git a/spec/requests/api/graphql/project/terraform/state_spec.rb b/spec/requests/api/graphql/project/terraform/state_spec.rb new file mode 100644 index 00000000000..9f1d9ab204a --- /dev/null +++ b/spec/requests/api/graphql/project/terraform/state_spec.rb @@ -0,0 +1,83 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'query a single terraform state' do + include GraphqlHelpers + include ::API::Helpers::RelatedResourcesHelpers + + let_it_be(:terraform_state) { create(:terraform_state, :with_version, :locked) } + + let(:latest_version) { terraform_state.latest_version } + let(:project) { terraform_state.project } + let(:current_user) { project.creator } + let(:data) { graphql_data.dig('project', 'terraformState') } + + let(:query) do + graphql_query_for( + :project, + { fullPath: project.full_path }, + query_graphql_field( + :terraformState, + { name: terraform_state.name }, + %{ + id + name + lockedAt + createdAt + updatedAt + + latestVersion { + id + serial + createdAt + updatedAt + + createdByUser { + id + } + + job { + name + } + } + + lockedByUser { + id + } + } + ) + ) + end + + before do + post_graphql(query, current_user: current_user) + end + + it_behaves_like 'a working graphql query' + + it 'returns terraform state data' do + expect(data).to match(a_hash_including({ + 'id' => global_id_of(terraform_state), + 'name' => terraform_state.name, + 'lockedAt' => terraform_state.locked_at.iso8601, + 'createdAt' => terraform_state.created_at.iso8601, + 'updatedAt' => terraform_state.updated_at.iso8601, + 'lockedByUser' => { 'id' => global_id_of(terraform_state.locked_by_user) }, + 'latestVersion' => { + 'id' => eq(global_id_of(latest_version)), + 'serial' => eq(latest_version.version), + 'createdAt' => eq(latest_version.created_at.iso8601), + 'updatedAt' => eq(latest_version.updated_at.iso8601), + 'createdByUser' => { 'id' => eq(global_id_of(latest_version.created_by_user)) }, + 'job' => { 'name' => eq(latest_version.build.name) } + } + })) + end + + context 'unauthorized users' do + let(:current_user) { nil } + + it { expect(data).to be_nil } + end +end |