ぼざクリタグ広場 https://hub.nizika.monster
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

218 lines
7.1 KiB

  1. require "rails_helper"
  2. RSpec.describe "nico:sync" do
  3. def stub_python(json_array)
  4. status = instance_double(Process::Status, success?: true)
  5. allow(Open3).to receive(:capture3).and_return([json_array.to_json, "", status])
  6. end
  7. def create_tag!(name, category:)
  8. tn = TagName.find_undiscard_or_create_by!(name: name.to_s.strip)
  9. Tag.find_undiscard_or_create_by!(tag_name_id: tn.id) { |t| t.category = category }
  10. end
  11. def link_nico_to_tag!(nico_tag, tag)
  12. NicoTagRelation.create!(nico_tag_id: nico_tag.id, tag_id: tag.id)
  13. end
  14. it "既存 post を見つけて、nico tag と linked tag を追加し、差分が出たら bot を付ける" do
  15. # 既存 post(正規表現で拾われるURL)
  16. post = Post.create!(title: "old", url: "https://www.nicovideo.jp/watch/sm9", uploaded_user: nil)
  17. # 既存の非nicoタグ(kept_non_nico_ids)
  18. kept_general = create_tag!("spec_kept", category: "general")
  19. PostTag.create!(post: post, tag: kept_general)
  20. # 追加される linked tag を準備(nico tag に紐付く一般タグ)
  21. linked = create_tag!("spec_linked", category: "general")
  22. nico = create_tag!("nico:AAA", category: "nico")
  23. link_nico_to_tag!(nico, linked)
  24. # bot / tagme は task 内で使うので作っておく(Tag.bot/tagme がある前提)
  25. Tag.bot
  26. Tag.tagme
  27. # pythonの出力(AAA が付く)
  28. stub_python([{
  29. 'code' => 'sm9',
  30. 'title' => 't',
  31. 'tags' => ['AAA'],
  32. 'uploaded_at' => '2026-01-01 12:34:56',
  33. 'deleted_at' => '2026-01-31 00:00:00' }])
  34. # 外部HTTPは今回「既存 post なので呼ばれない」はずだが、念のため塞ぐ
  35. allow(URI).to receive(:open).and_return(StringIO.new("<html></html>"))
  36. run_rake_task("nico:sync")
  37. post.reload
  38. active_tag_names = post.tags.joins(:tag_name).pluck("tag_names.name")
  39. expect(active_tag_names).to include("spec_kept")
  40. expect(active_tag_names).to include("nico:AAA")
  41. expect(active_tag_names).to include("spec_linked")
  42. expect(post.original_created_from).to eq(Time.iso8601('2026-01-01T03:34:00Z'))
  43. expect(post.original_created_before).to eq(Time.iso8601('2026-01-01T03:35:00Z'))
  44. # 差分が出るので bot が付く(kept_non_nico_ids != desired_non_nico_ids)
  45. expect(active_tag_names).to include("bot操作")
  46. end
  47. it "既存 post にあった古い nico tag は active から外され、履歴として discard される" do
  48. post = Post.create!(title: "old", url: "https://www.nicovideo.jp/watch/sm9", uploaded_user: nil)
  49. # 旧nicoタグ(今回の同期結果に含まれない)
  50. old_nico = create_tag!("nico:OLD", category: "nico")
  51. old_pt = PostTag.create!(post: post, tag: old_nico)
  52. expect(old_pt.discarded_at).to be_nil
  53. # 今回は NEW のみ欲しい
  54. new_nico = create_tag!("nico:NEW", category: "nico")
  55. # bot/tagme 念のため
  56. Tag.bot
  57. Tag.tagme
  58. stub_python([{ "code" => "sm9", "title" => "t", "tags" => ["NEW"] }])
  59. allow(URI).to receive(:open).and_return(StringIO.new("<html></html>"))
  60. run_rake_task("nico:sync")
  61. # OLD は active から外れる(discarded_at が入る)
  62. old_pts = PostTag.where(post_id: post.id, tag_id: old_nico.id).order(:id).to_a
  63. expect(old_pts.last.discarded_at).to be_present
  64. # NEW は active にいる
  65. post.reload
  66. active_names = post.tags.joins(:tag_name).pluck("tag_names.name")
  67. expect(active_names).to include("nico:NEW")
  68. expect(active_names).not_to include("nico:OLD")
  69. end
  70. def snapshot_tags(post)
  71. post.snapshot_tag_names.join(' ')
  72. end
  73. def create_post_version_for!(post, version_no: 1, event_type: 'create', created_by_user: nil)
  74. PostVersion.create!(
  75. post: post,
  76. version_no: version_no,
  77. event_type: event_type,
  78. title: post.title,
  79. url: post.url,
  80. thumbnail_base: post.thumbnail_base,
  81. tags: snapshot_tags(post),
  82. parent: post.parent,
  83. original_created_from: post.original_created_from,
  84. original_created_before: post.original_created_before,
  85. created_at: Time.current,
  86. created_by_user: created_by_user
  87. )
  88. end
  89. it '新規 post 作成時に version 1 を作る' do
  90. Tag.bot
  91. Tag.tagme
  92. Tag.niconico
  93. Tag.video
  94. Tag.no_deerjikist
  95. stub_python([{
  96. 'code' => 'sm9',
  97. 'title' => 't',
  98. 'tags' => ['AAA'],
  99. 'uploaded_at' => '2026-01-01 12:34:56'
  100. }])
  101. allow(URI).to receive(:open).and_return(StringIO.new('<html></html>'))
  102. expect {
  103. run_rake_task('nico:sync')
  104. }.to change(PostVersion, :count).by(1)
  105. post = Post.find_by!(url: 'https://www.nicovideo.jp/watch/sm9')
  106. version = post.post_versions.order(:version_no).last
  107. expect(version.version_no).to eq(1)
  108. expect(version.event_type).to eq('create')
  109. expect(version.created_by_user).to be_nil
  110. expect(version.tags).to eq(snapshot_tags(post.reload))
  111. end
  112. it '既存 post の内容または tags が変わったとき update version を作る' do
  113. post = Post.create!(
  114. title: 'old',
  115. url: 'https://www.nicovideo.jp/watch/sm9',
  116. uploaded_user: nil
  117. )
  118. kept_general = create_tag!('spec_kept', category: 'general')
  119. PostTag.create!(post: post, tag: kept_general)
  120. create_post_version_for!(post)
  121. linked = create_tag!('spec_linked', category: 'general')
  122. nico = create_tag!('nico:AAA', category: 'nico')
  123. link_nico_to_tag!(nico, linked)
  124. Tag.bot
  125. Tag.tagme
  126. Tag.no_deerjikist
  127. stub_python([{
  128. 'code' => 'sm9',
  129. 'title' => 't',
  130. 'tags' => ['AAA'],
  131. 'uploaded_at' => '2026-01-01 12:34:56'
  132. }])
  133. allow(URI).to receive(:open).and_return(StringIO.new('<html></html>'))
  134. expect {
  135. run_rake_task('nico:sync')
  136. }.to change(PostVersion, :count).by(1)
  137. version = post.reload.post_versions.order(:version_no).last
  138. expect(version.version_no).to eq(2)
  139. expect(version.event_type).to eq('update')
  140. expect(version.created_by_user).to be_nil
  141. expect(version.tags).to eq(snapshot_tags(post.reload))
  142. end
  143. it '既存 post に差分が無いときは新しい version を作らない' do
  144. nico = create_tag!('nico:AAA', category: 'nico')
  145. no_deerjikist = create_tag!('ニジラー情報不詳', category: 'meta')
  146. post = Post.create!(
  147. title: 't',
  148. url: 'https://www.nicovideo.jp/watch/sm9',
  149. uploaded_user: nil,
  150. original_created_from: Time.iso8601('2026-01-01T03:34:00Z'),
  151. original_created_before: Time.iso8601('2026-01-01T03:35:00Z')
  152. )
  153. PostTag.create!(post: post, tag: nico)
  154. PostTag.create!(post: post, tag: no_deerjikist)
  155. create_post_version_for!(post)
  156. stub_python([{
  157. 'code' => 'sm9',
  158. 'title' => 't',
  159. 'tags' => ['AAA'],
  160. 'uploaded_at' => '2026-01-01 12:34:56'
  161. }])
  162. allow(URI).to receive(:open).and_return(StringIO.new('<html></html>'))
  163. expect {
  164. run_rake_task('nico:sync')
  165. }.not_to change(PostVersion, :count)
  166. version = post.reload.post_versions.order(:version_no).last
  167. expect(version.version_no).to eq(1)
  168. expect(version.event_type).to eq('create')
  169. expect(version.tags).to eq(snapshot_tags(post.reload))
  170. end
  171. end