release_spec.rb 10.1 KB
Newer Older
1 2 3 4
# frozen_string_literal: true

require 'spec_helper'

5
RSpec.describe 'Query.project(fullPath).release(tagName)' do
6
  include GraphqlHelpers
7
  include Presentable
8 9

  let_it_be(:developer) { create(:user) }
10 11 12
  let_it_be(:guest) { create(:user) }
  let_it_be(:reporter) { create(:user) }
  let_it_be(:stranger) { create(:user) }
13

14 15 16 17 18
  let(:params_for_issues_and_mrs) { { scope: 'all', state: 'opened', release_tag: release.tag } }
  let(:post_query) { post_graphql(query, current_user: current_user) }
  let(:path_prefix) { %w[project release] }
  let(:data) { graphql_data.dig(*path) }

19 20 21 22 23
  def query(rq = release_fields)
    graphql_query_for(:project, { fullPath: project.full_path },
      query_graphql_field(:release, { tagName: release.tag }, rq))
  end

24 25 26
  before do
    stub_default_url_options(host: 'www.example.com')
  end
27

28 29 30
  shared_examples 'full access to the release field' do
    describe 'scalar fields' do
      let(:path) { path_prefix }
31

32 33 34 35 36 37 38 39 40 41 42
      let(:release_fields) do
        query_graphql_field(%{
          tagName
          tagPath
          description
          descriptionHtml
          name
          createdAt
          releasedAt
        })
      end
43

44 45 46
      before do
        post_query
      end
47

48 49 50 51 52 53 54 55 56 57 58
      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
        })
      end
59 60
    end

61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
    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.map do |milestone|
          { 'id' => global_id_of(milestone), 'title' => milestone.title }
        end

        expect(data).to match_array(expected)
      end
77 78
    end

79 80
    describe 'author' do
      let(:path) { path_prefix + %w[author] }
81

82 83
      let(:release_fields) do
        query_graphql_field(:author, nil, 'id username')
84 85
      end

86 87
      it 'finds the author of the release' do
        post_query
88

89
        expect(data).to eq(
90 91
          'id' => global_id_of(release.author),
          'username' => release.author.username
92
        )
93
      end
94 95
    end

96 97
    describe 'commit' do
      let(:path) { path_prefix + %w[commit] }
98

99 100 101 102 103 104
      let(:release_fields) do
        query_graphql_field(:commit, nil, 'sha')
      end

      it 'finds the commit associated with the release' do
        post_query
105

106
        expect(data).to eq('sha' => release.commit.sha)
107
      end
108 109
    end

110 111 112
    describe 'assets' do
      describe 'count' do
        let(:path) { path_prefix + %w[assets] }
113

114 115 116
        let(:release_fields) do
          query_graphql_field(:assets, nil, 'count')
        end
117

118 119 120
        it 'returns the number of assets associated to the release' do
          post_query

121
          expect(data).to eq('count' => release.sources.size + release.links.size)
122
        end
123 124
      end

125 126 127 128 129 130 131
      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 external }'))
        end
132

133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
        it 'finds all release links' do
          post_query

          expected = release.links.map do |link|
            {
              'id' => global_id_of(link),
              'name' => link.name,
              'url' => link.url,
              'external' => link.external?
            }
          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
169 170 171
      end
    end

172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
    describe 'links' do
      let(:path) { path_prefix + %w[links] }

      let(:release_fields) do
        query_graphql_field(:links, nil, %{
          selfUrl
          mergeRequestsUrl
          issuesUrl
        })
      end

      it 'finds all release links' do
        post_query

        expect(data).to eq(
          'selfUrl' => project_release_url(project, release),
          'mergeRequestsUrl' => project_merge_requests_url(project, params_for_issues_and_mrs),
          'issuesUrl' => project_issues_url(project, params_for_issues_and_mrs)
        )
      end
    end

194 195 196
    describe 'evidences' do
      let(:path) { path_prefix + %w[evidences] }

197
      let(:release_fields) do
198
        query_graphql_field(:evidences, nil, 'nodes { id sha filepath collectedAt }')
199 200
      end

201
      it 'finds all evidence fields' do
202 203
        post_query

204
        evidence = release.evidences.first.present
205 206

        expect(data["nodes"].first).to eq(
207 208 209 210
          'id' => global_id_of(evidence),
          'sha' => evidence.sha,
          'filepath' => evidence.filepath,
          'collectedAt' => evidence.collected_at.utc.iso8601
211
        )
212 213
      end
    end
214 215 216 217 218
  end

  shared_examples 'no access to the release field' do
    describe 'repository-related fields' do
      let(:path) { path_prefix }
219 220

      let(:release_fields) do
221
        query_graphql_field('description')
222 223
      end

224
      before do
225
        post_query
226
      end
227

228 229 230 231 232
      it 'returns nil' do
        expect(data).to eq(nil)
      end
    end
  end
233

234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265
  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

266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296
  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) { create(:release, :with_evidence, project: project, milestones: [milestone_1, milestone_2]) }
      let_it_be(:release_link_1) { create(:release_link, release: release) }
      let_it_be(:release_link_2) { create(:release_link, release: release) }

      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 'no access to the release field'
      end

      context 'when the user has Reporter permissions' do
        let(:current_user) { reporter }

        it_behaves_like 'full access to the release field'
297
        it_behaves_like 'no access to editUrl'
298 299 300 301 302 303
      end

      context 'when the user has Developer permissions' do
        let(:current_user) { developer }

        it_behaves_like 'full access to the release field'
304
        it_behaves_like 'access to editUrl'
305 306
      end
    end
307

308 309 310 311 312 313 314 315 316 317 318 319
    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) { create(:release, :with_evidence, project: project, milestones: [milestone_1, milestone_2]) }
      let_it_be(:release_link_1) { create(:release_link, release: release) }
      let_it_be(:release_link_2) { create(:release_link, release: release) }

      before_all do
        project.add_developer(developer)
        project.add_guest(guest)
        project.add_reporter(reporter)
320 321
      end

322 323
      context 'when the user is not logged in' do
        let(:current_user) { stranger }
324

325
        it_behaves_like 'full access to the release field'
326
        it_behaves_like 'no access to editUrl'
327
      end
328

329 330 331 332
      context 'when the user has Guest permissions' do
        let(:current_user) { guest }

        it_behaves_like 'full access to the release field'
333 334 335 336 337 338 339 340
        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'
341 342
      end

343 344
      context 'when the user has Reporter permissions' do
        let(:current_user) { reporter }
345

346 347
        it_behaves_like 'full access to the release field'
      end
348

349 350
      context 'when the user has Developer permissions' do
        let(:current_user) { developer }
351

352
        it_behaves_like 'full access to the release field'
353
        it_behaves_like 'access to editUrl'
354 355
      end
    end
356
  end
357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373

  describe 'ensures that the release data can be contolled by a feature flag' do
    context 'when the graphql_release_data feature flag is disabled' do
      let_it_be(:project) { create(:project, :repository, :public) }
      let_it_be(:release) { create(:release, project: project) }

      let(:current_user) { developer }

      before do
        stub_feature_flags(graphql_release_data: false)

        project.add_developer(developer)
      end

      it_behaves_like 'no access to the release field'
    end
  end
374
end