BigW Consortium Gitlab

builds_spec.rb 11.2 KB
Newer Older
1 2
require 'spec_helper'

3
describe Ci::API::API do
4 5
  include ApiHelpers

6 7
  let(:runner) { FactoryGirl.create(:ci_runner, tag_list: ["mysql", "ruby"]) }
  let(:project) { FactoryGirl.create(:ci_project) }
Kamil Trzcinski committed
8
  let(:gl_project) { project.gl_project }
9

10 11 12 13
  before do
    stub_ci_commit_to_return_yaml_file
  end

14
  describe "Builds API for runners" do
15 16
    let(:shared_runner) { FactoryGirl.create(:ci_runner, token: "SharedRunner") }
    let(:shared_project) { FactoryGirl.create(:ci_project, name: "SharedProject") }
Kamil Trzcinski committed
17
    let(:shared_gl_project) { shared_project.gl_project }
18 19

    before do
Valery Sizov committed
20
      FactoryGirl.create :ci_runner_project, project_id: project.id, runner_id: runner.id
21 22 23 24
    end

    describe "POST /builds/register" do
      it "should start a build" do
Kamil Trzcinski committed
25
        commit = FactoryGirl.create(:ci_commit, gl_project: gl_project)
26
        commit.create_builds('master', false, nil)
27 28
        build = commit.builds.first

Valery Sizov committed
29
        post ci_api("/builds/register"), token: runner.token, info: { platform: :darwin }
30

31 32 33
        expect(response.status).to eq(201)
        expect(json_response['sha']).to eq(build.sha)
        expect(runner.reload.platform).to eq("darwin")
34 35 36
      end

      it "should return 404 error if no pending build found" do
Valery Sizov committed
37
        post ci_api("/builds/register"), token: runner.token
38

39
        expect(response.status).to eq(404)
40 41 42
      end

      it "should return 404 error if no builds for specific runner" do
Kamil Trzcinski committed
43
        commit = FactoryGirl.create(:ci_commit, gl_project: shared_gl_project)
44
        FactoryGirl.create(:ci_build, commit: commit, status: 'pending')
45

Valery Sizov committed
46
        post ci_api("/builds/register"), token: runner.token
47

48
        expect(response.status).to eq(404)
49 50 51
      end

      it "should return 404 error if no builds for shared runner" do
Kamil Trzcinski committed
52
        commit = FactoryGirl.create(:ci_commit, gl_project: gl_project)
53
        FactoryGirl.create(:ci_build, commit: commit, status: 'pending')
54

Valery Sizov committed
55
        post ci_api("/builds/register"), token: shared_runner.token
56

57
        expect(response.status).to eq(404)
58 59 60
      end

      it "returns options" do
Kamil Trzcinski committed
61
        commit = FactoryGirl.create(:ci_commit, gl_project: gl_project)
62
        commit.create_builds('master', false, nil)
63

Valery Sizov committed
64
        post ci_api("/builds/register"), token: runner.token, info: { platform: :darwin }
65

66
        expect(response.status).to eq(201)
Valery Sizov committed
67
        expect(json_response["options"]).to eq({ "image" => "ruby:2.1", "services" => ["postgres"] })
68 69 70
      end

      it "returns variables" do
Kamil Trzcinski committed
71
        commit = FactoryGirl.create(:ci_commit, gl_project: gl_project)
72
        commit.create_builds('master', false, nil)
Valery Sizov committed
73
        project.variables << Ci::Variable.new(key: "SECRET_KEY", value: "secret_value")
74

Valery Sizov committed
75
        post ci_api("/builds/register"), token: runner.token, info: { platform: :darwin }
76

77 78
        expect(response.status).to eq(201)
        expect(json_response["variables"]).to eq([
79 80
          { "key" => "CI_BUILD_NAME", "value" => "spinach", "public" => true },
          { "key" => "CI_BUILD_STAGE", "value" => "test", "public" => true },
Valery Sizov committed
81
          { "key" => "DB_NAME", "value" => "postgres", "public" => true },
82
          { "key" => "SECRET_KEY", "value" => "secret_value", "public" => false }
83
        ])
84 85 86
      end

      it "returns variables for triggers" do
87
        trigger = FactoryGirl.create(:ci_trigger, project: project)
Kamil Trzcinski committed
88
        commit = FactoryGirl.create(:ci_commit, gl_project: gl_project)
89

90
        trigger_request = FactoryGirl.create(:ci_trigger_request_with_variables, commit: commit, trigger: trigger)
91
        commit.create_builds('master', false, nil, trigger_request)
Valery Sizov committed
92
        project.variables << Ci::Variable.new(key: "SECRET_KEY", value: "secret_value")
93

Valery Sizov committed
94
        post ci_api("/builds/register"), token: runner.token, info: { platform: :darwin }
95

96 97
        expect(response.status).to eq(201)
        expect(json_response["variables"]).to eq([
98 99 100
          { "key" => "CI_BUILD_NAME", "value" => "spinach", "public" => true },
          { "key" => "CI_BUILD_STAGE", "value" => "test", "public" => true },
          { "key" => "CI_BUILD_TRIGGERED", "value" => "true", "public" => true },
Valery Sizov committed
101 102 103
          { "key" => "DB_NAME", "value" => "postgres", "public" => true },
          { "key" => "SECRET_KEY", "value" => "secret_value", "public" => false },
          { "key" => "TRIGGER_KEY", "value" => "TRIGGER_VALUE", "public" => false },
104
        ])
105 106 107 108
      end
    end

    describe "PUT /builds/:id" do
Kamil Trzcinski committed
109
      let(:commit) { FactoryGirl.create(:ci_commit, gl_project: gl_project)}
110
      let(:build) { FactoryGirl.create(:ci_build, commit: commit, runner_id: runner.id) }
111 112 113

      it "should update a running build" do
        build.run!
Valery Sizov committed
114
        put ci_api("/builds/#{build.id}"), token: runner.token
115
        expect(response.status).to eq(200)
116 117 118 119 120
      end

      it 'Should not override trace information when no trace is given' do
        build.run!
        build.update!(trace: 'hello_world')
Valery Sizov committed
121
        put ci_api("/builds/#{build.id}"), token: runner.token
122 123 124
        expect(build.reload.trace).to eq 'hello_world'
      end
    end
125 126 127 128 129 130 131 132 133 134

    context "Artifacts" do
      let(:file_upload) { fixture_file_upload(Rails.root + 'spec/fixtures/banana_sample.gif', 'image/gif') }
      let(:file_upload2) { fixture_file_upload(Rails.root + 'spec/fixtures/dk.png', 'image/gif') }
      let(:commit) { FactoryGirl.create(:ci_commit, gl_project: gl_project) }
      let(:build) { FactoryGirl.create(:ci_build, commit: commit, runner_id: runner.id) }
      let(:authorize_url) { ci_api("/builds/#{build.id}/artifacts/authorize") }
      let(:post_url) { ci_api("/builds/#{build.id}/artifacts") }
      let(:delete_url) { ci_api("/builds/#{build.id}/artifacts") }
      let(:get_url) { ci_api("/builds/#{build.id}/artifacts") }
135
      let(:headers) { { "GitLab-Workhorse" => "1.0" } }
136 137 138 139 140 141 142 143 144 145 146
      let(:headers_with_token) { headers.merge(Ci::API::Helpers::BUILD_TOKEN_HEADER => build.project.token) }

      describe "POST /builds/:id/artifacts/authorize" do
        context "should authorize posting artifact to running build" do
          before do
            build.run!
          end

          it "using token as parameter" do
            post authorize_url, { token: build.project.token }, headers
            expect(response.status).to eq(200)
Kamil Trzcinski committed
147
            expect(json_response["TempPath"]).to_not be_nil
148 149 150 151 152
          end

          it "using token as header" do
            post authorize_url, {}, headers_with_token
            expect(response.status).to eq(200)
Kamil Trzcinski committed
153
            expect(json_response["TempPath"]).to_not be_nil
154 155 156 157 158 159 160 161 162
          end
        end

        context "should fail to post too large artifact" do
          before do
            build.run!
          end

          it "using token as parameter" do
163
            stub_application_setting(max_artifacts_size: 0)
164 165 166 167 168
            post authorize_url, { token: build.project.token, filesize: 100 }, headers
            expect(response.status).to eq(413)
          end

          it "using token as header" do
169
            stub_application_setting(max_artifacts_size: 0)
170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194
            post authorize_url, { filesize: 100 }, headers_with_token
            expect(response.status).to eq(413)
          end
        end

        context "should get denied" do
          it do
            post authorize_url, { token: 'invalid', filesize: 100 }
            expect(response.status).to eq(403)
          end
        end
      end

      describe "POST /builds/:id/artifacts" do
        context "Disable sanitizer" do
          before do
            # by configuring this path we allow to pass temp file from any path
            allow(ArtifactUploader).to receive(:artifacts_upload_path).and_return('/')
          end

          context "should post artifact to running build" do
            before do
              build.run!
            end

195 196 197 198 199 200 201 202
            it "uses regual file post" do
              upload_artifacts(file_upload, headers_with_token, false)
              expect(response.status).to eq(201)
              expect(json_response["artifacts_file"]["filename"]).to eq(file_upload.original_filename)
            end

            it "uses accelerated file post" do
              upload_artifacts(file_upload, headers_with_token, true)
203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220
              expect(response.status).to eq(201)
              expect(json_response["artifacts_file"]["filename"]).to eq(file_upload.original_filename)
            end

            it "updates artifact" do
              upload_artifacts(file_upload, headers_with_token)
              upload_artifacts(file_upload2, headers_with_token)
              expect(response.status).to eq(201)
              expect(json_response["artifacts_file"]["filename"]).to eq(file_upload2.original_filename)
            end
          end

          context "should fail to post too large artifact" do
            before do
              build.run!
            end

            it do
221
              stub_application_setting(max_artifacts_size: 0)
222 223 224 225 226 227 228 229 230 231 232 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 266 267 268
              upload_artifacts(file_upload, headers_with_token)
              expect(response.status).to eq(413)
            end
          end

          context "should fail to post artifacts without file" do
            before do
              build.run!
            end

            it do
              post post_url, {}, headers_with_token
              expect(response.status).to eq(400)
            end
          end

          context "should fail to post artifacts without GitLab-Workhorse" do
            before do
              build.run!
            end

            it do
              post post_url, { token: build.project.token }, {}
              expect(response.status).to eq(403)
            end
          end
        end

        context "should fail to post artifacts for outside of tmp path" do
          before do
            # by configuring this path we allow to pass file from @tmpdir only
            # but all temporary files are stored in system tmp directory
            @tmpdir = Dir.mktmpdir
            allow(ArtifactUploader).to receive(:artifacts_upload_path).and_return(@tmpdir)
            build.run!
          end

          after do
            FileUtils.remove_entry @tmpdir
          end

          it do
            upload_artifacts(file_upload, headers_with_token)
            expect(response.status).to eq(400)
          end
        end

269 270 271 272 273 274 275 276 277
        def upload_artifacts(file, headers = {}, accelerated = true)
          if accelerated
            post post_url, {
              'file.path' => file.path,
              'file.name' => file.original_filename
            }, headers
          else
            post post_url, { file: file }, headers
          end
278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310
        end
      end

      describe "DELETE /builds/:id/artifacts" do
        before do
          build.run!
          post delete_url, token: build.project.token, file: file_upload
        end

        it "should delete artifact build" do
          build.success
          delete delete_url, token: build.project.token
          expect(response.status).to eq(200)
        end
      end

      describe "GET /builds/:id/artifacts" do
        before do
          build.run!
        end

        it "should download artifact" do
          build.update_attributes(artifacts_file: file_upload)
          get get_url, token: build.project.token
          expect(response.status).to eq(200)
        end

        it "should fail to download if no artifact uploaded" do
          get get_url, token: build.project.token
          expect(response.status).to eq(404)
        end
      end
    end
311 312
  end
end