1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
|
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe ProjectExportJob, feature_category: :importers, type: :model do
describe 'associations' do
it { is_expected.to belong_to(:project) }
it { is_expected.to belong_to(:user) }
it { is_expected.to have_many(:relation_exports) }
end
describe 'validations' do
it { is_expected.to validate_presence_of(:project) }
it { is_expected.to validate_presence_of(:jid) }
it { is_expected.to validate_presence_of(:status) }
end
describe 'scopes' do
let_it_be(:current_time) { Time.current }
let_it_be(:eight_days_ago) { current_time - 8.days }
let_it_be(:seven_days_ago) { current_time - 7.days }
let_it_be(:five_days_ago) { current_time - 5.days }
let_it_be(:user) { create(:user) }
let_it_be(:recent_export_job) { create(:project_export_job, updated_at: five_days_ago, user: user) }
let_it_be(:week_old_export_job) { create(:project_export_job, updated_at: seven_days_ago) }
let_it_be(:prunable_export_job_1) { create(:project_export_job, updated_at: eight_days_ago, user: user) }
let_it_be(:prunable_export_job_2) { create(:project_export_job, updated_at: eight_days_ago) }
around do |example|
travel_to(current_time) { example.run }
end
describe '.prunable' do
it 'only includes records with updated_at older than 7 days ago' do
expect(described_class.prunable).to match_array([prunable_export_job_1, prunable_export_job_2])
end
end
describe '.order_by_updated_at' do
it 'sorts by updated_at' do
expect(described_class.order_by_updated_at).to eq(
[
prunable_export_job_1,
prunable_export_job_2,
week_old_export_job,
recent_export_job
]
)
end
it 'uses id as a tiebreaker' do
export_jobs_with_same_updated_at = described_class.where(updated_at: eight_days_ago).order_by_updated_at
expect(export_jobs_with_same_updated_at[0].id).to be < export_jobs_with_same_updated_at[1].id
end
end
describe '.by_user_id' do
it 'returns export_jobs filtered by user_id' do
expect(described_class.by_user_id(user.id)).to match_array([recent_export_job, prunable_export_job_1])
end
end
end
describe 'status transitions' do
let(:queued) { ProjectExportJob::STATUS[:queued] }
let(:started) { ProjectExportJob::STATUS[:started] }
let(:failed) { ProjectExportJob::STATUS[:failed] }
let(:finished) { ProjectExportJob::STATUS[:finished] }
context 'when a new ProjectExportJob is created' do
let(:project_export_job) { create(:project_export_job) }
it 'is initialized in the queued state' do
expect(project_export_job).to be_queued
end
end
context 'when the ProjectExportJob is in queued state' do
let(:project_export_job) { create(:project_export_job) }
it 'can transition to started state' do
expect { project_export_job.start }.to change { project_export_job.status }.from(queued).to(started)
end
it 'can transition to failed state' do
expect { project_export_job.fail_op }.to change { project_export_job.status }.from(queued).to(failed)
end
it 'cannnot transition to finished state' do
expect { project_export_job.finish }.not_to change { project_export_job.status }
end
end
context 'when the ProjectExportJob is in started state' do
let(:project_export_job) { create(:project_export_job, status: started) }
it 'can transition to finished state' do
expect { project_export_job.finish }.to change { project_export_job.status }.from(started).to(finished)
end
it 'can transition to failed state' do
expect { project_export_job.fail_op }.to change { project_export_job.status }.from(started).to(failed)
end
end
context 'when the ProjectExportJob is in finished state' do
let(:project_export_job) { create(:project_export_job, status: finished) }
it 'does not transition further' do
expect { project_export_job.fail_op }.not_to change { project_export_job.status }
end
end
end
describe '#finish' do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project) }
let(:export_job) { build(:project_export_job, :started, user: user, project: project) }
let(:expected_audit) do
{
name: 'project_export_created',
author: user,
scope: project,
target: project,
message: 'Profile file export was created'
}
end
subject(:finish) { export_job.finish }
it 'creates an audit event' do
expect(Gitlab::Audit::Auditor).to receive(:audit).with(expected_audit)
finish
end
context 'when user is nil' do
let_it_be(:user) { nil }
it 'creates an audit event' do
expect(Gitlab::Audit::Auditor).to receive(:audit).with(expected_audit)
finish
end
end
context 'when user was admin', :enable_admin_mode do
let_it_be(:user) { create(:admin) }
it 'creates an audit event' do
expect(Gitlab::Audit::Auditor).to receive(:audit).with(expected_audit)
finish
end
context 'when silent exports enabled' do
before do
stub_application_setting(silent_admin_exports_enabled: true)
end
it 'does not create an audit event' do
expect(Gitlab::Audit::Auditor).not_to receive(:audit)
finish
end
end
end
end
end
|