BigW Consortium Gitlab

commit_spec.rb 14 KB
Newer Older
Robert Speicher committed
1 2 3
require "spec_helper"

describe Gitlab::Git::Commit, seed_helper: true do
4
  let(:repository) { Gitlab::Git::Repository.new('default', TEST_REPO_PATH, '') }
5
  let(:commit) { described_class.find(repository, SeedRepo::Commit::ID) }
Robert Speicher committed
6 7 8 9 10 11
  let(:rugged_commit) do
    repository.rugged.lookup(SeedRepo::Commit::ID)
  end

  describe "Commit info" do
    before do
12
      repo = Gitlab::Git::Repository.new('default', TEST_REPO_PATH, '').rugged
Robert Speicher committed
13 14 15 16 17 18 19 20 21 22 23 24 25 26

      @committer = {
        email: 'mike@smith.com',
        name: "Mike Smith",
        time: Time.now
      }

      @author = {
        email: 'john@smith.com',
        name: "John Smith",
        time: Time.now
      }

      @parents = [repo.head.target]
27
      @gitlab_parents = @parents.map { |c| described_class.decorate(repository, c) }
Robert Speicher committed
28 29 30 31 32 33 34 35 36 37 38 39 40
      @tree = @parents.first.tree

      sha = Rugged::Commit.create(
        repo,
        author: @author,
        committer: @committer,
        tree: @tree,
        parents: @parents,
        message: "Refactoring specs",
        update_ref: "HEAD"
      )

      @raw_commit = repo.lookup(sha)
41
      @commit = described_class.new(repository, @raw_commit)
Robert Speicher committed
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
    end

    it { expect(@commit.short_id).to eq(@raw_commit.oid[0..10]) }
    it { expect(@commit.id).to eq(@raw_commit.oid) }
    it { expect(@commit.sha).to eq(@raw_commit.oid) }
    it { expect(@commit.safe_message).to eq(@raw_commit.message) }
    it { expect(@commit.created_at).to eq(@raw_commit.author[:time]) }
    it { expect(@commit.date).to eq(@raw_commit.committer[:time]) }
    it { expect(@commit.author_email).to eq(@author[:email]) }
    it { expect(@commit.author_name).to eq(@author[:name]) }
    it { expect(@commit.committer_name).to eq(@committer[:name]) }
    it { expect(@commit.committer_email).to eq(@committer[:email]) }
    it { expect(@commit.different_committer?).to be_truthy }
    it { expect(@commit.parents).to eq(@gitlab_parents) }
    it { expect(@commit.parent_id).to eq(@parents.first.oid) }
    it { expect(@commit.no_commit_message).to eq("--no commit message") }
    it { expect(@commit.tree).to eq(@tree) }

    after do
      # Erase the new commit so other tests get the original repo
62
      repo = Gitlab::Git::Repository.new('default', TEST_REPO_PATH, '').rugged
Robert Speicher committed
63 64 65 66
      repo.references.update("refs/heads/master", SeedRepo::LastCommit::ID)
    end
  end

67 68
  describe "Commit info from gitaly commit" do
    let(:subject) { "My commit".force_encoding('ASCII-8BIT') }
69
    let(:body) { subject + "My body".force_encoding('ASCII-8BIT') }
70 71 72 73
    let(:gitaly_commit) { build(:gitaly_commit, subject: subject, body: body) }
    let(:id) { gitaly_commit.id }
    let(:committer) { gitaly_commit.committer }
    let(:author) { gitaly_commit.author }
74
    let(:commit) { described_class.new(repository, gitaly_commit) }
75 76 77 78

    it { expect(commit.short_id).to eq(id[0..10]) }
    it { expect(commit.id).to eq(id) }
    it { expect(commit.sha).to eq(id) }
79
    it { expect(commit.safe_message).to eq(body) }
80 81 82 83 84
    it { expect(commit.created_at).to eq(Time.at(committer.date.seconds)) }
    it { expect(commit.author_email).to eq(author.email) }
    it { expect(commit.author_name).to eq(author.name) }
    it { expect(commit.committer_name).to eq(committer.name) }
    it { expect(commit.committer_email).to eq(committer.email) }
85
    it { expect(commit.parent_ids).to eq(gitaly_commit.parent_ids) }
86 87 88 89 90 91

    context 'no body' do
      let(:body) { "".force_encoding('ASCII-8BIT') }

      it { expect(commit.safe_message).to eq(subject) }
    end
92 93
  end

Robert Speicher committed
94
  context 'Class methods' do
95
    describe '.find' do
Robert Speicher committed
96
      it "should return first head commit if without params" do
97
        expect(described_class.last(repository).id).to eq(
98
          repository.rugged.head.target.oid
Robert Speicher committed
99 100 101 102
        )
      end

      it "should return valid commit" do
103
        expect(described_class.find(repository, SeedRepo::Commit::ID)).to be_valid_commit
Robert Speicher committed
104 105 106
      end

      it "should return valid commit for tag" do
107
        expect(described_class.find(repository, 'v1.0.0').id).to eq('6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9')
Robert Speicher committed
108 109 110 111
      end

      it "should return nil for non-commit ids" do
        blob = Gitlab::Git::Blob.find(repository, SeedRepo::Commit::ID, "files/ruby/popen.rb")
112
        expect(described_class.find(repository, blob.id)).to be_nil
Robert Speicher committed
113 114 115 116
      end

      it "should return nil for parent of non-commit object" do
        blob = Gitlab::Git::Blob.find(repository, SeedRepo::Commit::ID, "files/ruby/popen.rb")
117
        expect(described_class.find(repository, "#{blob.id}^")).to be_nil
Robert Speicher committed
118 119 120
      end

      it "should return nil for nonexisting ids" do
121
        expect(described_class.find(repository, "+123_4532530XYZ")).to be_nil
Robert Speicher committed
122 123 124
      end

      context 'with broken repo' do
125
        let(:repository) { Gitlab::Git::Repository.new('default', TEST_BROKEN_REPO_PATH, '') }
Robert Speicher committed
126 127

        it 'returns nil' do
128
          expect(described_class.find(repository, SeedRepo::Commit::ID)).to be_nil
Robert Speicher committed
129 130 131 132
        end
      end
    end

133
    describe '.last_for_path' do
Robert Speicher committed
134
      context 'no path' do
135
        subject { described_class.last_for_path(repository, 'master') }
Robert Speicher committed
136 137 138 139 140 141 142 143

        describe '#id' do
          subject { super().id }
          it { is_expected.to eq(SeedRepo::LastCommit::ID) }
        end
      end

      context 'path' do
144
        subject { described_class.last_for_path(repository, 'master', 'files/ruby') }
Robert Speicher committed
145 146 147 148 149 150 151 152

        describe '#id' do
          subject { super().id }
          it { is_expected.to eq(SeedRepo::Commit::ID) }
        end
      end

      context 'ref + path' do
153
        subject { described_class.last_for_path(repository, SeedRepo::Commit::ID, 'encoding') }
Robert Speicher committed
154 155 156 157 158 159 160 161

        describe '#id' do
          subject { super().id }
          it { is_expected.to eq(SeedRepo::BigCommit::ID) }
        end
      end
    end

162
    shared_examples '.where' do
Robert Speicher committed
163 164
      context 'path is empty string' do
        subject do
165
          commits = described_class.where(
Robert Speicher committed
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182
            repo: repository,
            ref: 'master',
            path: '',
            limit: 10
          )

          commits.map { |c| c.id }
        end

        it 'has 10 elements' do
          expect(subject.size).to eq(10)
        end
        it { is_expected.to include(SeedRepo::EmptyCommit::ID) }
      end

      context 'path is nil' do
        subject do
183
          commits = described_class.where(
Robert Speicher committed
184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
            repo: repository,
            ref: 'master',
            path: nil,
            limit: 10
          )

          commits.map { |c| c.id }
        end

        it 'has 10 elements' do
          expect(subject.size).to eq(10)
        end
        it { is_expected.to include(SeedRepo::EmptyCommit::ID) }
      end

      context 'ref is branch name' do
        subject do
201
          commits = described_class.where(
Robert Speicher committed
202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220
            repo: repository,
            ref: 'master',
            path: 'files',
            limit: 3,
            offset: 1
          )

          commits.map { |c| c.id }
        end

        it 'has 3 elements' do
          expect(subject.size).to eq(3)
        end
        it { is_expected.to include("d14d6c0abdd253381df51a723d58691b2ee1ab08") }
        it { is_expected.not_to include("eb49186cfa5c4338011f5f590fac11bd66c5c631") }
      end

      context 'ref is commit id' do
        subject do
221
          commits = described_class.where(
Robert Speicher committed
222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240
            repo: repository,
            ref: "874797c3a73b60d2187ed6e2fcabd289ff75171e",
            path: 'files',
            limit: 3,
            offset: 1
          )

          commits.map { |c| c.id }
        end

        it 'has 3 elements' do
          expect(subject.size).to eq(3)
        end
        it { is_expected.to include("2f63565e7aac07bcdadb654e253078b727143ec4") }
        it { is_expected.not_to include(SeedRepo::Commit::ID) }
      end

      context 'ref is tag' do
        subject do
241
          commits = described_class.where(
Robert Speicher committed
242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259
            repo: repository,
            ref: 'v1.0.0',
            path: 'files',
            limit: 3,
            offset: 1
          )

          commits.map { |c| c.id }
        end

        it 'has 3 elements' do
          expect(subject.size).to eq(3)
        end
        it { is_expected.to include("874797c3a73b60d2187ed6e2fcabd289ff75171e") }
        it { is_expected.not_to include(SeedRepo::Commit::ID) }
      end
    end

260 261 262 263
    describe '.where with gitaly' do
      it_should_behave_like '.where'
    end

264
    describe '.where without gitaly', :skip_gitaly_mock do
265 266 267
      it_should_behave_like '.where'
    end

268
    describe '.between' do
Robert Speicher committed
269
      subject do
270
        commits = described_class.between(repository, SeedRepo::Commit::PARENT_ID, SeedRepo::Commit::ID)
Robert Speicher committed
271 272 273 274 275 276 277 278 279 280
        commits.map { |c| c.id }
      end

      it 'has 1 element' do
        expect(subject.size).to eq(1)
      end
      it { is_expected.to include(SeedRepo::Commit::ID) }
      it { is_expected.not_to include(SeedRepo::FirstCommit::ID) }
    end

281
    describe '.find_all' do
282 283 284
      shared_examples 'finding all commits' do
        it 'should return a return a collection of commits' do
          commits = described_class.find_all(repository)
285

286
          expect(commits).to all( be_a_kind_of(described_class) )
287 288
        end

289 290
        context 'max_count' do
          subject do
291
            commits = described_class.find_all(
292 293 294 295 296 297 298
              repository,
              max_count: 50
            )

            commits.map(&:id)
          end

299 300
          it 'has 34 elements' do
            expect(subject.size).to eq(34)
301 302 303 304 305 306 307 308 309
          end

          it 'includes the expected commits' do
            expect(subject).to include(
              SeedRepo::Commit::ID,
              SeedRepo::Commit::PARENT_ID,
              SeedRepo::FirstCommit::ID
            )
          end
310 311
        end

312 313
        context 'ref + max_count + skip' do
          subject do
314
            commits = described_class.find_all(
315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331
              repository,
              ref: 'master',
              max_count: 50,
              skip: 1
            )

            commits.map(&:id)
          end

          it 'has 24 elements' do
            expect(subject.size).to eq(24)
          end

          it 'includes the expected commits' do
            expect(subject).to include(SeedRepo::Commit::ID, SeedRepo::FirstCommit::ID)
            expect(subject).not_to include(SeedRepo::LastCommit::ID)
          end
332 333 334
        end
      end

335 336 337
      context 'when Gitaly find_all_commits feature is enabled' do
        it_behaves_like 'finding all commits'
      end
Robert Speicher committed
338

339
      context 'when Gitaly find_all_commits feature is disabled', :skip_gitaly_mock do
340
        it_behaves_like 'finding all commits'
Robert Speicher committed
341

342 343 344
        context 'while applying a sort order based on the `order` option' do
          it "allows ordering topologically (no parents shown before their children)" do
            expect_any_instance_of(Rugged::Walker).to receive(:sorting).with(Rugged::SORT_TOPO)
Robert Speicher committed
345

346 347
            described_class.find_all(repository, order: :topo)
          end
Robert Speicher committed
348

349 350 351 352 353 354 355 356
          it "allows ordering by date" do
            expect_any_instance_of(Rugged::Walker).to receive(:sorting).with(Rugged::SORT_DATE | Rugged::SORT_TOPO)

            described_class.find_all(repository, order: :date)
          end

          it "applies no sorting by default" do
            expect_any_instance_of(Rugged::Walker).to receive(:sorting).with(Rugged::SORT_NONE)
Robert Speicher committed
357

358 359
            described_class.find_all(repository)
          end
Robert Speicher committed
360 361 362 363 364
        end
      end
    end
  end

365
  describe '#init_from_rugged' do
366
    let(:gitlab_commit) { described_class.new(repository, rugged_commit) }
Robert Speicher committed
367 368 369 370 371 372 373 374
    subject { gitlab_commit }

    describe '#id' do
      subject { super().id }
      it { is_expected.to eq(SeedRepo::Commit::ID) }
    end
  end

375
  describe '#init_from_hash' do
376
    let(:commit) { described_class.new(repository, sample_commit_hash) }
Robert Speicher committed
377 378 379 380 381 382 383 384 385 386 387 388 389
    subject { commit }

    describe '#id' do
      subject { super().id }
      it { is_expected.to eq(sample_commit_hash[:id])}
    end

    describe '#message' do
      subject { super().message }
      it { is_expected.to eq(sample_commit_hash[:message])}
    end
  end

390
  shared_examples '#stats' do
Robert Speicher committed
391 392 393 394 395 396 397 398 399 400 401 402 403
    subject { commit.stats }

    describe '#additions' do
      subject { super().additions }
      it { is_expected.to eq(11) }
    end

    describe '#deletions' do
      subject { super().deletions }
      it { is_expected.to eq(6) }
    end
  end

404 405 406 407
  describe '#stats with gitaly on' do
    it_should_behave_like '#stats'
  end

408
  describe '#stats with gitaly disabled', :skip_gitaly_mock do
409 410 411
    it_should_behave_like '#stats'
  end

412
  describe '#to_diff' do
Robert Speicher committed
413 414 415 416 417 418
    subject { commit.to_diff }

    it { is_expected.not_to include "From #{SeedRepo::Commit::ID}" }
    it { is_expected.to include 'diff --git a/files/ruby/popen.rb b/files/ruby/popen.rb'}
  end

419
  describe '#has_zero_stats?' do
Robert Speicher committed
420 421 422
    it { expect(commit.has_zero_stats?).to eq(false) }
  end

423
  describe '#to_patch' do
Robert Speicher committed
424 425 426 427 428 429
    subject { commit.to_patch }

    it { is_expected.to include "From #{SeedRepo::Commit::ID}" }
    it { is_expected.to include 'diff --git a/files/ruby/popen.rb b/files/ruby/popen.rb'}
  end

430
  describe '#to_hash' do
Robert Speicher committed
431 432 433 434 435 436 437 438 439 440 441
    let(:hash) { commit.to_hash }
    subject { hash }

    it { is_expected.to be_kind_of Hash }

    describe '#keys' do
      subject { super().keys.sort }
      it { is_expected.to match(sample_commit_hash.keys.sort) }
    end
  end

442
  describe '#diffs' do
Robert Speicher committed
443 444 445 446 447 448 449
    subject { commit.diffs }

    it { is_expected.to be_kind_of Gitlab::Git::DiffCollection }
    it { expect(subject.count).to eq(2) }
    it { expect(subject.first).to be_kind_of Gitlab::Git::Diff }
  end

450
  describe '#ref_names' do
451
    let(:commit) { described_class.find(repository, 'master') }
Robert Speicher committed
452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474
    subject { commit.ref_names(repository) }

    it 'has 1 element' do
      expect(subject.size).to eq(1)
    end
    it { is_expected.to include("master") }
    it { is_expected.not_to include("feature") }
  end

  def sample_commit_hash
    {
      author_email: "dmitriy.zaporozhets@gmail.com",
      author_name: "Dmitriy Zaporozhets",
      authored_date: "2012-02-27 20:51:12 +0200",
      committed_date: "2012-02-27 20:51:12 +0200",
      committer_email: "dmitriy.zaporozhets@gmail.com",
      committer_name: "Dmitriy Zaporozhets",
      id: SeedRepo::Commit::ID,
      message: "tree css fixes",
      parent_ids: ["874797c3a73b60d2187ed6e2fcabd289ff75171e"]
    }
  end
end