612 lines
16 KiB
Ruby
612 lines
16 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require 'spec_helper'
|
|
|
|
RSpec.describe 'Query.project(fullPath).release(tagName)', feature_category: :release_orchestration do
|
|
include GraphqlHelpers
|
|
include Presentable
|
|
|
|
let_it_be(:developer) { create(:user) }
|
|
let_it_be(:guest) { create(:user) }
|
|
let_it_be(:reporter) { create(:user) }
|
|
let_it_be(:stranger) { create(:user) }
|
|
let_it_be(:link_filepath) { '/direct/asset/link/path' }
|
|
let_it_be(:released_at) { Time.now - 1.day }
|
|
|
|
let(:base_url_params) { { scope: 'all', release_tag: release.tag } }
|
|
let(:opened_url_params) { { state: 'opened', **base_url_params } }
|
|
let(:merged_url_params) { { state: 'merged', **base_url_params } }
|
|
let(:closed_url_params) { { state: 'closed', **base_url_params } }
|
|
|
|
let(:post_query) { post_graphql(query, current_user: current_user) }
|
|
let(:path_prefix) { %w[project release] }
|
|
let(:data) { graphql_data.dig(*path) }
|
|
|
|
def query(rq = release_fields)
|
|
graphql_query_for(:project, { fullPath: project.full_path },
|
|
query_graphql_field(:release, { tagName: release.tag }, rq))
|
|
end
|
|
|
|
before do
|
|
stub_default_url_options(host: 'www.example.com')
|
|
end
|
|
|
|
shared_examples 'full access to the release field' do
|
|
describe 'scalar fields' do
|
|
let(:path) { path_prefix }
|
|
|
|
let(:release_fields) do
|
|
%{
|
|
tagName
|
|
tagPath
|
|
description
|
|
descriptionHtml
|
|
name
|
|
createdAt
|
|
releasedAt
|
|
upcomingRelease
|
|
}
|
|
end
|
|
|
|
before do
|
|
post_query
|
|
end
|
|
|
|
it 'finds all release data' do
|
|
expect(data).to eq({
|
|
'tagName' => release.tag,
|
|
'tagPath' => project_tag_path(project, release.tag),
|
|
'description' => release.description,
|
|
'descriptionHtml' => release.description_html,
|
|
'name' => release.name,
|
|
'createdAt' => release.created_at.iso8601,
|
|
'releasedAt' => release.released_at.iso8601,
|
|
'upcomingRelease' => false
|
|
})
|
|
end
|
|
end
|
|
|
|
describe 'milestones' do
|
|
let(:path) { path_prefix + %w[milestones nodes] }
|
|
|
|
let(:release_fields) do
|
|
query_graphql_field(:milestones, nil, 'nodes { id title }')
|
|
end
|
|
|
|
it 'finds all milestones associated to a release' do
|
|
post_query
|
|
|
|
expected = release.milestones.order_by_dates_and_title.map do |milestone|
|
|
a_graphql_entity_for(milestone, :title)
|
|
end
|
|
|
|
expect(data).to match(expected)
|
|
end
|
|
end
|
|
|
|
describe 'author' do
|
|
let(:path) { path_prefix + %w[author] }
|
|
|
|
let(:release_fields) do
|
|
query_graphql_field(:author, nil, 'id username')
|
|
end
|
|
|
|
it 'finds the author of the release' do
|
|
post_query
|
|
|
|
expect(data).to match a_graphql_entity_for(release.author, :username)
|
|
end
|
|
end
|
|
|
|
describe 'commit' do
|
|
let(:path) { path_prefix + %w[commit] }
|
|
|
|
let(:release_fields) do
|
|
query_graphql_field(:commit, nil, 'sha')
|
|
end
|
|
|
|
it 'finds the commit associated with the release' do
|
|
post_query
|
|
|
|
expect(data).to eq('sha' => release.commit.sha)
|
|
end
|
|
end
|
|
|
|
describe 'assets' do
|
|
describe 'count' do
|
|
let(:path) { path_prefix + %w[assets] }
|
|
|
|
let(:release_fields) do
|
|
query_graphql_field(:assets, nil, 'count')
|
|
end
|
|
|
|
it 'returns the number of assets associated to the release' do
|
|
post_query
|
|
|
|
expect(data).to eq('count' => release.sources.size + release.links.size)
|
|
end
|
|
end
|
|
|
|
describe 'links' do
|
|
let(:path) { path_prefix + %w[assets links nodes] }
|
|
|
|
let(:release_fields) do
|
|
query_graphql_field(:assets, nil,
|
|
query_graphql_field(:links, nil, 'nodes { id name url, directAssetUrl }'))
|
|
end
|
|
|
|
it 'finds all release links' do
|
|
post_query
|
|
|
|
expected = release.links.map do |link|
|
|
a_graphql_entity_for(
|
|
link, :name, :url,
|
|
'directAssetUrl' => link.filepath ? Gitlab::Routing.url_helpers.project_release_url(project, release) << "/downloads#{link.filepath}" : link.url
|
|
)
|
|
end
|
|
|
|
expect(data).to match_array(expected)
|
|
end
|
|
end
|
|
|
|
describe 'sources' do
|
|
let(:path) { path_prefix + %w[assets sources nodes] }
|
|
|
|
let(:release_fields) do
|
|
query_graphql_field(:assets, nil,
|
|
query_graphql_field(:sources, nil, 'nodes { format url }'))
|
|
end
|
|
|
|
it 'finds all release sources' do
|
|
post_query
|
|
|
|
expected = release.sources.map do |source|
|
|
{
|
|
'format' => source.format,
|
|
'url' => source.url
|
|
}
|
|
end
|
|
|
|
expect(data).to match_array(expected)
|
|
end
|
|
end
|
|
end
|
|
|
|
describe 'links' do
|
|
let(:path) { path_prefix + %w[links] }
|
|
|
|
let(:release_fields) do
|
|
query_graphql_field(:links, nil, %{
|
|
selfUrl
|
|
openedMergeRequestsUrl
|
|
mergedMergeRequestsUrl
|
|
closedMergeRequestsUrl
|
|
openedIssuesUrl
|
|
closedIssuesUrl
|
|
})
|
|
end
|
|
|
|
it 'finds all release links' do
|
|
post_query
|
|
|
|
expect(data).to eq(
|
|
'selfUrl' => project_release_url(project, release),
|
|
'openedMergeRequestsUrl' => project_merge_requests_url(project, opened_url_params),
|
|
'mergedMergeRequestsUrl' => project_merge_requests_url(project, merged_url_params),
|
|
'closedMergeRequestsUrl' => project_merge_requests_url(project, closed_url_params),
|
|
'openedIssuesUrl' => project_issues_url(project, opened_url_params),
|
|
'closedIssuesUrl' => project_issues_url(project, closed_url_params)
|
|
)
|
|
end
|
|
end
|
|
|
|
describe 'evidences' do
|
|
let(:path) { path_prefix + %w[evidences] }
|
|
|
|
let(:release_fields) do
|
|
query_graphql_field(:evidences, nil, 'nodes { id sha filepath collectedAt }')
|
|
end
|
|
|
|
it 'finds all evidence fields' do
|
|
post_query
|
|
|
|
evidence = release.evidences.first.present
|
|
|
|
expect(data["nodes"].first).to match a_graphql_entity_for(
|
|
evidence, :sha, :filepath,
|
|
'collectedAt' => evidence.collected_at.utc.iso8601
|
|
)
|
|
end
|
|
end
|
|
end
|
|
|
|
shared_examples 'restricted access to release fields' do
|
|
describe 'scalar fields' do
|
|
let(:path) { path_prefix }
|
|
|
|
let(:release_fields) do
|
|
%{
|
|
tagName
|
|
tagPath
|
|
description
|
|
descriptionHtml
|
|
name
|
|
createdAt
|
|
releasedAt
|
|
upcomingRelease
|
|
}
|
|
end
|
|
|
|
before do
|
|
post_query
|
|
end
|
|
|
|
it 'finds all release data' do
|
|
expect(data).to eq({
|
|
'tagName' => release.tag,
|
|
'tagPath' => nil,
|
|
'description' => release.description,
|
|
'descriptionHtml' => release.description_html,
|
|
'name' => release.name,
|
|
'createdAt' => release.created_at.iso8601,
|
|
'releasedAt' => release.released_at.iso8601,
|
|
'upcomingRelease' => false
|
|
})
|
|
end
|
|
end
|
|
|
|
describe 'milestones' do
|
|
let(:path) { path_prefix + %w[milestones nodes] }
|
|
|
|
let(:release_fields) do
|
|
query_graphql_field(:milestones, nil, 'nodes { id title }')
|
|
end
|
|
|
|
it 'finds milestones associated to a release' do
|
|
post_query
|
|
|
|
expected = release.milestones.order_by_dates_and_title.map do |milestone|
|
|
a_graphql_entity_for(milestone, :title)
|
|
end
|
|
|
|
expect(data).to match(expected)
|
|
end
|
|
end
|
|
|
|
describe 'author' do
|
|
let(:path) { path_prefix + %w[author] }
|
|
|
|
let(:release_fields) do
|
|
query_graphql_field(:author, nil, 'id username')
|
|
end
|
|
|
|
it 'finds the author of the release' do
|
|
post_query
|
|
|
|
expect(data).to match a_graphql_entity_for(release.author, :username)
|
|
end
|
|
end
|
|
|
|
describe 'commit' do
|
|
let(:path) { path_prefix + %w[commit] }
|
|
|
|
let(:release_fields) do
|
|
query_graphql_field(:commit, nil, 'sha')
|
|
end
|
|
|
|
it 'restricts commit associated with the release' do
|
|
post_query
|
|
|
|
expect(data).to eq(nil)
|
|
end
|
|
end
|
|
|
|
describe 'assets' do
|
|
describe 'count' do
|
|
let(:path) { path_prefix + %w[assets] }
|
|
|
|
let(:release_fields) do
|
|
query_graphql_field(:assets, nil, 'count')
|
|
end
|
|
|
|
it 'returns non source release links count' do
|
|
post_query
|
|
|
|
expect(data).to eq('count' => release.assets_count(except: [:sources]))
|
|
end
|
|
end
|
|
|
|
describe 'links' do
|
|
let(:path) { path_prefix + %w[assets links nodes] }
|
|
|
|
let(:release_fields) do
|
|
query_graphql_field(:assets, nil,
|
|
query_graphql_field(:links, nil, 'nodes { id name url, directAssetUrl }'))
|
|
end
|
|
|
|
it 'finds all non source release links' do
|
|
post_query
|
|
|
|
expected = release.links.map do |link|
|
|
a_graphql_entity_for(
|
|
link, :name, :url,
|
|
'directAssetUrl' => link.filepath ? Gitlab::Routing.url_helpers.project_release_url(project, release) << "/downloads#{link.filepath}" : link.url
|
|
)
|
|
end
|
|
|
|
expect(data).to match_array(expected)
|
|
end
|
|
end
|
|
|
|
describe 'sources' do
|
|
let(:path) { path_prefix + %w[assets sources nodes] }
|
|
|
|
let(:release_fields) do
|
|
query_graphql_field(:assets, nil,
|
|
query_graphql_field(:sources, nil, 'nodes { format url }'))
|
|
end
|
|
|
|
it 'restricts release sources' do
|
|
post_query
|
|
|
|
expect(data).to match_array([])
|
|
end
|
|
end
|
|
end
|
|
|
|
describe 'links' do
|
|
let(:path) { path_prefix + %w[links] }
|
|
|
|
let(:release_fields) do
|
|
query_graphql_field(:links, nil, %{
|
|
selfUrl
|
|
openedMergeRequestsUrl
|
|
mergedMergeRequestsUrl
|
|
closedMergeRequestsUrl
|
|
openedIssuesUrl
|
|
closedIssuesUrl
|
|
})
|
|
end
|
|
|
|
it 'finds only selfUrl' do
|
|
post_query
|
|
|
|
expect(data).to eq(
|
|
'selfUrl' => project_release_url(project, release),
|
|
'openedMergeRequestsUrl' => nil,
|
|
'mergedMergeRequestsUrl' => nil,
|
|
'closedMergeRequestsUrl' => nil,
|
|
'openedIssuesUrl' => nil,
|
|
'closedIssuesUrl' => nil
|
|
)
|
|
end
|
|
end
|
|
|
|
describe 'evidences' do
|
|
let(:path) { path_prefix + %w[evidences] }
|
|
|
|
let(:release_fields) do
|
|
query_graphql_field(:evidences, nil, 'nodes { id sha filepath collectedAt }')
|
|
end
|
|
|
|
it 'restricts all evidence fields' do
|
|
post_query
|
|
|
|
expect(data).to eq('nodes' => [])
|
|
end
|
|
end
|
|
end
|
|
|
|
shared_examples 'no access to the release field' do
|
|
describe 'repository-related fields' do
|
|
let(:path) { path_prefix }
|
|
|
|
let(:release_fields) do
|
|
'description'
|
|
end
|
|
|
|
before do
|
|
post_query
|
|
end
|
|
|
|
it 'returns nil' do
|
|
expect(data).to eq(nil)
|
|
end
|
|
end
|
|
end
|
|
|
|
shared_examples 'access to editUrl' do
|
|
let(:path) { path_prefix + %w[links] }
|
|
|
|
let(:release_fields) do
|
|
query_graphql_field(:links, nil, 'editUrl')
|
|
end
|
|
|
|
before do
|
|
post_query
|
|
end
|
|
|
|
it 'returns editUrl' do
|
|
expect(data).to eq('editUrl' => edit_project_release_url(project, release))
|
|
end
|
|
end
|
|
|
|
shared_examples 'no access to editUrl' do
|
|
let(:path) { path_prefix + %w[links] }
|
|
|
|
let(:release_fields) do
|
|
query_graphql_field(:links, nil, 'editUrl')
|
|
end
|
|
|
|
before do
|
|
post_query
|
|
end
|
|
|
|
it 'does not return editUrl' do
|
|
expect(data).to eq('editUrl' => nil)
|
|
end
|
|
end
|
|
|
|
describe "ensures that the correct data is returned based on the project's visibility and the user's access level" do
|
|
context 'when the project is private' 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, 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) }
|
|
|
|
before_all do
|
|
project.add_developer(developer)
|
|
project.add_guest(guest)
|
|
project.add_reporter(reporter)
|
|
end
|
|
|
|
context 'when the user is not logged in' do
|
|
let(:current_user) { stranger }
|
|
|
|
it_behaves_like 'no access to the release field'
|
|
end
|
|
|
|
context 'when the user has Guest permissions' do
|
|
let(:current_user) { guest }
|
|
|
|
it_behaves_like 'restricted access to release fields'
|
|
it_behaves_like 'no access to editUrl'
|
|
end
|
|
|
|
context 'when the user has Reporter permissions' do
|
|
let(:current_user) { reporter }
|
|
|
|
it_behaves_like 'full access to the release field'
|
|
it_behaves_like 'no access to editUrl'
|
|
end
|
|
|
|
context 'when the user has Developer permissions' do
|
|
let(:current_user) { developer }
|
|
|
|
it_behaves_like 'full access to the release field'
|
|
it_behaves_like 'access to editUrl'
|
|
end
|
|
end
|
|
|
|
context 'when the project is public' 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, 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) }
|
|
|
|
before_all do
|
|
project.add_developer(developer)
|
|
project.add_guest(guest)
|
|
project.add_reporter(reporter)
|
|
end
|
|
|
|
context 'when the user is not logged in' do
|
|
let(:current_user) { stranger }
|
|
|
|
it_behaves_like 'full access to the release field'
|
|
it_behaves_like 'no access to editUrl'
|
|
end
|
|
|
|
context 'when the user has Guest permissions' do
|
|
let(:current_user) { guest }
|
|
|
|
it_behaves_like 'full access to the release field'
|
|
it_behaves_like 'no access to editUrl'
|
|
end
|
|
|
|
context 'when the user has Reporter permissions' do
|
|
let(:current_user) { reporter }
|
|
|
|
it_behaves_like 'full access to the release field'
|
|
it_behaves_like 'no access to editUrl'
|
|
end
|
|
|
|
context 'when the user has Reporter permissions' do
|
|
let(:current_user) { reporter }
|
|
|
|
it_behaves_like 'full access to the release field'
|
|
end
|
|
|
|
context 'when the user has Developer permissions' do
|
|
let(:current_user) { developer }
|
|
|
|
it_behaves_like 'full access to the release field'
|
|
it_behaves_like 'access to editUrl'
|
|
end
|
|
end
|
|
end
|
|
|
|
describe 'upcoming release' do
|
|
let(:path) { path_prefix }
|
|
let(:project) { create(:project, :repository, :private) }
|
|
let(:release) { create(:release, :with_evidence, project: project, released_at: released_at) }
|
|
let(:current_user) { developer }
|
|
|
|
let(:release_fields) do
|
|
%{
|
|
releasedAt
|
|
upcomingRelease
|
|
}
|
|
end
|
|
|
|
before do
|
|
project.add_developer(developer)
|
|
post_query
|
|
end
|
|
|
|
context 'future release' do
|
|
let(:released_at) { Time.now + 1.day }
|
|
|
|
it 'finds all release data' do
|
|
expect(data).to eq({
|
|
'releasedAt' => release.released_at.iso8601,
|
|
'upcomingRelease' => true
|
|
})
|
|
end
|
|
end
|
|
|
|
context 'past release' do
|
|
let(:released_at) { Time.now - 1.day }
|
|
|
|
it 'finds all release data' do
|
|
expect(data).to eq({
|
|
'releasedAt' => release.released_at.iso8601,
|
|
'upcomingRelease' => false
|
|
})
|
|
end
|
|
end
|
|
end
|
|
|
|
describe 'milestone order' do
|
|
let(:path) { path_prefix }
|
|
let(:current_user) { stranger }
|
|
let_it_be(:project) { create(:project, :public) }
|
|
let_it_be_with_reload(:release) { create(:release, project: project) }
|
|
|
|
let(:release_fields) do
|
|
%{
|
|
milestones {
|
|
nodes {
|
|
title
|
|
}
|
|
}
|
|
}
|
|
end
|
|
|
|
let(:actual_milestone_title_order) do
|
|
post_query
|
|
|
|
data.dig('milestones', 'nodes').map { |m| m['title'] }
|
|
end
|
|
|
|
before do
|
|
release.update!(milestones: [milestone_2, milestone_1])
|
|
end
|
|
|
|
it_behaves_like 'correct release milestone order'
|
|
end
|
|
end
|