|
- 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.parent,
- 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
- end
|