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 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225
|
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe PagesDeployment, feature_category: :pages do
let_it_be(:project) { create(:project) }
describe 'associations' do
it { is_expected.to belong_to(:project).required }
it { is_expected.to belong_to(:ci_build).optional }
end
describe 'validations' do
it { is_expected.to validate_presence_of(:file) }
it { is_expected.to validate_presence_of(:size) }
it { is_expected.to validate_numericality_of(:size).only_integer.is_greater_than(0) }
it { is_expected.to validate_presence_of(:file_count) }
it { is_expected.to validate_numericality_of(:file_count).only_integer.is_greater_than_or_equal_to(0) }
it { is_expected.to validate_presence_of(:file_sha256) }
it { is_expected.to validate_inclusion_of(:file_store).in_array(ObjectStorage::SUPPORTED_STORES) }
it 'is valid when created from the factory' do
expect(create(:pages_deployment)).to be_valid
end
end
context 'with deployments stored locally and remotely' do
before do
stub_pages_object_storage(::Pages::DeploymentUploader)
end
let!(:remote_deployment) { create(:pages_deployment, project: project, file_store: ::ObjectStorage::Store::REMOTE) }
let!(:local_deployment) { create(:pages_deployment, project: project, file_store: ::ObjectStorage::Store::LOCAL) }
describe '.with_files_stored_locally' do
it 'only returns deployments with files stored locally' do
expect(described_class.with_files_stored_locally).to contain_exactly(local_deployment)
end
end
describe '.with_files_stored_remotely' do
it 'only returns deployments with files stored remotely' do
expect(described_class.with_files_stored_remotely).to contain_exactly(remote_deployment)
end
end
end
context 'when uploading the file' do
before do
stub_pages_object_storage(::Pages::DeploymentUploader)
end
it 'stores the file outsize of the transaction' do
expect_next_instance_of(PagesDeployment) do |deployment|
expect(deployment).to receive(:store_file_now!)
end
create(:pages_deployment, project: project)
end
it 'does nothing when the file did not change' do
deployment = create(:pages_deployment, project: project)
expect(deployment).not_to receive(:store_file_now!)
deployment.touch
end
end
describe '#upload_ready' do
it 'marks #upload_ready as true when upload finishes' do
deployment = build(:pages_deployment)
expect { deployment.save! }
.to change { deployment.upload_ready }
.from(false).to(true)
end
end
describe '.deactivate_all', :freeze_time do
let!(:deployment) { create(:pages_deployment, project: project, updated_at: 5.minutes.ago) }
let!(:nil_path_prefix_deployment) { create(:pages_deployment, project: project, path_prefix: nil) }
let!(:empty_path_prefix_deployment) { create(:pages_deployment, project: project, path_prefix: '') }
let!(:other_project_deployment) { create(:pages_deployment) }
let!(:deactivated_deployment) { create(:pages_deployment, project: project, deleted_at: 5.minutes.ago) }
it 'updates only older deployments for the same project and path prefix' do
expect { described_class.deactivate_all(project) }
.to change { deployment.reload.deleted_at }.from(nil).to(Time.zone.now)
.and change { deployment.reload.updated_at }.to(Time.zone.now)
.and change { nil_path_prefix_deployment.reload.deleted_at }.from(nil).to(Time.zone.now)
.and change { empty_path_prefix_deployment.reload.deleted_at }.from(nil).to(Time.zone.now)
.and not_change { other_project_deployment.reload.deleted_at }
.and not_change { deactivated_deployment.reload.deleted_at }
end
end
describe '.deactivate_deployments_older_than', :freeze_time do
let!(:nil_path_prefix_deployment) { create(:pages_deployment, project: project, path_prefix: nil) }
let!(:empty_path_prefix_deployment) { create(:pages_deployment, project: project, path_prefix: '') }
let!(:older_deployment) { create(:pages_deployment, project: project, updated_at: 5.minutes.ago) }
let!(:reference_deployment) { create(:pages_deployment, project: project, updated_at: 5.minutes.ago) }
let!(:newer_deployment) { create(:pages_deployment, project: project, updated_at: 5.minutes.ago) }
let!(:other_project_deployment) { create(:pages_deployment) }
let!(:other_path_prefix_deployment) { create(:pages_deployment, project: project, path_prefix: 'other') }
let!(:deactivated_deployment) { create(:pages_deployment, project: project, deleted_at: 5.minutes.ago) }
it 'updates only older deployments for the same project and path prefix' do
expect { described_class.deactivate_deployments_older_than(reference_deployment) }
.to change { older_deployment.reload.deleted_at }.from(nil).to(Time.zone.now)
.and change { older_deployment.reload.updated_at }.to(Time.zone.now)
.and change { nil_path_prefix_deployment.reload.deleted_at }.from(nil).to(Time.zone.now)
.and change { empty_path_prefix_deployment.reload.deleted_at }.from(nil).to(Time.zone.now)
.and not_change { reference_deployment.reload.deleted_at }
.and not_change { newer_deployment.reload.deleted_at }
.and not_change { other_project_deployment.reload.deleted_at }
.and not_change { other_path_prefix_deployment.reload.deleted_at }
.and not_change { deactivated_deployment.reload.deleted_at }
end
it 'updates only older deployments for the same project with the given time' do
time = 30.minutes.from_now
expect { described_class.deactivate_deployments_older_than(reference_deployment, time: time) }
.to change { older_deployment.reload.deleted_at }.from(nil).to(time)
.and change { older_deployment.reload.updated_at }.to(Time.zone.now)
.and change { nil_path_prefix_deployment.reload.deleted_at }.from(nil).to(time)
.and change { empty_path_prefix_deployment.reload.deleted_at }.from(nil).to(time)
.and not_change { reference_deployment.reload.deleted_at }
.and not_change { newer_deployment.reload.deleted_at }
.and not_change { other_project_deployment.reload.deleted_at }
.and not_change { other_path_prefix_deployment.reload.deleted_at }
.and not_change { deactivated_deployment.reload.deleted_at }
end
end
describe '.count_versioned_deployments_for' do
it 'counts the number of active pages deployments for the root level namespace of a given project' do
group = create(:group)
create(:project, group: group).tap do |project|
# not versioned
create(:pages_deployment, project: project)
# versioned, active
create(:pages_deployment, project: project, path_prefix: 'v1')
# versioned, not active
create(:pages_deployment, project: project, path_prefix: 'v2', deleted_at: 1.day.from_now)
end
project = create(:project, group: group).tap do |project|
# not versioned
create(:pages_deployment, project: project)
# versioned, active
create(:pages_deployment, project: project, path_prefix: 'v1')
# versioned, not active
create(:pages_deployment, project: project, path_prefix: 'v2', deleted_at: 1.day.from_now)
end
expect(described_class.count_versioned_deployments_for(project, 10)).to eq(2)
expect(described_class.count_versioned_deployments_for(project, 1)).to eq(1)
end
end
describe 'default for file_store' do
let(:deployment) do
filepath = Rails.root.join("spec/fixtures/pages.zip")
described_class.create!(
project: project,
file: fixture_file_upload(filepath),
file_sha256: Digest::SHA256.file(filepath).hexdigest,
file_count: 3
)
end
it 'uses local store when object storage is not enabled' do
expect(deployment.file_store).to eq(ObjectStorage::Store::LOCAL)
end
it 'uses remote store when object storage is enabled' do
stub_pages_object_storage(::Pages::DeploymentUploader)
expect(deployment.file_store).to eq(ObjectStorage::Store::REMOTE)
end
end
it 'saves size along with the file' do
deployment = create(:pages_deployment)
expect(deployment.size).to eq(deployment.file.size)
end
describe '.older_than' do
it 'returns deployments with lower id' do
old_deployments = create_list(:pages_deployment, 2)
deployment = create(:pages_deployment)
# new deployment
create(:pages_deployment)
expect(described_class.older_than(deployment.id)).to eq(old_deployments)
end
end
# Verify that calling deactivate on an instance sets the deleted_at value to now
describe '.deactivate (instance method)' do
it 'sets deleted_at to the current time', :freeze_time do
deployment = create(:pages_deployment)
expect { deployment.deactivate }
.to change { deployment.deleted_at }.from(nil).to(Time.zone.now)
end
end
describe '.restore' do
it 'sets deleted_at to nil', :freeze_time do
deployment = create(:pages_deployment, deleted_at: Time.zone.now)
expect { deployment.restore }
.to change { deployment.deleted_at }.from(Time.zone.now).to(nil)
end
end
end
|