|
77 | 77 | expect(compose).to be_a ActiveStorageDB::File |
78 | 78 | expect(compose.data).to eq [first_db_file.data, second_db_file.data, third_db_file.data].join |
79 | 79 | end |
| 80 | + |
| 81 | + context "when a source key is missing" do |
| 82 | + subject(:compose) { service.compose(%w[key1 missing_key key3], "dest_key") } |
| 83 | + |
| 84 | + it "raises FileNotFoundError" do |
| 85 | + expect { compose }.to raise_exception(ActiveStorage::FileNotFoundError) |
| 86 | + end |
| 87 | + |
| 88 | + it "does not create the destination file" do |
| 89 | + compose rescue nil # rubocop:disable Style/RescueModifier |
| 90 | + expect(ActiveStorageDB::File.find_by(ref: "dest_key")).to be_nil |
| 91 | + end |
| 92 | + end |
| 93 | + |
| 94 | + context "with empty source keys" do |
| 95 | + subject(:compose) { service.compose([], "dest_key") } |
| 96 | + |
| 97 | + it "does not create a destination file" do |
| 98 | + expect { compose }.not_to change(ActiveStorageDB::File, :count) |
| 99 | + end |
| 100 | + |
| 101 | + it "returns nil" do |
| 102 | + expect(compose).to be_nil |
| 103 | + end |
| 104 | + end |
80 | 105 | end |
81 | 106 | end |
82 | 107 |
|
|
238 | 263 | end |
239 | 264 |
|
240 | 265 | describe ".url_for_direct_upload" do |
241 | | - subject do |
| 266 | + subject(:url_for_direct_upload) do |
242 | 267 | service.url_for_direct_upload( |
243 | 268 | key, |
244 | 269 | expires_in: 5.minutes, |
|
260 | 285 | after { service.delete(key) } |
261 | 286 |
|
262 | 287 | it { is_expected.to start_with "#{url_options[:protocol]}#{url_options[:host]}" } |
| 288 | + |
| 289 | + it "generates a token that contains the expected fields" do |
| 290 | + url = url_for_direct_upload |
| 291 | + token = url.split("/").last |
| 292 | + verified = ActiveStorage.verifier.verified(token, purpose: :blob_token).symbolize_keys |
| 293 | + expect(verified).to include( |
| 294 | + key: key, |
| 295 | + content_type: content_type, |
| 296 | + content_length: fixture_data.size, |
| 297 | + checksum: checksum |
| 298 | + ) |
| 299 | + expect(verified[:service_name]).to be_present |
| 300 | + end |
| 301 | + end |
| 302 | + |
| 303 | + describe ".ensure_integrity_of" do |
| 304 | + before { upload } |
| 305 | + |
| 306 | + after { service.delete(key) rescue nil } # rubocop:disable Style/RescueModifier |
| 307 | + |
| 308 | + context "when the record is missing during integrity check" do |
| 309 | + it "raises FileNotFoundError" do |
| 310 | + # Simulate the record disappearing between upload and integrity check |
| 311 | + allow(service).to receive(:object_for).with(key).and_return(nil) |
| 312 | + |
| 313 | + expect { |
| 314 | + service.send(:ensure_integrity_of, key, "bad_checksum") |
| 315 | + }.to raise_exception(ActiveStorage::FileNotFoundError) |
| 316 | + end |
| 317 | + end |
| 318 | + end |
| 319 | + |
| 320 | + describe "chunk_size validation" do |
| 321 | + it "enforces a minimum chunk size of 1" do |
| 322 | + allow(ENV).to receive(:fetch).with("ASDB_CHUNK_SIZE").and_return("0") |
| 323 | + svc = described_class.configure(:tmp, tmp: { service: "DB" }) |
| 324 | + expect(svc.instance_variable_get(:@chunk_size)).to eq(1) |
| 325 | + end |
| 326 | + |
| 327 | + it "enforces a minimum chunk size for negative values" do |
| 328 | + allow(ENV).to receive(:fetch).with("ASDB_CHUNK_SIZE").and_return("-5") |
| 329 | + svc = described_class.configure(:tmp, tmp: { service: "DB" }) |
| 330 | + expect(svc.instance_variable_get(:@chunk_size)).to eq(1) |
| 331 | + end |
263 | 332 | end |
264 | 333 | end |
0 commit comments