BigW Consortium Gitlab

runners_spec.rb 14.9 KB
Newer Older
1 2
require 'spec_helper'

3
describe API::Runners, api: true  do
4 5 6 7 8
  include ApiHelpers

  let(:admin) { create(:user, :admin) }
  let(:user) { create(:user) }
  let(:user2) { create(:user) }
9 10 11 12

  let(:project) { create(:project, creator_id: user.id) }
  let(:project2) { create(:project, creator_id: user.id) }

13 14
  let!(:shared_runner) { create(:ci_runner, :shared) }
  let!(:unused_specific_runner) { create(:ci_runner) }
15 16

  let!(:specific_runner) do
17 18 19
    create(:ci_runner).tap do |runner|
      create(:ci_runner_project, runner: runner, project: project)
    end
20 21 22
  end

  let!(:two_projects_runner) do
23 24 25 26
    create(:ci_runner).tap do |runner|
      create(:ci_runner_project, runner: runner, project: project)
      create(:ci_runner_project, runner: runner, project: project2)
    end
27 28 29 30
  end

  before do
    # Set project access for users
31 32 33
    create(:project_member, :master, user: user, project: project)
    create(:project_member, :master, user: user, project: project2)
    create(:project_member, :reporter, user: user2, project: project)
34
  end
35 36

  describe 'GET /runners' do
37
    context 'authorized user' do
38 39
      it 'should return user available runners' do
        get api('/runners', user)
40
        shared = json_response.any?{ |r| r['is_shared'] }
41

42
        expect(response).to have_http_status(200)
43 44 45 46 47
        expect(json_response).to be_an Array
        expect(shared).to be_falsey
      end

      it 'should filter runners by scope' do
48
        get api('/runners?scope=active', user)
49
        shared = json_response.any?{ |r| r['is_shared'] }
50

51
        expect(response).to have_http_status(200)
52 53 54 55 56 57
        expect(json_response).to be_an Array
        expect(shared).to be_falsey
      end

      it 'should avoid filtering if scope is invalid' do
        get api('/runners?scope=unknown', user)
58
        expect(response).to have_http_status(400)
59 60 61 62 63 64 65
      end
    end

    context 'unauthorized user' do
      it 'should not return runners' do
        get api('/runners')

66
        expect(response).to have_http_status(401)
67 68 69 70 71 72 73
      end
    end
  end

  describe 'GET /runners/all' do
    context 'authorized user' do
      context 'with admin privileges' do
74
        it 'should return all runners' do
75
          get api('/runners/all', admin)
76
          shared = json_response.any?{ |r| r['is_shared'] }
77

78
          expect(response).to have_http_status(200)
79 80 81 82
          expect(json_response).to be_an Array
          expect(shared).to be_truthy
        end
      end
83

84 85 86
      context 'without admin privileges' do
        it 'should not return runners list' do
          get api('/runners/all', user)
87

88
          expect(response).to have_http_status(403)
89
        end
90 91 92
      end

      it 'should filter runners by scope' do
93
        get api('/runners/all?scope=specific', admin)
94
        shared = json_response.any?{ |r| r['is_shared'] }
95

96
        expect(response).to have_http_status(200)
97 98 99 100
        expect(json_response).to be_an Array
        expect(shared).to be_falsey
      end

101
      it 'should avoid filtering if scope is invalid' do
102
        get api('/runners?scope=unknown', admin)
103
        expect(response).to have_http_status(400)
104 105 106 107 108 109 110
      end
    end

    context 'unauthorized user' do
      it 'should not return runners' do
        get api('/runners')

111
        expect(response).to have_http_status(401)
112 113 114 115 116 117
      end
    end
  end

  describe 'GET /runners/:id' do
    context 'admin user' do
118 119 120
      context 'when runner is shared' do
        it "should return runner's details" do
          get api("/runners/#{shared_runner.id}", admin)
121

122
          expect(response).to have_http_status(200)
123 124
          expect(json_response['description']).to eq(shared_runner.description)
        end
125 126
      end

127 128 129
      context 'when runner is not shared' do
        it "should return runner's details" do
          get api("/runners/#{specific_runner.id}", admin)
130

131
          expect(response).to have_http_status(200)
132 133
          expect(json_response['description']).to eq(specific_runner.description)
        end
134 135 136 137 138
      end

      it 'should return 404 if runner does not exists' do
        get api('/runners/9999', admin)

139
        expect(response).to have_http_status(404)
140 141 142 143
      end
    end

    context "runner project's administrative user" do
144 145 146
      context 'when runner is not shared' do
        it "should return runner's details" do
          get api("/runners/#{specific_runner.id}", user)
147

148
          expect(response).to have_http_status(200)
149 150
          expect(json_response['description']).to eq(specific_runner.description)
        end
151 152
      end

153 154 155
      context 'when runner is shared' do
        it "should return runner's details" do
          get api("/runners/#{shared_runner.id}", user)
156

157
          expect(response).to have_http_status(200)
158 159
          expect(json_response['description']).to eq(shared_runner.description)
        end
160 161 162 163 164 165 166
      end
    end

    context 'other authorized user' do
      it "should not return runner's details" do
        get api("/runners/#{specific_runner.id}", user2)

167
        expect(response).to have_http_status(403)
168 169 170 171 172 173 174
      end
    end

    context 'unauthorized user' do
      it "should not return runner's details" do
        get api("/runners/#{specific_runner.id}")

175
        expect(response).to have_http_status(401)
176 177 178 179 180 181
      end
    end
  end

  describe 'PUT /runners/:id' do
    context 'admin user' do
182 183 184 185
      context 'when runner is shared' do
        it 'should update runner' do
          description = shared_runner.description
          active = shared_runner.active
186

187 188 189
          update_runner(shared_runner.id, admin, description: "#{description}_updated",
                                                 active: !active,
                                                 tag_list: ['ruby2.1', 'pgsql', 'mysql'],
190 191
                                                 run_untagged: 'false',
                                                 locked: 'true')
192
          shared_runner.reload
193

194
          expect(response).to have_http_status(200)
195 196 197
          expect(shared_runner.description).to eq("#{description}_updated")
          expect(shared_runner.active).to eq(!active)
          expect(shared_runner.tag_list).to include('ruby2.1', 'pgsql', 'mysql')
198 199
          expect(shared_runner.run_untagged?).to be(false)
          expect(shared_runner.locked?).to be(true)
200
        end
201 202
      end

203 204 205
      context 'when runner is not shared' do
        it 'should update runner' do
          description = specific_runner.description
206
          update_runner(specific_runner.id, admin, description: 'test')
207
          specific_runner.reload
208

209
          expect(response).to have_http_status(200)
210 211 212
          expect(specific_runner.description).to eq('test')
          expect(specific_runner.description).not_to eq(description)
        end
213 214 215
      end

      it 'should return 404 if runner does not exists' do
216
        update_runner(9999, admin, description: 'test')
217

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

      def update_runner(id, user, args)
        put api("/runners/#{id}", user), args
      end
224 225 226
    end

    context 'authorized user' do
227 228
      context 'when runner is shared' do
        it 'should not update runner' do
229
          put api("/runners/#{shared_runner.id}", user)
230

231
          expect(response).to have_http_status(403)
232
        end
233 234
      end

235 236
      context 'when runner is not shared' do
        it 'should not update runner without access to it' do
237
          put api("/runners/#{specific_runner.id}", user2)
238

239
          expect(response).to have_http_status(403)
240
        end
241

242 243 244 245
        it 'should update runner with access to it' do
          description = specific_runner.description
          put api("/runners/#{specific_runner.id}", admin), description: 'test'
          specific_runner.reload
246

247
          expect(response).to have_http_status(200)
248 249 250
          expect(specific_runner.description).to eq('test')
          expect(specific_runner.description).not_to eq(description)
        end
251 252 253 254 255
      end
    end

    context 'unauthorized user' do
      it 'should not delete runner' do
256
        put api("/runners/#{specific_runner.id}")
257

258
        expect(response).to have_http_status(401)
259 260 261 262 263 264
      end
    end
  end

  describe 'DELETE /runners/:id' do
    context 'admin user' do
265 266 267 268 269
      context 'when runner is shared' do
        it 'should delete runner' do
          expect do
            delete api("/runners/#{shared_runner.id}", admin)
          end.to change{ Ci::Runner.shared.count }.by(-1)
270
          expect(response).to have_http_status(200)
271
        end
272 273
      end

274 275 276 277 278
      context 'when runner is not shared' do
        it 'should delete unused runner' do
          expect do
            delete api("/runners/#{unused_specific_runner.id}", admin)
          end.to change{ Ci::Runner.specific.count }.by(-1)
279
          expect(response).to have_http_status(200)
280
        end
281

282 283 284 285
        it 'should delete used runner' do
          expect do
            delete api("/runners/#{specific_runner.id}", admin)
          end.to change{ Ci::Runner.specific.count }.by(-1)
286
          expect(response).to have_http_status(200)
287
        end
288 289 290 291 292
      end

      it 'should return 404 if runner does not exists' do
        delete api('/runners/9999', admin)

293
        expect(response).to have_http_status(404)
294 295 296 297
      end
    end

    context 'authorized user' do
298 299 300
      context 'when runner is shared' do
        it 'should not delete runner' do
          delete api("/runners/#{shared_runner.id}", user)
301
          expect(response).to have_http_status(403)
302
        end
303 304
      end

305 306 307
      context 'when runner is not shared' do
        it 'should not delete runner without access to it' do
          delete api("/runners/#{specific_runner.id}", user2)
308
          expect(response).to have_http_status(403)
309
        end
310

311 312
        it 'should not delete runner with more than one associated project' do
          delete api("/runners/#{two_projects_runner.id}", user)
313
          expect(response).to have_http_status(403)
314
        end
315

316 317 318 319
        it 'should delete runner for one owned project' do
          expect do
            delete api("/runners/#{specific_runner.id}", user)
          end.to change{ Ci::Runner.specific.count }.by(-1)
320
          expect(response).to have_http_status(200)
321
        end
322 323 324 325 326 327 328
      end
    end

    context 'unauthorized user' do
      it 'should not delete runner' do
        delete api("/runners/#{specific_runner.id}")

329
        expect(response).to have_http_status(401)
330 331 332 333 334 335 336 337
      end
    end
  end

  describe 'GET /projects/:id/runners' do
    context 'authorized user with master privileges' do
      it "should return project's runners" do
        get api("/projects/#{project.id}/runners", user)
338
        shared = json_response.any?{ |r| r['is_shared'] }
339

340
        expect(response).to have_http_status(200)
341 342 343 344 345 346 347 348 349
        expect(json_response).to be_an Array
        expect(shared).to be_truthy
      end
    end

    context 'authorized user without master privileges' do
      it "should not return project's runners" do
        get api("/projects/#{project.id}/runners", user2)

350
        expect(response).to have_http_status(403)
351 352 353 354 355 356 357
      end
    end

    context 'unauthorized user' do
      it "should not return project's runners" do
        get api("/projects/#{project.id}/runners")

358
        expect(response).to have_http_status(401)
359 360 361
      end
    end
  end
362

363
  describe 'POST /projects/:id/runners' do
364
    context 'authorized user' do
365 366
      let(:specific_runner2) do
        create(:ci_runner).tap do |runner|
367 368
          create(:ci_runner_project, runner: runner, project: project2)
        end
369
      end
370

371
      it 'should enable specific runner' do
372
        expect do
373
          post api("/projects/#{project.id}/runners", user), runner_id: specific_runner2.id
374
        end.to change{ project.runners.count }.by(+1)
375
        expect(response).to have_http_status(201)
376 377 378 379
      end

      it 'should avoid changes when enabling already enabled runner' do
        expect do
380
          post api("/projects/#{project.id}/runners", user), runner_id: specific_runner.id
381
        end.to change{ project.runners.count }.by(0)
382
        expect(response).to have_http_status(409)
383 384
      end

385 386 387 388 389 390 391
      it 'should not enable locked runner' do
        specific_runner2.update(locked: true)

        expect do
          post api("/projects/#{project.id}/runners", user), runner_id: specific_runner2.id
        end.to change{ project.runners.count }.by(0)

392
        expect(response).to have_http_status(403)
393 394
      end

395
      it 'should not enable shared runner' do
396
        post api("/projects/#{project.id}/runners", user), runner_id: shared_runner.id
397

398
        expect(response).to have_http_status(403)
399 400 401 402 403
      end

      context 'user is admin' do
        it 'should enable any specific runner' do
          expect do
404
            post api("/projects/#{project.id}/runners", admin), runner_id: unused_specific_runner.id
405
          end.to change{ project.runners.count }.by(+1)
406
          expect(response).to have_http_status(201)
407 408 409 410 411
        end
      end

      context 'user is not admin' do
        it 'should not enable runner without access to' do
412
          post api("/projects/#{project.id}/runners", user), runner_id: unused_specific_runner.id
413

414
          expect(response).to have_http_status(403)
415 416
        end
      end
417 418 419 420

      it 'should raise an error when no runner_id param is provided' do
        post api("/projects/#{project.id}/runners", admin)

421
        expect(response).to have_http_status(400)
422
      end
423 424 425 426
    end

    context 'authorized user without permissions' do
      it 'should not enable runner' do
427
        post api("/projects/#{project.id}/runners", user2)
428

429
        expect(response).to have_http_status(403)
430 431 432 433 434
      end
    end

    context 'unauthorized user' do
      it 'should not enable runner' do
435
        post api("/projects/#{project.id}/runners")
436

437
        expect(response).to have_http_status(401)
438 439 440 441 442 443 444 445 446 447 448
      end
    end
  end

  describe 'DELETE /projects/:id/runners/:runner_id' do
    context 'authorized user' do
      context 'when runner have more than one associated projects' do
        it "should disable project's runner" do
          expect do
            delete api("/projects/#{project.id}/runners/#{two_projects_runner.id}", user)
          end.to change{ project.runners.count }.by(-1)
449
          expect(response).to have_http_status(200)
450 451 452 453 454 455 456 457
        end
      end

      context 'when runner have one associated projects' do
        it "should not disable project's runner" do
          expect do
            delete api("/projects/#{project.id}/runners/#{specific_runner.id}", user)
          end.to change{ project.runners.count }.by(0)
458
          expect(response).to have_http_status(403)
459 460 461 462 463 464
        end
      end

      it 'should return 404 is runner is not found' do
        delete api("/projects/#{project.id}/runners/9999", user)

465
        expect(response).to have_http_status(404)
466 467 468 469 470 471 472
      end
    end

    context 'authorized user without permissions' do
      it "should not disable project's runner" do
        delete api("/projects/#{project.id}/runners/#{specific_runner.id}", user2)

473
        expect(response).to have_http_status(403)
474 475 476 477 478 479 480
      end
    end

    context 'unauthorized user' do
      it "should not disable project's runner" do
        delete api("/projects/#{project.id}/runners/#{specific_runner.id}")

481
        expect(response).to have_http_status(401)
482 483 484
      end
    end
  end
485
end