diff options
author | Andreas Brandl <abrandl@gitlab.com> | 2018-03-06 20:09:01 +0100 |
---|---|---|
committer | Andreas Brandl <abrandl@gitlab.com> | 2018-03-16 13:35:25 +0100 |
commit | 754272e392c0da088200a1b56156600973f63267 (patch) | |
tree | 21fdb2f633deff884d39d89f7672f230f1d6c143 /spec | |
parent | a0abb904782970de456dae5539ad5de2afef0e05 (diff) | |
download | gitlab-ce-754272e392c0da088200a1b56156600973f63267.tar.gz |
Atomic generation of internal ids for issues.
Diffstat (limited to 'spec')
-rw-r--r-- | spec/factories/internal_ids.rb | 6 | ||||
-rw-r--r-- | spec/models/internal_id_spec.rb | 87 |
2 files changed, 93 insertions, 0 deletions
diff --git a/spec/factories/internal_ids.rb b/spec/factories/internal_ids.rb new file mode 100644 index 00000000000..b4c14d22a29 --- /dev/null +++ b/spec/factories/internal_ids.rb @@ -0,0 +1,6 @@ +FactoryBot.define do + factory :internal_id do + project + usage { InternalId.usages.keys.first } + end +end diff --git a/spec/models/internal_id_spec.rb b/spec/models/internal_id_spec.rb new file mode 100644 index 00000000000..b953b6a2df8 --- /dev/null +++ b/spec/models/internal_id_spec.rb @@ -0,0 +1,87 @@ +require 'spec_helper' + +describe InternalId do + let(:project) { create(:project) } + let(:usage) { :issues } + + context 'validations' do + it { is_expected.to validate_presence_of(:usage) } + it { is_expected.to validate_presence_of(:project_id) } + end + + describe '.generate_next' do + context 'in the absence of a record' do + subject { described_class.generate_next(project, usage) } + + it 'creates a record if not yet present' do + expect { subject }.to change { described_class.count }.from(0).to(1) + end + + it 'stores record attributes' do + subject + + described_class.first.tap do |record| + expect(record.project).to eq(project) + expect(record.usage).to eq(usage.to_s) # TODO + end + end + + context 'with existing issues' do + before do + rand(10).times { create(:issue, project: project) } + end + + it 'calculates last_value values automatically' do + expect(subject).to eq(project.issues.size + 1) + end + end + end + + it 'generates a strictly monotone, gapless sequence' do + seq = (0..rand(1000)).map do + described_class.generate_next(project, usage) + end + normalized = seq.map { |i| i - seq.min } + expect(normalized).to eq((0..seq.size - 1).to_a) + end + end + + describe '#increment_and_save!' do + let(:id) { create(:internal_id) } + subject { id.increment_and_save! } + + it 'returns incremented iid' do + value = id.last_value + expect(subject).to eq(value + 1) + end + + it 'saves the record' do + subject + expect(id.changed?).to be_falsey + end + + context 'with last_value=nil' do + let(:id) { build(:internal_id, last_value: nil) } + + it 'returns 1' do + expect(subject).to eq(1) + end + end + end + + describe '#calculate_last_value! (for issues)' do + subject do + build(:internal_id, project: project, usage: :issues) + end + + context 'with existing issues' do + before do + rand(10).times { create(:issue, project: project) } + end + + it 'counts related issues and saves' do + expect { subject.calculate_last_value! }.to change { subject.last_value }.from(nil).to(project.issues.size) + end + end + end +end |