dceed1caa1
Merge remote-tracking branch 'origin/main' into feature/046 #46 #46 #46 #46 #46 #46 Co-authored-by: miteruzo <miteruzo@naver.com> Reviewed-on: #339
322 lines
9.9 KiB
Ruby
322 lines
9.9 KiB
Ruby
require "rails_helper"
|
||
|
||
|
||
RSpec.describe "nico:sync" do
|
||
def stub_python(json_array)
|
||
status = instance_double(Process::Status, success?: true)
|
||
allow(Open3).to receive(:capture3).and_return([json_array.to_json, "", status])
|
||
end
|
||
|
||
def create_tag!(name, category:)
|
||
tn = TagName.find_undiscard_or_create_by!(name: name.to_s.strip)
|
||
Tag.find_undiscard_or_create_by!(tag_name_id: tn.id) { |t| t.category = category }
|
||
end
|
||
|
||
def link_nico_to_tag!(nico_tag, tag)
|
||
NicoTagRelation.create!(nico_tag_id: nico_tag.id, tag_id: tag.id)
|
||
end
|
||
|
||
it "既存 post を見つけて、nico tag と linked tag を追加し、差分が出たら bot を付ける" do
|
||
# 既存 post(正規表現で拾われるURL)
|
||
post = Post.create!(title: "old", url: "https://www.nicovideo.jp/watch/sm9", uploaded_user: nil)
|
||
|
||
# 既存の非nicoタグ(kept_non_nico_ids)
|
||
kept_general = create_tag!("spec_kept", category: "general")
|
||
PostTag.create!(post: post, tag: kept_general)
|
||
|
||
# 追加される linked tag を準備(nico tag に紐付く一般タグ)
|
||
linked = create_tag!("spec_linked", category: "general")
|
||
nico = create_tag!("nico:AAA", category: "nico")
|
||
link_nico_to_tag!(nico, linked)
|
||
|
||
# bot / tagme は task 内で使うので作っておく(Tag.bot/tagme がある前提)
|
||
Tag.bot
|
||
Tag.tagme
|
||
|
||
# pythonの出力(AAA が付く)
|
||
stub_python([{
|
||
'code' => 'sm9',
|
||
'title' => 't',
|
||
'tags' => ['AAA'],
|
||
'uploaded_at' => '2026-01-01 12:34:56',
|
||
'deleted_at' => '2026-01-31 00:00:00' }])
|
||
|
||
# 外部HTTPは今回「既存 post なので呼ばれない」はずだが、念のため塞ぐ
|
||
allow(URI).to receive(:open).and_return(StringIO.new("<html></html>"))
|
||
|
||
run_rake_task("nico:sync")
|
||
|
||
post.reload
|
||
active_tag_names = post.tags.joins(:tag_name).pluck("tag_names.name")
|
||
|
||
expect(active_tag_names).to include("spec_kept")
|
||
expect(active_tag_names).to include("nico:AAA")
|
||
expect(active_tag_names).to include("spec_linked")
|
||
|
||
expect(post.original_created_from).to eq(Time.iso8601('2026-01-01T03:34:00Z'))
|
||
expect(post.original_created_before).to eq(Time.iso8601('2026-01-01T03:35:00Z'))
|
||
|
||
# 差分が出るので bot が付く(kept_non_nico_ids != desired_non_nico_ids)
|
||
expect(active_tag_names).to include("bot操作")
|
||
end
|
||
|
||
it "既存 post にあった古い nico tag は active から外され、履歴として discard される" do
|
||
post = Post.create!(title: "old", url: "https://www.nicovideo.jp/watch/sm9", uploaded_user: nil)
|
||
|
||
# 旧nicoタグ(今回の同期結果に含まれない)
|
||
old_nico = create_tag!("nico:OLD", category: "nico")
|
||
old_pt = PostTag.create!(post: post, tag: old_nico)
|
||
expect(old_pt.discarded_at).to be_nil
|
||
|
||
# 今回は NEW のみ欲しい
|
||
new_nico = create_tag!("nico:NEW", category: "nico")
|
||
|
||
# bot/tagme 念のため
|
||
Tag.bot
|
||
Tag.tagme
|
||
|
||
stub_python([{ "code" => "sm9", "title" => "t", "tags" => ["NEW"] }])
|
||
allow(URI).to receive(:open).and_return(StringIO.new("<html></html>"))
|
||
|
||
run_rake_task("nico:sync")
|
||
|
||
# OLD は active から外れる(discarded_at が入る)
|
||
old_pts = PostTag.where(post_id: post.id, tag_id: old_nico.id).order(:id).to_a
|
||
expect(old_pts.last.discarded_at).to be_present
|
||
|
||
# NEW は active にいる
|
||
post.reload
|
||
active_names = post.tags.joins(:tag_name).pluck("tag_names.name")
|
||
expect(active_names).to include("nico:NEW")
|
||
expect(active_names).not_to include("nico:OLD")
|
||
end
|
||
|
||
def snapshot_tags(post)
|
||
post.snapshot_tag_names.join(' ')
|
||
end
|
||
|
||
def create_post_version_for!(post, version_no: 1, event_type: 'create', created_by_user: nil)
|
||
PostVersion.create!(
|
||
post: post,
|
||
version_no: version_no,
|
||
event_type: event_type,
|
||
title: post.title,
|
||
url: post.url,
|
||
thumbnail_base: post.thumbnail_base,
|
||
tags: snapshot_tags(post),
|
||
parent_post_ids: post.snapshot_parent_post_ids.join(' '),
|
||
original_created_from: post.original_created_from,
|
||
original_created_before: post.original_created_before,
|
||
created_at: Time.current,
|
||
created_by_user: created_by_user
|
||
)
|
||
end
|
||
|
||
it '新規 post 作成時に version 1 を作る' do
|
||
Tag.bot
|
||
Tag.tagme
|
||
Tag.niconico
|
||
Tag.video
|
||
Tag.no_deerjikist
|
||
|
||
stub_python([{
|
||
'code' => 'sm9',
|
||
'title' => 't',
|
||
'tags' => ['AAA'],
|
||
'uploaded_at' => '2026-01-01 12:34:56'
|
||
}])
|
||
|
||
allow(URI).to receive(:open).and_return(StringIO.new('<html></html>'))
|
||
|
||
expect {
|
||
run_rake_task('nico:sync')
|
||
}.to change(PostVersion, :count).by(1)
|
||
|
||
post = Post.find_by!(url: 'https://www.nicovideo.jp/watch/sm9')
|
||
version = post.post_versions.order(:version_no).last
|
||
|
||
expect(version.version_no).to eq(1)
|
||
expect(version.event_type).to eq('create')
|
||
expect(version.created_by_user).to be_nil
|
||
expect(version.tags).to eq(snapshot_tags(post.reload))
|
||
end
|
||
|
||
it '既存 post の内容または tags が変わったとき update version を作る' do
|
||
post = Post.create!(
|
||
title: 'old',
|
||
url: 'https://www.nicovideo.jp/watch/sm9',
|
||
uploaded_user: nil
|
||
)
|
||
|
||
kept_general = create_tag!('spec_kept', category: 'general')
|
||
PostTag.create!(post: post, tag: kept_general)
|
||
create_post_version_for!(post)
|
||
|
||
linked = create_tag!('spec_linked', category: 'general')
|
||
nico = create_tag!('nico:AAA', category: 'nico')
|
||
link_nico_to_tag!(nico, linked)
|
||
|
||
Tag.bot
|
||
Tag.tagme
|
||
Tag.no_deerjikist
|
||
|
||
stub_python([{
|
||
'code' => 'sm9',
|
||
'title' => 't',
|
||
'tags' => ['AAA'],
|
||
'uploaded_at' => '2026-01-01 12:34:56'
|
||
}])
|
||
|
||
allow(URI).to receive(:open).and_return(StringIO.new('<html></html>'))
|
||
|
||
expect {
|
||
run_rake_task('nico:sync')
|
||
}.to change(PostVersion, :count).by(1)
|
||
|
||
version = post.reload.post_versions.order(:version_no).last
|
||
expect(version.version_no).to eq(2)
|
||
expect(version.event_type).to eq('update')
|
||
expect(version.created_by_user).to be_nil
|
||
expect(version.tags).to eq(snapshot_tags(post.reload))
|
||
end
|
||
|
||
it '既存 post に差分が無いときは新しい version を作らない' do
|
||
nico = create_tag!('nico:AAA', category: 'nico')
|
||
no_deerjikist = create_tag!('ニジラー情報不詳', category: 'meta')
|
||
|
||
post = Post.create!(
|
||
title: 't',
|
||
url: 'https://www.nicovideo.jp/watch/sm9',
|
||
uploaded_user: nil,
|
||
original_created_from: Time.iso8601('2026-01-01T03:34:00Z'),
|
||
original_created_before: Time.iso8601('2026-01-01T03:35:00Z')
|
||
)
|
||
|
||
PostTag.create!(post: post, tag: nico)
|
||
PostTag.create!(post: post, tag: no_deerjikist)
|
||
create_post_version_for!(post)
|
||
|
||
stub_python([{
|
||
'code' => 'sm9',
|
||
'title' => 't',
|
||
'tags' => ['AAA'],
|
||
'uploaded_at' => '2026-01-01 12:34:56'
|
||
}])
|
||
|
||
allow(URI).to receive(:open).and_return(StringIO.new('<html></html>'))
|
||
|
||
expect {
|
||
run_rake_task('nico:sync')
|
||
}.not_to change(PostVersion, :count)
|
||
|
||
version = post.reload.post_versions.order(:version_no).last
|
||
expect(version.version_no).to eq(1)
|
||
expect(version.event_type).to eq('create')
|
||
expect(version.tags).to eq(snapshot_tags(post.reload))
|
||
end
|
||
|
||
it '新規 nico tag に nico tag version を作る' do
|
||
Tag.bot
|
||
Tag.tagme
|
||
Tag.niconico
|
||
Tag.video
|
||
Tag.no_deerjikist
|
||
|
||
stub_python([{
|
||
'code' => 'sm9',
|
||
'title' => 't',
|
||
'tags' => ['AAA'],
|
||
'uploaded_at' => '2026-01-01 12:34:56'
|
||
}])
|
||
|
||
allow(URI).to receive(:open).and_return(StringIO.new('<html></html>'))
|
||
|
||
expect {
|
||
run_rake_task('nico:sync')
|
||
}.to change(NicoTagVersion, :count).by(1)
|
||
|
||
nico_tag = Tag.joins(:tag_name).find_by!(tag_names: { name: 'nico:AAA' })
|
||
version = nico_tag.nico_tag_versions.order(:version_no).last
|
||
|
||
expect(version.version_no).to eq(1)
|
||
expect(version.event_type).to eq('create')
|
||
expect(version.name).to eq('nico:AAA')
|
||
expect(version.created_by_user).to be_nil
|
||
end
|
||
|
||
it '既存 post に version が無い場合は create snapshot を補う' do
|
||
post = Post.create!(
|
||
title: 'old',
|
||
url: 'https://www.nicovideo.jp/watch/sm9',
|
||
uploaded_user: nil
|
||
)
|
||
|
||
kept_general = create_tag!('spec_kept_without_version', category: 'general')
|
||
PostTag.create!(post: post, tag: kept_general)
|
||
|
||
Tag.bot
|
||
Tag.tagme
|
||
Tag.no_deerjikist
|
||
|
||
stub_python([{
|
||
'code' => 'sm9',
|
||
'title' => 'changed title',
|
||
'tags' => ['AAA'],
|
||
'uploaded_at' => '2026-01-01 12:34:56'
|
||
}])
|
||
|
||
allow(URI).to receive(:open).and_return(StringIO.new('<html></html>'))
|
||
|
||
expect {
|
||
run_rake_task('nico:sync')
|
||
}.to change { post.reload.post_versions.count }.by(1)
|
||
|
||
versions = post.reload.post_versions.order(:version_no)
|
||
|
||
expect(versions.map(&:event_type)).to eq(['create'])
|
||
expect(versions.first.title).to eq('changed title')
|
||
expect(versions.first.tags).to eq(snapshot_tags(post.reload))
|
||
end
|
||
|
||
it '既存 version がある post には update version を作る' do
|
||
post = Post.create!(
|
||
title: 'old',
|
||
url: 'https://www.nicovideo.jp/watch/sm9',
|
||
uploaded_user: nil
|
||
)
|
||
|
||
kept_general = create_tag!('spec_kept_with_version', category: 'general')
|
||
PostTag.create!(post: post, tag: kept_general)
|
||
|
||
PostVersionRecorder.record!(
|
||
post: post,
|
||
event_type: :create,
|
||
created_by_user: nil
|
||
)
|
||
|
||
Tag.bot
|
||
Tag.tagme
|
||
Tag.no_deerjikist
|
||
|
||
stub_python([{
|
||
'code' => 'sm9',
|
||
'title' => 'changed title',
|
||
'tags' => ['AAA'],
|
||
'uploaded_at' => '2026-01-01 12:34:56'
|
||
}])
|
||
|
||
allow(URI).to receive(:open).and_return(StringIO.new('<html></html>'))
|
||
|
||
expect {
|
||
run_rake_task('nico:sync')
|
||
}.to change { post.reload.post_versions.count }.by(1)
|
||
|
||
versions = post.reload.post_versions.order(:version_no)
|
||
|
||
expect(versions.map(&:event_type)).to eq(['create', 'update'])
|
||
expect(versions.first.title).to eq('old')
|
||
expect(versions.second.title).to eq('changed title')
|
||
expect(versions.second.tags).to eq(snapshot_tags(post.reload))
|
||
end
|
||
end
|