PageRenderTime 98ms CodeModel.GetById 31ms app.highlight 59ms RepoModel.GetById 1ms app.codeStats 0ms

/spec/requests/api/members_spec.rb

https://gitlab.com/dcondrey/gitlab-ee
Ruby | 363 lines | 288 code | 69 blank | 6 comment | 8 complexity | b7f6f622d502c3a7567819668b3b408f MD5 | raw file
  1require 'spec_helper'
  2
  3describe API::Members, api: true  do
  4  include ApiHelpers
  5
  6  let(:master) { create(:user) }
  7  let(:developer) { create(:user) }
  8  let(:access_requester) { create(:user) }
  9  let(:stranger) { create(:user) }
 10
 11  let(:project) do
 12    project = create(:project, :public, creator_id: master.id, namespace: master.namespace)
 13    project.team << [developer, :developer]
 14    project.team << [master, :master]
 15    project.request_access(access_requester)
 16    project
 17  end
 18
 19  let!(:group) do
 20    group = create(:group, :public)
 21    group.add_developer(developer)
 22    group.add_owner(master)
 23    group.request_access(access_requester)
 24    group
 25  end
 26
 27  shared_examples 'GET /:sources/:id/members' do |source_type|
 28    context "with :sources == #{source_type.pluralize}" do
 29      it_behaves_like 'a 404 response when source is private' do
 30        let(:route) { get api("/#{source_type.pluralize}/#{source.id}/members", stranger) }
 31      end
 32
 33      %i[master developer access_requester stranger].each do |type|
 34        context "when authenticated as a #{type}" do
 35          it 'returns 200' do
 36            user = public_send(type)
 37            get api("/#{source_type.pluralize}/#{source.id}/members", user)
 38
 39            expect(response).to have_http_status(200)
 40            expect(json_response.size).to eq(2)
 41            expect(json_response.map { |u| u['id'] }).to match_array [master.id, developer.id]
 42          end
 43        end
 44      end
 45
 46      it 'does not return invitees' do
 47        create(:"#{source_type}_member", invite_token: '123', invite_email: 'test@abc.com', source: source, user: nil)
 48
 49        get api("/#{source_type.pluralize}/#{source.id}/members", developer)
 50
 51        expect(response).to have_http_status(200)
 52        expect(json_response.size).to eq(2)
 53        expect(json_response.map { |u| u['id'] }).to match_array [master.id, developer.id]
 54      end
 55
 56      it 'finds members with query string' do
 57        get api("/#{source_type.pluralize}/#{source.id}/members", developer), query: master.username
 58
 59        expect(response).to have_http_status(200)
 60        expect(json_response.count).to eq(1)
 61        expect(json_response.first['username']).to eq(master.username)
 62      end
 63    end
 64  end
 65
 66  shared_examples 'GET /:sources/:id/members/:user_id' do |source_type|
 67    context "with :sources == #{source_type.pluralize}" do
 68      it_behaves_like 'a 404 response when source is private' do
 69        let(:route) { get api("/#{source_type.pluralize}/#{source.id}/members/#{developer.id}", stranger) }
 70      end
 71
 72      context 'when authenticated as a non-member' do
 73        %i[access_requester stranger].each do |type|
 74          context "as a #{type}" do
 75            it 'returns 200' do
 76              user = public_send(type)
 77              get api("/#{source_type.pluralize}/#{source.id}/members/#{developer.id}", user)
 78
 79              expect(response).to have_http_status(200)
 80              # User attributes
 81              expect(json_response['id']).to eq(developer.id)
 82              expect(json_response['name']).to eq(developer.name)
 83              expect(json_response['username']).to eq(developer.username)
 84              expect(json_response['state']).to eq(developer.state)
 85              expect(json_response['avatar_url']).to eq(developer.avatar_url)
 86              expect(json_response['web_url']).to eq(Gitlab::Routing.url_helpers.user_url(developer))
 87
 88              # Member attributes
 89              expect(json_response['access_level']).to eq(Member::DEVELOPER)
 90            end
 91          end
 92        end
 93      end
 94    end
 95  end
 96
 97  shared_examples 'POST /:sources/:id/members' do |source_type|
 98    context "with :sources == #{source_type.pluralize}" do
 99      it_behaves_like 'a 404 response when source is private' do
100        let(:route) do
101          post api("/#{source_type.pluralize}/#{source.id}/members", stranger),
102               user_id: access_requester.id, access_level: Member::MASTER
103        end
104      end
105
106      context 'when authenticated as a non-member or member with insufficient rights' do
107        %i[access_requester stranger developer].each do |type|
108          context "as a #{type}" do
109            it 'returns 403' do
110              user = public_send(type)
111              post api("/#{source_type.pluralize}/#{source.id}/members", user),
112                   user_id: access_requester.id, access_level: Member::MASTER
113
114              expect(response).to have_http_status(403)
115            end
116          end
117        end
118      end
119
120      context 'when authenticated as a master/owner' do
121        context 'and new member is already a requester' do
122          it 'transforms the requester into a proper member' do
123            expect do
124              post api("/#{source_type.pluralize}/#{source.id}/members", master),
125                   user_id: access_requester.id, access_level: Member::MASTER
126
127              expect(response).to have_http_status(201)
128            end.to change { source.members.count }.by(1)
129            expect(source.requesters.count).to eq(0)
130            expect(json_response['id']).to eq(access_requester.id)
131            expect(json_response['access_level']).to eq(Member::MASTER)
132          end
133        end
134
135        it 'creates a new member' do
136          expect do
137            post api("/#{source_type.pluralize}/#{source.id}/members", master),
138                 user_id: stranger.id, access_level: Member::DEVELOPER, expires_at: '2016-08-05'
139
140            expect(response).to have_http_status(201)
141          end.to change { source.members.count }.by(1)
142          expect(json_response['id']).to eq(stranger.id)
143          expect(json_response['access_level']).to eq(Member::DEVELOPER)
144          expect(json_response['expires_at']).to eq('2016-08-05')
145        end
146      end
147
148      it "returns #{source_type == 'project' ? 201 : 409} if member already exists" do
149        post api("/#{source_type.pluralize}/#{source.id}/members", master),
150             user_id: master.id, access_level: Member::MASTER
151
152        expect(response).to have_http_status(source_type == 'project' ? 201 : 409)
153      end
154
155      it 'returns 400 when user_id is not given' do
156        post api("/#{source_type.pluralize}/#{source.id}/members", master),
157             access_level: Member::MASTER
158
159        expect(response).to have_http_status(400)
160      end
161
162      it 'returns 400 when access_level is not given' do
163        post api("/#{source_type.pluralize}/#{source.id}/members", master),
164             user_id: stranger.id
165
166        expect(response).to have_http_status(400)
167      end
168
169      it 'returns 422 when access_level is not valid' do
170        post api("/#{source_type.pluralize}/#{source.id}/members", master),
171             user_id: stranger.id, access_level: 1234
172
173        expect(response).to have_http_status(422)
174      end
175    end
176  end
177
178  ## EE specific
179  shared_examples 'POST /projects/:id/members with the project group membership locked' do
180    context 'project in a group' do
181      it 'returns a 405 method not allowed error when group membership lock is enabled' do
182        group_with_membership_locked = create(:group, membership_lock: true)
183        project = create(:project, group: group_with_membership_locked)
184        project.group.add_owner(master)
185
186        post api("/projects/#{project.id}/members", master),
187             user_id: developer.id, access_level: Member::MASTER
188
189        expect(response.status).to eq 405
190      end
191    end
192  end
193  ## EE specific
194
195  shared_examples 'PUT /:sources/:id/members/:user_id' do |source_type|
196    context "with :sources == #{source_type.pluralize}" do
197      it_behaves_like 'a 404 response when source is private' do
198        let(:route) do
199          put api("/#{source_type.pluralize}/#{source.id}/members/#{developer.id}", stranger),
200              access_level: Member::MASTER
201        end
202      end
203
204      context 'when authenticated as a non-member or member with insufficient rights' do
205        %i[access_requester stranger developer].each do |type|
206          context "as a #{type}" do
207            it 'returns 403' do
208              user = public_send(type)
209              put api("/#{source_type.pluralize}/#{source.id}/members/#{developer.id}", user),
210                  access_level: Member::MASTER
211
212              expect(response).to have_http_status(403)
213            end
214          end
215        end
216      end
217
218      context 'when authenticated as a master/owner' do
219        it 'updates the member' do
220          put api("/#{source_type.pluralize}/#{source.id}/members/#{developer.id}", master),
221              access_level: Member::MASTER, expires_at: '2016-08-05'
222
223          expect(response).to have_http_status(200)
224          expect(json_response['id']).to eq(developer.id)
225          expect(json_response['access_level']).to eq(Member::MASTER)
226          expect(json_response['expires_at']).to eq('2016-08-05')
227        end
228      end
229
230      it 'returns 409 if member does not exist' do
231        put api("/#{source_type.pluralize}/#{source.id}/members/123", master),
232            access_level: Member::MASTER
233
234        expect(response).to have_http_status(404)
235      end
236
237      it 'returns 400 when access_level is not given' do
238        put api("/#{source_type.pluralize}/#{source.id}/members/#{developer.id}", master)
239
240        expect(response).to have_http_status(400)
241      end
242
243      it 'returns 422 when access level is not valid' do
244        put api("/#{source_type.pluralize}/#{source.id}/members/#{developer.id}", master),
245            access_level: 1234
246
247        expect(response).to have_http_status(422)
248      end
249    end
250  end
251
252  shared_examples 'DELETE /:sources/:id/members/:user_id' do |source_type|
253    context "with :sources == #{source_type.pluralize}" do
254      it_behaves_like 'a 404 response when source is private' do
255        let(:route) { delete api("/#{source_type.pluralize}/#{source.id}/members/#{developer.id}", stranger) }
256      end
257
258      context 'when authenticated as a non-member or member with insufficient rights' do
259        %i[access_requester stranger].each do |type|
260          context "as a #{type}" do
261            it 'returns 403' do
262              user = public_send(type)
263              delete api("/#{source_type.pluralize}/#{source.id}/members/#{developer.id}", user)
264
265              expect(response).to have_http_status(403)
266            end
267          end
268        end
269      end
270
271      context 'when authenticated as a member and deleting themself' do
272        it 'deletes the member' do
273          expect do
274            delete api("/#{source_type.pluralize}/#{source.id}/members/#{developer.id}", developer)
275
276            expect(response).to have_http_status(200)
277          end.to change { source.members.count }.by(-1)
278        end
279      end
280
281      context 'when authenticated as a master/owner' do
282        context 'and member is a requester' do
283          it "returns #{source_type == 'project' ? 200 : 404}" do
284            expect do
285              delete api("/#{source_type.pluralize}/#{source.id}/members/#{access_requester.id}", master)
286
287              expect(response).to have_http_status(source_type == 'project' ? 200 : 404)
288            end.not_to change { source.requesters.count }
289          end
290        end
291
292        it 'deletes the member' do
293          expect do
294            delete api("/#{source_type.pluralize}/#{source.id}/members/#{developer.id}", master)
295
296            expect(response).to have_http_status(200)
297          end.to change { source.members.count }.by(-1)
298        end
299      end
300
301      it "returns #{source_type == 'project' ? 200 : 404} if member does not exist" do
302        delete api("/#{source_type.pluralize}/#{source.id}/members/123", master)
303
304        expect(response).to have_http_status(source_type == 'project' ? 200 : 404)
305      end
306    end
307  end
308
309  it_behaves_like 'GET /:sources/:id/members', 'project' do
310    let(:source) { project }
311  end
312
313  it_behaves_like 'GET /:sources/:id/members', 'group' do
314    let(:source) { group }
315  end
316
317  it_behaves_like 'GET /:sources/:id/members/:user_id', 'project' do
318    let(:source) { project }
319  end
320
321  it_behaves_like 'GET /:sources/:id/members/:user_id', 'group' do
322    let(:source) { group }
323  end
324
325  it_behaves_like 'POST /:sources/:id/members', 'project' do
326    let(:source) { project }
327  end
328
329  ## EE specific
330  it_behaves_like 'POST /projects/:id/members with the project group membership locked'
331  ## EE specific
332
333  it_behaves_like 'POST /:sources/:id/members', 'group' do
334    let(:source) { group }
335  end
336
337  it_behaves_like 'PUT /:sources/:id/members/:user_id', 'project' do
338    let(:source) { project }
339  end
340
341  it_behaves_like 'PUT /:sources/:id/members/:user_id', 'group' do
342    let(:source) { group }
343  end
344
345  it_behaves_like 'DELETE /:sources/:id/members/:user_id', 'project' do
346    let(:source) { project }
347  end
348
349  it_behaves_like 'DELETE /:sources/:id/members/:user_id', 'group' do
350    let(:source) { group }
351  end
352
353  context 'Adding owner to project' do
354    it 'returns 403' do
355      expect do
356        post api("/projects/#{project.id}/members", master),
357             user_id: stranger.id, access_level: Member::OWNER
358
359        expect(response).to have_http_status(422)
360      end.to change { project.members.count }.by(0)
361    end
362  end
363end