このコミットが含まれているのは:
@@ -0,0 +1,98 @@
|
||||
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|
|
||||
allow(CountsExportDownload).to receive(:directory).and_return(Pathname.new(path))
|
||||
example.run
|
||||
end
|
||||
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
|
||||
@@ -266,4 +266,12 @@ RSpec.describe 'Counts table API', type: :request do
|
||||
expect(json).to eq('error' => 'private_condition')
|
||||
end
|
||||
|
||||
it 'reports the combined axis limit without replacing it with a generic 400' do
|
||||
get '/counts/query', params: base.merge(mode: 'summary', sort: '',
|
||||
rows: 'resource_id version_no event_type user created_at:month',
|
||||
cols: 'title url thumbnail_base video_ms')
|
||||
expect(response).to have_http_status(:bad_request)
|
||||
expect(response.parsed_body).to eq('error' => 'too_many_axes', 'max_axes' => 8)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
新しいイシューから参照
ユーザーをブロックする