Testing File Storage Management in CarrierWave
This test suite examines the file storage functionality in CarrierWave, focusing on cache management and directory operations. It validates core file handling mechanisms including directory cleanup, cache expiration, and error handling for storage operations. The tests ensure robust file management across different scenarios and edge cases.
Test Coverage Overview
Implementation Analysis
Technical Details
Best Practices Demonstrated
carrierwaveuploader/carrierwave
spec/storage/file_spec.rb
require 'spec_helper'
require 'support/file_utils_helper'
require 'tempfile'
describe CarrierWave::Storage::File do
include FileUtilsHelper
subject(:storage) { described_class.new(uploader) }
let(:uploader_class) { Class.new(CarrierWave::Uploader::Base) }
let(:tempfile) { Tempfile.new("foo") }
let(:sanitized_temp_file) { CarrierWave::SanitizedFile.new(tempfile) }
let(:uploader) { uploader_class.new }
after { FileUtils.rm_rf(public_path) }
describe '#delete_dir!' do
let(:file) { File.open(file_path("test.jpg")) }
context "when the directory is not empty" do
let(:cache_id_dir) { File.dirname(cache_path) }
let(:cache_path) { File.expand_path(File.join(uploader.cache_dir, uploader.cache_name), uploader.root) }
let(:existing_file) { File.join(cache_id_dir, "existing_file.txt") }
before do
uploader.cache!(file)
File.open(existing_file, "wb"){|f| f << "I exist"}
uploader.store!
end
it "doesn't delete the old cache_id" do
expect(File).to be_directory(cache_id_dir)
end
it "doesn't delete other existing files in old cache_id dir" do
expect(File).to exist existing_file
end
end
end
describe '#cache!' do
context "when FileUtils.mkdir_p raises Errno::EMLINK" do
before { fake_failed_mkdir_p(Errno::EMLINK) }
after { storage.cache!(sanitized_temp_file) }
it { is_expected.to receive(:clean_cache!).with(600) }
end
context "when FileUtils.mkdir_p raises Errno::ENOSPC" do
before { fake_failed_mkdir_p(Errno::ENOSPC) }
after { storage.cache!(sanitized_temp_file) }
it { is_expected.to receive(:clean_cache!).with(600) }
end
end
describe '#clean_cache!' do
let(:today) { '2016/10/09 10:00:00'.to_time }
let(:five_days_ago) { today.ago(5.days) }
let(:three_days_ago) { today.ago(3.days) }
let(:yesterday) { today.yesterday }
let(:cache_dir) { File.expand_path(uploader_class.cache_dir, CarrierWave.root) }
before do
[five_days_ago, three_days_ago, yesterday, (today - 1.minute)].each do |created_date|
Timecop.freeze(created_date) do
FileUtils.mkdir_p File.expand_path(CarrierWave.generate_cache_id, cache_dir)
end
end
end
after { FileUtils.rm_rf(cache_dir) }
it "clears all files older than now in the default cache directory" do
Timecop.freeze(today) { uploader_class.clean_cached_files!(0) }
expect(Dir.glob("#{cache_dir}/*").size).to eq(0)
end
it "clears all files older than, by default, 24 hours in the default cache directory" do
Timecop.freeze(today) { uploader_class.clean_cached_files! }
expect(Dir.glob("#{cache_dir}/*").size).to eq(2)
end
it "allows to set since how many seconds delete the cached files" do
Timecop.freeze(today) { uploader_class.clean_cached_files!(4.days) }
expect(Dir.glob("#{cache_dir}/*").size).to eq(3)
end
it "'s aliased on the CarrierWave module" do
Timecop.freeze(today) { CarrierWave.clean_cached_files! }
expect(Dir.glob("#{cache_dir}/*").size).to eq(2)
end
it "cleans a directory named using old format of cache id" do
FileUtils.mkdir_p File.expand_path("#{yesterday.utc.to_i}-100-1234", cache_dir)
Timecop.freeze(today) { uploader_class.clean_cached_files!(0) }
expect(Dir.glob("#{cache_dir}/*").size).to eq(0)
end
it "clears all files older than now in the new cache directory" do
uploader_class.root = File.expand_path("new", CarrierWave.root)
new_cache_dir = File.expand_path(uploader_class.cache_dir, uploader.root)
Timecop.freeze(today - 1.minute) { FileUtils.mkdir_p File.expand_path(CarrierWave.generate_cache_id, new_cache_dir) }
Timecop.freeze(today) { uploader_class.clean_cached_files!(0) }
expect(Dir.glob("#{new_cache_dir}/*").size).to eq(0)
end
context "when a file which does not conform to the cache_id format exists" do
before do
FileUtils.touch File.expand_path("invalid", cache_dir)
end
it "should just ignore that" do
Timecop.freeze(today) { uploader_class.clean_cached_files!(0) }
expect(Dir.glob("#{cache_dir}/*").size).to eq(1)
expect(File).to exist("#{cache_dir}/invalid")
end
end
end
end