103 行
4.7 KiB
Ruby
103 行
4.7 KiB
Ruby
require 'rails_helper'
|
|
require 'tmpdir'
|
|
|
|
RSpec.describe 'Counts native GET acknowledgement', type: :request do
|
|
include ActiveSupport::Testing::TimeHelpers
|
|
around do |example|
|
|
Dir.mktmpdir('counts-download-request') do |path|
|
|
@counts_download_dir = Pathname.new(path)
|
|
example.run
|
|
end
|
|
end
|
|
|
|
before do
|
|
allow(CountsExportDownload).to receive(:directory).and_return(@counts_download_dir)
|
|
end
|
|
|
|
def ready_job(format)
|
|
CountsExportJobs.pulse
|
|
post '/counts/export/jobs', params: { resource: 'posts', definition: 'history',
|
|
mode: 'details', columns: 'resource_id', locale: 'ja', format: }
|
|
expect(response).to have_http_status(:accepted)
|
|
job = response.parsed_body.fetch('job')
|
|
signature = CountsExportJobs.verifier.verified(job, purpose: 'counts_export_job')
|
|
owner = signature.fetch('owner')
|
|
exporter = instance_double(CountsExporter, resource: 'posts', format:, body: ['payload'])
|
|
file = HistoryAccess.set(user: nil) { CountsExportDownload.prepare(exporter, owner) }
|
|
state = CountsExportJobs.read(signature.fetch('id'))
|
|
state.merge!('status' => 'ready', 'token' => file)
|
|
CountsExportJobs.write(state)
|
|
post "/counts/export/jobs/#{ job }/download"
|
|
expect(response).to have_http_status(:ok)
|
|
[job, file, response.parsed_body.fetch('download_attempt')]
|
|
end
|
|
|
|
['csv', 'json'].each do |format|
|
|
it "acknowledges only an authorised #{ format } GET body, not HEAD or acceptance" do
|
|
job, file, attempt = ready_job(format)
|
|
get "/counts/export/jobs/#{ job }"
|
|
expect(response.parsed_body['download_status']).to eq('pending')
|
|
head "/counts/export/files/#{ file }", params: { job:, attempt: }
|
|
expect(response).to have_http_status(:method_not_allowed)
|
|
get "/counts/export/jobs/#{ job }"
|
|
expect(response.parsed_body['download_status']).to eq('pending')
|
|
get "/counts/export/files/#{ file }", params: { job:, attempt: }
|
|
expect(response).to have_http_status(:ok)
|
|
expect(response.headers['Content-Disposition']).to include("counts-posts.#{ format }")
|
|
expect(response.body).to eq('payload')
|
|
get "/counts/export/jobs/#{ job }"
|
|
expect(response.parsed_body['download_status']).to eq('started')
|
|
get "/counts/export/files/#{ file }", params: { job:, attempt: }
|
|
expect(response).to have_http_status(:not_found)
|
|
end
|
|
end
|
|
|
|
it 'rejects wrong attempts, cancellation and a newly discarded resource' do
|
|
job, file, attempt = ready_job('json')
|
|
get "/counts/export/files/#{ file }", params: { job:, attempt: 'wrong' }
|
|
expect(response).to have_http_status(:not_found)
|
|
delete "/counts/export/jobs/#{ job }"
|
|
expect(response).to have_http_status(:ok)
|
|
get "/counts/export/files/#{ file }", params: { job:, attempt: }
|
|
expect(response).to have_http_status(:not_found)
|
|
job, file, attempt = ready_job('json')
|
|
record = create(:post)
|
|
PostVersion.create!(post: record, version_no: 1, event_type: 'discard', title: 'private',
|
|
url: record.url, tags: '', tags_json: [], parent_post_ids: '', created_at: Time.utc(2024))
|
|
get "/counts/export/files/#{ file }", params: { job:, attempt: }
|
|
expect(response).to have_http_status(:not_found)
|
|
expect(response.body).not_to include('payload', 'private')
|
|
end
|
|
it 'does not let a second browser session inspect the job or download its file' do
|
|
job, file, attempt = ready_job('json')
|
|
other = ActionDispatch::Integration::Session.new(Rails.application)
|
|
other.get("/counts/export/jobs/#{ job }")
|
|
expect(other.response).to have_http_status(:not_found)
|
|
other.get("/counts/export/files/#{ file }", params: { job:, attempt: })
|
|
expect(other.response).to have_http_status(:not_found)
|
|
expect(other.response.body).not_to include('payload')
|
|
end
|
|
|
|
it 'does not acknowledge an expired attempt' do
|
|
job, file, attempt = ready_job('json')
|
|
travel_to(Time.current + 46.seconds) do
|
|
get "/counts/export/files/#{ file }", params: { job:, attempt: }
|
|
expect(response).to have_http_status(:not_found)
|
|
get "/counts/export/jobs/#{ job }"
|
|
expect(response.parsed_body['download_status']).to eq('timeout')
|
|
end
|
|
end
|
|
|
|
it 'records a missing file without accepting the GET as started' do
|
|
job, file, attempt = ready_job('json')
|
|
owner = CountsExportJobs.verifier.verified(job, purpose: 'counts_export_job').fetch('owner')
|
|
metadata = HistoryAccess.set(user: nil) { CountsExportDownload.find(file, owner) }
|
|
File.unlink(metadata.fetch('path'))
|
|
get "/counts/export/files/#{ file }", params: { job:, attempt: }
|
|
expect(response).to have_http_status(:not_found)
|
|
get "/counts/export/jobs/#{ job }"
|
|
expect(response.parsed_body['download_status']).to eq('unavailable')
|
|
end
|
|
|
|
end
|