2
0
Fork 0
mirror of https://github.com/discourse/discourse.git synced 2026-03-04 01:15:08 +08:00
discourse/spec/lib/disk_cache_eviction_spec.rb
Joffrey JAFFEUX 1267b818a3
PERF: extract shared DiskCacheEviction utility for disk caches (#37842)
- Extracts a shared `DiskCacheEviction.evict` utility used by both
avatar proxy cache (`tmp/avatar_proxy/`) and download cache
(`tmp/download_cache/`)
- `base_store.rb` no longer sorts the entire file list on every
`cache_file` call, eviction only runs when count exceeds the limit
- Fixes a concurrency bug in `proxy_avatar` where a file could be
evicted between `File.exist?` and `send_file`, now rescues
`Errno::ENOENT` / `ActionController::MissingFile` and falls back to
`render_blank`
2026-02-16 12:24:38 +01:00

55 lines
1.8 KiB
Ruby

# frozen_string_literal: true
RSpec.describe DiskCacheEviction do
let(:cache_dir) { Dir.mktmpdir }
after { FileUtils.rm_rf(cache_dir) }
def create_files(count, prefix: "file", age_offset: 0)
count.times.map do |i|
path = File.join(cache_dir, "#{prefix}_#{i}.tmp")
File.write(path, "data_#{i}")
FileUtils.touch(path, mtime: Time.now - (age_offset + count - i).hours)
path
end
end
describe ".evict" do
it "does nothing when file count is under the limit" do
create_files(3)
described_class.evict(dir: cache_dir, max_entries: 5, evict_count: 2)
expect(Dir.glob(File.join(cache_dir, "*")).length).to eq(3)
end
it "does nothing when file count equals the limit" do
create_files(5)
described_class.evict(dir: cache_dir, max_entries: 5, evict_count: 2)
expect(Dir.glob(File.join(cache_dir, "*")).length).to eq(5)
end
it "evicts the oldest files when over the limit" do
old_files = create_files(3, prefix: "old", age_offset: 10)
new_files = create_files(3, prefix: "new", age_offset: 0)
described_class.evict(dir: cache_dir, max_entries: 5, evict_count: 2)
expect(File.exist?(old_files[0])).to eq(false)
expect(File.exist?(old_files[1])).to eq(false)
expect(File.exist?(old_files[2])).to eq(true)
new_files.each { |f| expect(File.exist?(f)).to eq(true) }
end
it "handles files vanishing between glob and stat" do
files = create_files(6, prefix: "race")
vanishing = files.first
# Simulate race: file is in glob results but gone when File.mtime is called
File.stubs(:mtime).with(anything).returns(Time.now)
File.stubs(:mtime).with(vanishing).raises(Errno::ENOENT)
expect {
described_class.evict(dir: cache_dir, max_entries: 5, evict_count: 2)
}.not_to raise_error
end
end
end