Read about our upcoming Code of Conduct on this issue

groups_spec.rb 18.6 KB
Newer Older
1
2
require 'spec_helper'

3
describe API::Groups do
4
  include UploadHelpers
5

6
  let(:user1) { create(:user, can_create_group: false) }
Izaak Alpert's avatar
Izaak Alpert committed
7
  let(:user2) { create(:user) }
8
  let(:user3) { create(:user) }
9
  let(:admin) { create(:admin) }
10
  let!(:group1) { create(:group, avatar: File.open(uploaded_image_temp_path)) }
Douwe Maan's avatar
Douwe Maan committed
11
  let!(:group2) { create(:group, :private) }
12
13
14
  let!(:project1) { create(:empty_project, namespace: group1) }
  let!(:project2) { create(:empty_project, namespace: group2) }
  let!(:project3) { create(:empty_project, namespace: group1, path: 'test', visibility_level: Gitlab::VisibilityLevel::PRIVATE) }
15
16
17
18
19

  before do
    group1.add_owner(user1)
    group2.add_owner(user2)
  end
20
21
22

  describe "GET /groups" do
    context "when unauthenticated" do
23
      it "returns authentication error" do
24
        get api("/groups")
25

26
        expect(response).to have_http_status(401)
27
28
29
30
      end
    end

    context "when authenticated as user" do
31
      it "normal user: returns an array of groups of user1" do
32
        get api("/groups", user1)
33

34
        expect(response).to have_http_status(200)
35
        expect(response).to include_pagination_headers
36
37
        expect(json_response).to be_an Array
        expect(json_response.length).to eq(1)
Douwe Maan's avatar
Douwe Maan committed
38
39
        expect(json_response)
          .to satisfy_one { |group| group['name'] == group1.name }
40
      end
Markus Koller's avatar
Markus Koller committed
41
42
43
44
45

      it "does not include statistics" do
        get api("/groups", user1), statistics: true

        expect(response).to have_http_status(200)
46
        expect(response).to include_pagination_headers
Markus Koller's avatar
Markus Koller committed
47
48
49
        expect(json_response).to be_an Array
        expect(json_response.first).not_to include 'statistics'
      end
50
    end
Andrey Kumanyaev's avatar
Andrey Kumanyaev committed
51

52
    context "when authenticated as admin" do
53
      it "admin: returns an array of all groups" do
54
        get api("/groups", admin)
55

56
        expect(response).to have_http_status(200)
57
        expect(response).to include_pagination_headers
58
59
        expect(json_response).to be_an Array
        expect(json_response.length).to eq(2)
60
      end
Markus Koller's avatar
Markus Koller committed
61
62
63
64
65

      it "does not include statistics by default" do
        get api("/groups", admin)

        expect(response).to have_http_status(200)
66
        expect(response).to include_pagination_headers
Markus Koller's avatar
Markus Koller committed
67
68
69
70
71
72
73
74
75
76
        expect(json_response).to be_an Array
        expect(json_response.first).not_to include('statistics')
      end

      it "includes statistics if requested" do
        attributes = {
          storage_size: 702,
          repository_size: 123,
          lfs_objects_size: 234,
          build_artifacts_size: 345,
77
        }.stringify_keys
78
        exposed_attributes = attributes.dup
Toon Claes's avatar
Toon Claes committed
79
        exposed_attributes['job_artifacts_size'] = exposed_attributes.delete('build_artifacts_size')
Markus Koller's avatar
Markus Koller committed
80
81
82
83
84
85

        project1.statistics.update!(attributes)

        get api("/groups", admin), statistics: true

        expect(response).to have_http_status(200)
86
        expect(response).to include_pagination_headers
Markus Koller's avatar
Markus Koller committed
87
        expect(json_response).to be_an Array
Douwe Maan's avatar
Douwe Maan committed
88
        expect(json_response)
Toon Claes's avatar
Toon Claes committed
89
          .to satisfy_one { |group| group['statistics'] == exposed_attributes }
Markus Koller's avatar
Markus Koller committed
90
      end
91
    end
barthc's avatar
barthc committed
92
93
94
95
96
97

    context "when using skip_groups in request" do
      it "returns all groups excluding skipped groups" do
        get api("/groups", admin), skip_groups: [group2.id]

        expect(response).to have_http_status(200)
98
        expect(response).to include_pagination_headers
barthc's avatar
barthc committed
99
100
101
102
        expect(json_response).to be_an Array
        expect(json_response.length).to eq(1)
      end
    end
103
104

    context "when using all_available in request" do
Sean McGivern's avatar
Sean McGivern committed
105
106
      let(:response_groups) { json_response.map { |group| group['name'] } }

107
108
      it "returns all groups you have access to" do
        public_group = create :group, :public
109

110
111
112
        get api("/groups", user1), all_available: true

        expect(response).to have_http_status(200)
113
        expect(response).to include_pagination_headers
114
        expect(json_response).to be_an Array
Sean McGivern's avatar
Sean McGivern committed
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
        expect(response_groups).to contain_exactly(public_group.name, group1.name)
      end
    end

    context "when using sorting" do
      let(:group3) { create(:group, name: "a#{group1.name}", path: "z#{group1.path}") }
      let(:response_groups) { json_response.map { |group| group['name'] } }

      before do
        group3.add_owner(user1)
      end

      it "sorts by name ascending by default" do
        get api("/groups", user1)

        expect(response).to have_http_status(200)
131
        expect(response).to include_pagination_headers
Sean McGivern's avatar
Sean McGivern committed
132
133
134
135
136
137
138
139
        expect(json_response).to be_an Array
        expect(response_groups).to eq([group3.name, group1.name])
      end

      it "sorts in descending order when passed" do
        get api("/groups", user1), sort: "desc"

        expect(response).to have_http_status(200)
140
        expect(response).to include_pagination_headers
Sean McGivern's avatar
Sean McGivern committed
141
142
143
144
145
146
147
148
        expect(json_response).to be_an Array
        expect(response_groups).to eq([group1.name, group3.name])
      end

      it "sorts by the order_by param" do
        get api("/groups", user1), order_by: "path"

        expect(response).to have_http_status(200)
149
        expect(response).to include_pagination_headers
Sean McGivern's avatar
Sean McGivern committed
150
151
        expect(json_response).to be_an Array
        expect(response_groups).to eq([group1.name, group3.name])
152
153
      end
    end
154

155
    context 'when using owned in the request' do
156
      it 'returns an array of groups the user owns' do
157
        get api('/groups', user2), owned: true
158

159
        expect(response).to have_http_status(200)
160
        expect(response).to include_pagination_headers
161
162
163
164
165
166
        expect(json_response).to be_an Array
        expect(json_response.first['name']).to eq(group2.name)
      end
    end
  end

167
168
  describe "GET /groups/:id" do
    context "when authenticated as user" do
169
      it "returns one of user1's groups" do
170
        project = create(:empty_project, namespace: group2, path: 'Foo')
171
172
        create(:project_group_link, project: project, group: group1)

173
        get api("/groups/#{group1.id}", user1)
174

175
        expect(response).to have_http_status(200)
176
177
178
179
        expect(json_response['id']).to eq(group1.id)
        expect(json_response['name']).to eq(group1.name)
        expect(json_response['path']).to eq(group1.path)
        expect(json_response['description']).to eq(group1.description)
180
        expect(json_response['visibility']).to eq(Gitlab::VisibilityLevel.string_level(group1.visibility_level))
181
        expect(json_response['avatar_url']).to eq(group1.avatar_url(only_path: false))
182
        expect(json_response['web_url']).to eq(group1.web_url)
183
184
185
        expect(json_response['request_access_enabled']).to eq(group1.request_access_enabled)
        expect(json_response['full_name']).to eq(group1.full_name)
        expect(json_response['full_path']).to eq(group1.full_path)
186
        expect(json_response['parent_id']).to eq(group1.parent_id)
187
188
189
190
191
        expect(json_response['projects']).to be_an Array
        expect(json_response['projects'].length).to eq(2)
        expect(json_response['shared_projects']).to be_an Array
        expect(json_response['shared_projects'].length).to eq(1)
        expect(json_response['shared_projects'][0]['id']).to eq(project.id)
192
      end
Andrey Kumanyaev's avatar
Andrey Kumanyaev committed
193

194
      it "does not return a non existing group" do
195
        get api("/groups/1328", user1)
196

197
        expect(response).to have_http_status(404)
198
      end
Andrey Kumanyaev's avatar
Andrey Kumanyaev committed
199

200
      it "does not return a group not attached to user1" do
201
        get api("/groups/#{group2.id}", user1)
202

203
        expect(response).to have_http_status(404)
204
205
      end
    end
Andrey Kumanyaev's avatar
Andrey Kumanyaev committed
206

207
    context "when authenticated as admin" do
208
      it "returns any existing group" do
209
        get api("/groups/#{group2.id}", admin)
210

211
        expect(response).to have_http_status(200)
Douwe Maan's avatar
Douwe Maan committed
212
        expect(json_response['name']).to eq(group2.name)
213
      end
Andrey Kumanyaev's avatar
Andrey Kumanyaev committed
214

215
      it "does not return a non existing group" do
216
        get api("/groups/1328", admin)
217

218
        expect(response).to have_http_status(404)
219
220
      end
    end
221
222

    context 'when using group path in URL' do
223
      it 'returns any existing group' do
224
        get api("/groups/#{group1.path}", admin)
225

226
        expect(response).to have_http_status(200)
Douwe Maan's avatar
Douwe Maan committed
227
        expect(json_response['name']).to eq(group1.name)
228
229
      end

230
      it 'does not return a non existing group' do
231
        get api('/groups/unknown', admin)
232

233
        expect(response).to have_http_status(404)
234
235
      end

236
      it 'does not return a group not attached to user1' do
237
        get api("/groups/#{group2.path}", user1)
238

239
        expect(response).to have_http_status(404)
240
241
      end
    end
242
  end
Andrey Kumanyaev's avatar
Andrey Kumanyaev committed
243

244
245
246
  describe 'PUT /groups/:id' do
    let(:new_group_name) { 'New Group'}

247
    context 'when authenticated as the group owner' do
248
      it 'updates the group' do
249
        put api("/groups/#{group1.id}", user1), name: new_group_name, request_access_enabled: true
250

251
        expect(response).to have_http_status(200)
252
        expect(json_response['name']).to eq(new_group_name)
253
        expect(json_response['request_access_enabled']).to eq(true)
254
255
256
      end

      it 'returns 404 for a non existing group' do
Robert Schilling's avatar
Robert Schilling committed
257
        put api('/groups/1328', user1), name: new_group_name
258

259
        expect(response).to have_http_status(404)
260
261
262
      end
    end

263
    context 'when authenticated as the admin' do
264
265
266
      it 'updates the group' do
        put api("/groups/#{group1.id}", admin), name: new_group_name

267
        expect(response).to have_http_status(200)
268
269
270
271
        expect(json_response['name']).to eq(new_group_name)
      end
    end

272
273
    context 'when authenticated as an user that can see the group' do
      it 'does not updates the group' do
274
275
        put api("/groups/#{group1.id}", user2), name: new_group_name

276
        expect(response).to have_http_status(403)
277
278
      end
    end
279
280

    context 'when authenticated as an user that cannot see the group' do
281
      it 'returns 404 when trying to update the group' do
282
283
        put api("/groups/#{group2.id}", user1), name: new_group_name

284
        expect(response).to have_http_status(404)
285
286
      end
    end
287
288
  end

Douwe Maan's avatar
Douwe Maan committed
289
290
  describe "GET /groups/:id/projects" do
    context "when authenticated as user" do
291
      it "returns the group's projects" do
Douwe Maan's avatar
Douwe Maan committed
292
        get api("/groups/#{group1.id}/projects", user1)
293

294
        expect(response).to have_http_status(200)
295
        expect(response).to include_pagination_headers
296
        expect(json_response.length).to eq(2)
Douwe Maan's avatar
Douwe Maan committed
297
        project_names = json_response.map { |proj| proj['name'] }
298
        expect(project_names).to match_array([project1.name, project3.name])
299
        expect(json_response.first['visibility']).to be_present
300
301
302
303
304
305
      end

      it "returns the group's projects with simple representation" do
        get api("/groups/#{group1.id}/projects", user1), simple: true

        expect(response).to have_http_status(200)
306
        expect(response).to include_pagination_headers
307
        expect(json_response.length).to eq(2)
Douwe Maan's avatar
Douwe Maan committed
308
        project_names = json_response.map { |proj| proj['name'] }
309
        expect(project_names).to match_array([project1.name, project3.name])
310
        expect(json_response.first['visibility']).not_to be_present
Douwe Maan's avatar
Douwe Maan committed
311
312
      end

Robert Schilling's avatar
Robert Schilling committed
313
      it 'filters the groups projects' do
314
        public_project = create(:empty_project, :public, path: 'test1', group: group1)
Robert Schilling's avatar
Robert Schilling committed
315
316
317
318

        get api("/groups/#{group1.id}/projects", user1), visibility: 'public'

        expect(response).to have_http_status(200)
319
        expect(response).to include_pagination_headers
Robert Schilling's avatar
Robert Schilling committed
320
321
        expect(json_response).to be_an(Array)
        expect(json_response.length).to eq(1)
322
        expect(json_response.first['name']).to eq(public_project.name)
Robert Schilling's avatar
Robert Schilling committed
323
324
      end

325
      it "does not return a non existing group" do
Douwe Maan's avatar
Douwe Maan committed
326
        get api("/groups/1328/projects", user1)
327

328
        expect(response).to have_http_status(404)
Douwe Maan's avatar
Douwe Maan committed
329
330
      end

331
      it "does not return a group not attached to user1" do
Douwe Maan's avatar
Douwe Maan committed
332
        get api("/groups/#{group2.id}/projects", user1)
333

334
        expect(response).to have_http_status(404)
Douwe Maan's avatar
Douwe Maan committed
335
      end
336

Valery Sizov's avatar
Valery Sizov committed
337
      it "only returns projects to which user has access" do
338
339
340
341
        project3.team << [user3, :developer]

        get api("/groups/#{group1.id}/projects", user3)

342
        expect(response).to have_http_status(200)
343
        expect(response).to include_pagination_headers
344
345
346
        expect(json_response.length).to eq(1)
        expect(json_response.first['name']).to eq(project3.name)
      end
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366

      it 'only returns the projects owned by user' do
        project2.group.add_owner(user3)

        get api("/groups/#{project2.group.id}/projects", user3), owned: true

        expect(response).to have_http_status(200)
        expect(json_response.length).to eq(1)
        expect(json_response.first['name']).to eq(project2.name)
      end

      it 'only returns the projects starred by user' do
        user1.starred_projects = [project1]

        get api("/groups/#{group1.id}/projects", user1), starred: true

        expect(response).to have_http_status(200)
        expect(json_response.length).to eq(1)
        expect(json_response.first['name']).to eq(project1.name)
      end
Douwe Maan's avatar
Douwe Maan committed
367
368
369
    end

    context "when authenticated as admin" do
Valery Sizov's avatar
Valery Sizov committed
370
      it "returns any existing group" do
Douwe Maan's avatar
Douwe Maan committed
371
        get api("/groups/#{group2.id}/projects", admin)
372

373
        expect(response).to have_http_status(200)
374
        expect(response).to include_pagination_headers
Douwe Maan's avatar
Douwe Maan committed
375
376
377
378
        expect(json_response.length).to eq(1)
        expect(json_response.first['name']).to eq(project2.name)
      end

Valery Sizov's avatar
Valery Sizov committed
379
      it "does not return a non existing group" do
Douwe Maan's avatar
Douwe Maan committed
380
        get api("/groups/1328/projects", admin)
381

382
        expect(response).to have_http_status(404)
Douwe Maan's avatar
Douwe Maan committed
383
384
385
386
      end
    end

    context 'when using group path in URL' do
Valery Sizov's avatar
Valery Sizov committed
387
      it 'returns any existing group' do
Douwe Maan's avatar
Douwe Maan committed
388
        get api("/groups/#{group1.path}/projects", admin)
389

390
        expect(response).to have_http_status(200)
391
        expect(response).to include_pagination_headers
Douwe Maan's avatar
Douwe Maan committed
392
        project_names = json_response.map { |proj| proj['name'] }
393
        expect(project_names).to match_array([project1.name, project3.name])
Douwe Maan's avatar
Douwe Maan committed
394
395
      end

396
      it 'does not return a non existing group' do
Douwe Maan's avatar
Douwe Maan committed
397
        get api('/groups/unknown/projects', admin)
398

399
        expect(response).to have_http_status(404)
Douwe Maan's avatar
Douwe Maan committed
400
401
      end

402
      it 'does not return a group not attached to user1' do
Douwe Maan's avatar
Douwe Maan committed
403
        get api("/groups/#{group2.path}/projects", user1)
404

405
        expect(response).to have_http_status(404)
Douwe Maan's avatar
Douwe Maan committed
406
407
408
409
      end
    end
  end

410
  describe "POST /groups" do
411
    context "when authenticated as user without group permissions" do
412
      it "does not create group" do
413
        post api("/groups", user1), attributes_for(:group)
414

415
        expect(response).to have_http_status(403)
416
417
      end
    end
Andrey Kumanyaev's avatar
Andrey Kumanyaev committed
418

419
    context "when authenticated as user with group permissions" do
420
      it "creates group" do
421
422
423
        group = attributes_for(:group, { request_access_enabled: false })

        post api("/groups", user3), group
424

425
        expect(response).to have_http_status(201)
426
427
428
429

        expect(json_response["name"]).to eq(group[:name])
        expect(json_response["path"]).to eq(group[:path])
        expect(json_response["request_access_enabled"]).to eq(group[:request_access_enabled])
430
      end
431

432
433
434
435
436
437
438
439
440
441
442
443
444
      it "creates a nested group" do
        parent = create(:group)
        parent.add_owner(user3)
        group = attributes_for(:group, { parent_id: parent.id })

        post api("/groups", user3), group

        expect(response).to have_http_status(201)

        expect(json_response["full_path"]).to eq("#{parent.path}/#{group[:path]}")
        expect(json_response["parent_id"]).to eq(parent.id)
      end

445
      it "does not create group, duplicate" do
446
        post api("/groups", user3), { name: 'Duplicate Test', path: group2.path }
447

448
        expect(response).to have_http_status(400)
449
        expect(response.message).to eq("Bad Request")
450
      end
451

452
      it "returns 400 bad request error if name not given" do
453
        post api("/groups", user3), { path: group2.path }
454

455
        expect(response).to have_http_status(400)
456
457
      end

458
      it "returns 400 bad request error if path not given" do
459
        post api("/groups", user3), { name: 'test' }
460

461
        expect(response).to have_http_status(400)
462
      end
463
464
    end
  end
Angus MacArthur's avatar
Angus MacArthur committed
465

Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
466
467
  describe "DELETE /groups/:id" do
    context "when authenticated as user" do
468
      it "removes group" do
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
469
        delete api("/groups/#{group1.id}", user1)
470

471
        expect(response).to have_http_status(204)
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
472
473
      end

474
      it "does not remove a group if not an owner" do
475
        user4 = create(:user)
476
        group1.add_master(user4)
477

Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
478
        delete api("/groups/#{group1.id}", user3)
479

480
        expect(response).to have_http_status(403)
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
481
482
      end

483
      it "does not remove a non existing group" do
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
484
        delete api("/groups/1328", user1)
485

486
        expect(response).to have_http_status(404)
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
487
488
      end

489
      it "does not remove a group not attached to user1" do
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
490
        delete api("/groups/#{group2.id}", user1)
491

492
        expect(response).to have_http_status(404)
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
493
494
495
496
      end
    end

    context "when authenticated as admin" do
497
      it "removes any existing group" do
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
498
        delete api("/groups/#{group2.id}", admin)
499

500
        expect(response).to have_http_status(204)
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
501
502
      end

503
      it "does not remove a non existing group" do
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
504
        delete api("/groups/1328", admin)
505

506
        expect(response).to have_http_status(404)
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
507
508
509
510
      end
    end
  end

Angus MacArthur's avatar
Angus MacArthur committed
511
  describe "POST /groups/:id/projects/:project_id" do
512
    let(:project) { create(:empty_project) }
513
    let(:project_path) { project.full_path.gsub('/', '%2F') }
514

Angus MacArthur's avatar
Angus MacArthur committed
515
    before(:each) do
516
517
      allow_any_instance_of(Projects::TransferService).
        to receive(:execute).and_return(true)
Angus MacArthur's avatar
Angus MacArthur committed
518
519
520
    end

    context "when authenticated as user" do
521
      it "does not transfer project to group" do
Angus MacArthur's avatar
Angus MacArthur committed
522
        post api("/groups/#{group1.id}/projects/#{project.id}", user2)
523

524
        expect(response).to have_http_status(403)
Angus MacArthur's avatar
Angus MacArthur committed
525
526
527
528
      end
    end

    context "when authenticated as admin" do
529
      it "transfers project to group" do
Angus MacArthur's avatar
Angus MacArthur committed
530
        post api("/groups/#{group1.id}/projects/#{project.id}", admin)
531

532
        expect(response).to have_http_status(201)
Angus MacArthur's avatar
Angus MacArthur committed
533
      end
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569

      context 'when using project path in URL' do
        context 'with a valid project path' do
          it "transfers project to group" do
            post api("/groups/#{group1.id}/projects/#{project_path}", admin)

            expect(response).to have_http_status(201)
          end
        end

        context 'with a non-existent project path' do
          it "does not transfer project to group" do
            post api("/groups/#{group1.id}/projects/nogroup%2Fnoproject", admin)

            expect(response).to have_http_status(404)
          end
        end
      end

      context 'when using a group path in URL' do
        context 'with a valid group path' do
          it "transfers project to group" do
            post api("/groups/#{group1.path}/projects/#{project_path}", admin)

            expect(response).to have_http_status(201)
          end
        end

        context 'with a non-existent group path' do
          it "does not transfer project to group" do
            post api("/groups/noexist/projects/#{project_path}", admin)

            expect(response).to have_http_status(404)
          end
        end
      end
Angus MacArthur's avatar
Angus MacArthur committed
570
571
    end
  end
572
end