|
65 | 65 | end |
66 | 66 | end |
67 | 67 |
|
| 68 | + context 'when a soft-deleted image has variants' do |
| 69 | + let(:container) { "bucket" } |
| 70 | + let(:client) { double("client") } |
| 71 | + |
| 72 | + # Blobs are created against the real service, then the OpenStack service is |
| 73 | + # mocked; the parent copy_object is stubbed to succeed. |
| 74 | + def setup_image_with_variant |
| 75 | + image_blob = ActiveStorage::Blob.create_and_upload!(io: StringIO.new("img"), filename: "i.png", content_type: "image/png") |
| 76 | + variant_blob = ActiveStorage::Blob.create_and_upload!(io: StringIO.new("variant"), filename: "v.png", content_type: "image/png") |
| 77 | + variant_record = ActiveStorage::VariantRecord.create!(blob: image_blob, variation_digest: "digest") |
| 78 | + image_attachment = ActiveStorage::Attachment.create!(name: "image", record: variant_record, blob: variant_blob) |
| 79 | + |
| 80 | + allow_any_instance_of(ActiveStorage::Blob).to receive(:service).and_return(double(name: :openstack, container:)) |
| 81 | + job = described_class.new(image_blob) |
| 82 | + allow(job).to receive(:client).and_return(client) |
| 83 | + allow(client).to receive(:copy_object).and_return(double(status: 201)) |
| 84 | + |
| 85 | + { job:, image_blob:, variant_blob:, variant_record:, image_attachment: } |
| 86 | + end |
| 87 | + |
| 88 | + it 'marks the variant files for expiration and keeps their rows for the cron' do |
| 89 | + ctx = setup_image_with_variant |
| 90 | + expect(client).to receive(:copy_object) |
| 91 | + .with(container, ctx[:variant_blob].key, container, ctx[:variant_blob].key, hash_including('X-Delete-At')) |
| 92 | + .and_return(double(status: 201)) |
| 93 | + |
| 94 | + ctx[:job].perform_now |
| 95 | + |
| 96 | + expect(ActiveStorage::Blob.where(id: ctx[:variant_blob].id)).to exist |
| 97 | + expect(ActiveStorage::VariantRecord.where(id: ctx[:variant_record].id)).to exist |
| 98 | + expect(ActiveStorage::Attachment.where(id: ctx[:image_attachment].id)).to exist |
| 99 | + expect(ActiveStorage::Blob.where(id: ctx[:image_blob].id)).to exist # parent soft-deleted |
| 100 | + end |
| 101 | + |
| 102 | + it 'reports to Sentry when a variant copy fails, keeping the rows' do |
| 103 | + ctx = setup_image_with_variant |
| 104 | + allow(client).to receive(:copy_object) |
| 105 | + .with(container, ctx[:variant_blob].key, container, ctx[:variant_blob].key, anything) |
| 106 | + .and_return(double(status: 500)) |
| 107 | + expect(Sentry).to receive(:capture_message).with("Can't expire blob", extra: hash_including(key: ctx[:variant_blob].key)) |
| 108 | + |
| 109 | + ctx[:job].perform_now |
| 110 | + |
| 111 | + expect(ActiveStorage::VariantRecord.where(id: ctx[:variant_record].id)).to exist |
| 112 | + expect(ActiveStorage::Blob.where(id: ctx[:variant_blob].id)).to exist |
| 113 | + end |
| 114 | + end |
| 115 | + |
68 | 116 | context 'when destroying an instance' do |
69 | 117 | it 'uses our custom job' do |
70 | 118 | expect { dossier.destroy }.to have_enqueued_job(DelayedPurgeJob) |
|
0 commit comments