188 行
6.5 KiB
Ruby
188 行
6.5 KiB
Ruby
require 'rails_helper'
|
|
|
|
RSpec.describe PostImportPreviewer do
|
|
before do
|
|
allow(Preview::UrlSafety).to receive(:validate) do |url|
|
|
[URI.parse(url), ['8.8.8.8']]
|
|
end
|
|
end
|
|
|
|
def row(source_row:, url:, attributes: { }, provenance: { }, **values)
|
|
{
|
|
source_row:,
|
|
url:,
|
|
attributes:,
|
|
provenance:
|
|
}.merge(values)
|
|
end
|
|
|
|
describe '#preview_rows' do
|
|
it 'marks an existing post for skipping without fetching metadata' do
|
|
existing = create(:post, url: 'https://example.com/existing')
|
|
expect(PostMetadataFetcher).not_to receive(:fetch)
|
|
|
|
result = described_class.new.preview_rows(rows: [
|
|
row(source_row: 1, url: 'https://EXAMPLE.com/existing/')
|
|
]).first
|
|
|
|
expect(result).to include(
|
|
url: 'https://example.com/existing',
|
|
skip_reason: 'existing',
|
|
existing_post_id: existing.id,
|
|
validation_errors: {}
|
|
)
|
|
expect(result.fetch(:field_warnings)).to eq({})
|
|
end
|
|
|
|
it 'reports list duplicates as URL errors instead of existing skips' do
|
|
create(:post, url: 'https://example.com/duplicate')
|
|
expect(PostMetadataFetcher).not_to receive(:fetch)
|
|
|
|
results = described_class.new.preview_rows(rows: [
|
|
row(source_row: 1, url: 'https://example.com/duplicate'),
|
|
row(source_row: 2, url: 'https://EXAMPLE.com/duplicate/')
|
|
])
|
|
|
|
expect(results.map { _1[:validation_errors] }).to all(
|
|
include(url: ['URL が重複しています.'])
|
|
)
|
|
expect(results).to all(include(skip_reason: nil, existing_post_id: nil))
|
|
end
|
|
|
|
it 'does not fetch metadata for an unsafe URL' do
|
|
allow(Preview::UrlSafety).to receive(:validate)
|
|
.and_raise(Preview::UrlSafety::UnsafeUrl, '安全でない接続先は使用できません.')
|
|
expect(PostMetadataFetcher).not_to receive(:fetch)
|
|
|
|
result = described_class.new.preview_rows(rows: [
|
|
row(source_row: 1, url: 'https://unsafe.example/post')
|
|
]).first
|
|
|
|
expect(result.fetch(:validation_errors)).to include(
|
|
url: ['安全でない接続先は使用できません.']
|
|
)
|
|
end
|
|
|
|
it 'applies metadata to automatic fields and recognises metadata tags' do
|
|
Tag.create!(name: 'known-tag', category: :general)
|
|
allow(PostMetadataFetcher).to receive(:fetch).and_return(
|
|
title: 'metadata title',
|
|
thumbnail_base: 'https://example.com/thumb.jpg',
|
|
duration: 2_000,
|
|
tags: 'known-tag'
|
|
)
|
|
|
|
result = described_class.new.preview_rows(rows: [
|
|
row(source_row: 1, url: 'https://example.com/new')
|
|
]).first
|
|
|
|
expect(result.fetch(:attributes)).to include(
|
|
'title' => 'metadata title',
|
|
'thumbnail_base' => 'https://example.com/thumb.jpg',
|
|
'duration' => 2_000,
|
|
'tags' => 'known-tag'
|
|
)
|
|
expect(result.fetch(:field_warnings)).not_to have_key('tags')
|
|
expect(PostMetadataFetcher).to have_received(:fetch).once
|
|
end
|
|
|
|
it 'preserves manual empty values when metadata is available' do
|
|
allow(PostMetadataFetcher).to receive(:fetch).and_return(
|
|
title: 'metadata title',
|
|
tags: 'metadata-tag'
|
|
)
|
|
|
|
result = described_class.new.preview_rows(rows: [
|
|
row(
|
|
source_row: 1,
|
|
url: 'https://example.com/manual',
|
|
attributes: { title: '', tags: '' },
|
|
provenance: { title: 'manual', tags: 'manual' },
|
|
tag_sources: { automatic: 'old-tag', manual: '' }
|
|
)
|
|
]).first
|
|
|
|
expect(result.fetch(:attributes)).to include('title' => '', 'tags' => '')
|
|
expect(result.fetch(:tag_sources)).to include('manual' => '')
|
|
end
|
|
|
|
it 'clears warnings derived from an old metadata URL' do
|
|
allow(PostMetadataFetcher).to receive(:fetch).and_return(
|
|
title: 'new title',
|
|
thumbnail_base: 'https://example.com/new-thumb.jpg',
|
|
tags: ''
|
|
)
|
|
|
|
result = described_class.new.preview_rows(rows: [
|
|
row(
|
|
source_row: 1,
|
|
url: 'https://example.com/new-url',
|
|
attributes: { title: 'old title', tags: 'old-tag' },
|
|
provenance: { title: 'automatic', tags: 'automatic' },
|
|
tag_sources: { automatic: 'old-tag', manual: '' },
|
|
metadata_url: 'https://example.com/old-url',
|
|
field_warnings: { tags: ['old tag warning'], url: ['old fetch warning'] },
|
|
base_warnings: ['old base warning']
|
|
)
|
|
]).first
|
|
|
|
expect(result.fetch(:attributes)).to include('title' => 'new title', 'tags' => '')
|
|
expect(result.fetch(:base_warnings)).to eq([])
|
|
expect(result.fetch(:field_warnings).values.flatten)
|
|
.not_to include('old tag warning', 'old fetch warning')
|
|
end
|
|
|
|
it 'isolates an unexpected metadata failure to the affected URL' do
|
|
allow(PostMetadataFetcher).to receive(:fetch) do |url|
|
|
raise 'fetch failure' if url.include?('failure')
|
|
|
|
{ title: 'successful title', tags: '' }
|
|
end
|
|
allow(Rails.logger).to receive(:error)
|
|
|
|
results = described_class.new.preview_rows(rows: [
|
|
row(source_row: 1, url: 'https://example.com/failure'),
|
|
row(source_row: 2, url: 'https://example.com/success')
|
|
])
|
|
|
|
expect(results[0].fetch(:field_warnings)).to include(
|
|
'url' => [described_class::METADATA_FETCH_WARNING]
|
|
)
|
|
expect(results[1].fetch(:attributes)).to include('title' => 'successful title')
|
|
end
|
|
|
|
it 'turns an unsafe URL detected during metadata fetching into a URL error' do
|
|
allow(PostMetadataFetcher).to receive(:fetch)
|
|
.and_raise(Preview::UrlSafety::UnsafeUrl, '安全でない接続先です.')
|
|
allow(Rails.logger).to receive(:info)
|
|
|
|
result = described_class.new.preview_rows(rows: [
|
|
row(source_row: 1, url: 'https://example.com/redirects-to-private')
|
|
]).first
|
|
|
|
expect(result.fetch(:validation_errors)).to include(
|
|
url: ['安全でない接続先です.']
|
|
)
|
|
end
|
|
|
|
it 'validates parent IDs from the preloaded set' do
|
|
parent = create(:post)
|
|
|
|
results = described_class.new.preview_rows(
|
|
rows: [
|
|
row(source_row: 1, url: 'https://example.com/valid-parent',
|
|
attributes: { parent_post_ids: parent.id.to_s }),
|
|
row(source_row: 2, url: 'https://example.com/missing-parent',
|
|
attributes: { parent_post_ids: '999999' })
|
|
],
|
|
fetch_metadata: false
|
|
)
|
|
|
|
expect(results[0].fetch(:validation_errors)).not_to have_key(:parent_post_ids)
|
|
expect(results[1].fetch(:validation_errors)).to include(
|
|
parent_post_ids: ['存在しない親投稿 Id. があります.']
|
|
)
|
|
end
|
|
end
|
|
end
|