Files
danbooru/test/unit/bulk_update_request_test.rb
evazion 7f90bc4216 BURs: remove ability to skip secondary validations.
Remove the ability to skip secondary validations when creating a BUR.
The only skippable validation that still existed was the requirement
that both tags in an implication must have wiki pages. It's now
mandatory to write wiki pages for tags before you can request an
implication. This doesn't apply to empty tags.
2020-11-12 20:15:14 -06:00

477 lines
18 KiB
Ruby

require 'test_helper'
class BulkUpdateRequestTest < ActiveSupport::TestCase
context "a bulk update request" do
setup do
@admin = FactoryBot.create(:admin_user)
CurrentUser.user = @admin
CurrentUser.ip_addr = "127.0.0.1"
end
teardown do
CurrentUser.user = nil
CurrentUser.ip_addr = nil
end
should_eventually "parse tags with tag type prefixes inside the script" do
@bur = create(:bulk_update_request, script: "mass update aaa -> artist:bbb")
assert_equal(%w[aaa bbb], @bur.tags)
end
context "when approving a BUR" do
context "the category command" do
should "change the tag's category" do
@tag = create(:tag, name: "hello")
@bur = create(:bulk_update_request, script: "category hello -> artist")
@bur.approve!(@admin)
assert_equal(true, @bur.valid?)
assert_equal(true, @tag.reload.artist?)
end
should "fail if the tag doesn't already exist" do
@bur = build(:bulk_update_request, script: "category hello -> artist")
assert_equal(false, @bur.valid?)
assert_equal(["Can't change category hello -> artist (the 'hello' tag doesn't exist)"], @bur.errors[:base])
end
end
context "the create alias command" do
setup do
@wiki = create(:wiki_page, title: "foo")
@artist = create(:artist, name: "foo")
@bur = create(:bulk_update_request, script: "create alias foo -> bar")
@bur.approve!(@admin)
perform_enqueued_jobs
end
should "create an alias" do
@alias = TagAlias.find_by(antecedent_name: "foo", consequent_name: "bar")
assert_equal(true, @alias.present?)
assert_equal(true, @alias.is_active?)
end
should "rename the aliased tag's artist entry and wiki page" do
assert_equal("bar", @artist.reload.name)
assert_equal("bar", @wiki.reload.title)
end
should "move any active aliases from the old tag to the new tag" do
@bur1 = create(:bulk_update_request, script: "alias aaa -> bbb")
@bur2 = create(:bulk_update_request, script: "alias bbb -> ccc")
@bur1.approve!(@admin)
@bur2.approve!(@admin)
perform_enqueued_jobs
assert_equal(false, TagAlias.where(antecedent_name: "aaa", consequent_name: "bbb", status: "active").exists?)
assert_equal(true, TagAlias.where(antecedent_name: "bbb", consequent_name: "ccc", status: "active").exists?)
assert_equal(true, TagAlias.where(antecedent_name: "aaa", consequent_name: "ccc", status: "active").exists?)
end
should "move any active implications from the old tag to the new tag" do
@bur1 = create(:bulk_update_request, script: "imply aaa -> bbb")
@bur2 = create(:bulk_update_request, script: "alias bbb -> ccc")
@bur1.approve!(@admin)
@bur2.approve!(@admin)
perform_enqueued_jobs
assert_equal(false, TagImplication.where(antecedent_name: "aaa", consequent_name: "bbb", status: "active").exists?)
assert_equal(true, TagImplication.where(antecedent_name: "aaa", consequent_name: "ccc", status: "active").exists?)
@bur3 = create(:bulk_update_request, script: "alias aaa -> ddd")
@bur3.approve!(@admin)
perform_enqueued_jobs
assert_equal(false, TagImplication.where(antecedent_name: "aaa", consequent_name: "ccc", status: "active").exists?)
assert_equal(true, TagImplication.where(antecedent_name: "ddd", consequent_name: "ccc", status: "active").exists?)
end
should "fail if the alias is invalid" do
create(:tag_alias, antecedent_name: "aaa", consequent_name: "bbb")
@bur = build(:bulk_update_request, script: "create alias bbb -> aaa")
assert_equal(false, @bur.valid?)
assert_equal(["Can't create alias bbb -> aaa (A tag alias for aaa already exists)"], @bur.errors.full_messages)
end
should "be case-insensitive" do
@bur = create(:bulk_update_request, script: "CREATE ALIAS AAA -> BBB")
@bur.approve!(@admin)
perform_enqueued_jobs
@alias = TagAlias.find_by(antecedent_name: "aaa", consequent_name: "bbb")
assert_equal(true, @alias.present?)
assert_equal(true, @alias.is_active?)
end
end
context "the create implication command" do
should "create an implication" do
@bur = create(:bulk_update_request, script: "create implication foo -> bar")
@bur.approve!(@admin)
perform_enqueued_jobs
@implication = TagImplication.find_by(antecedent_name: "foo", consequent_name: "bar")
assert_equal(true, @implication.present?)
assert_equal(true, @implication.is_active?)
end
should "fail for an implication that is redundant with an existing implication" do
create(:tag_implication, antecedent_name: "a", consequent_name: "b")
create(:tag_implication, antecedent_name: "b", consequent_name: "c")
@bur = build(:bulk_update_request, script: "imply a -> c")
assert_equal(false, @bur.valid?)
assert_equal(["Can't create implication a -> c (a already implies c through another implication)"], @bur.errors.full_messages)
end
should "fail for an implication that is a duplicate of an existing implication" do
create(:tag_implication, antecedent_name: "a", consequent_name: "b")
@bur = build(:bulk_update_request, script: "imply a -> b")
assert_equal(false, @bur.valid?)
assert_equal(["Can't create implication a -> b (Implication already exists)"], @bur.errors.full_messages)
end
should_eventually "fail for an implication that is redundant with another implication in the same BUR" do
create(:tag_implication, antecedent_name: "b", consequent_name: "c")
@bur = build(:bulk_update_request, script: "imply a -> b\nimply a -> c")
assert_equal(false, @bur.valid?)
assert_equal(["Can't create implication a -> c (a already implies c through another implication)"], @bur.errors.full_messages)
end
end
context "the remove alias command" do
should "remove an alias" do
create(:tag_alias, antecedent_name: "foo", consequent_name: "bar")
@bur = create(:bulk_update_request, script: "remove alias foo -> bar")
@bur.approve!(@admin)
@alias = TagAlias.find_by(antecedent_name: "foo", consequent_name: "bar")
assert_equal(true, @alias.present?)
assert_equal(true, @alias.is_deleted?)
end
should "fail if the alias isn't active" do
create(:tag_alias, antecedent_name: "foo", consequent_name: "bar", status: "pending")
@bur = build(:bulk_update_request, script: "remove alias foo -> bar")
assert_equal(false, @bur.valid?)
assert_equal(["Can't remove alias foo -> bar (alias doesn't exist)"], @bur.errors[:base])
end
should "fail if the alias doesn't already exist" do
@bur = build(:bulk_update_request, script: "remove alias foo -> bar")
assert_equal(false, @bur.valid?)
assert_equal(["Can't remove alias foo -> bar (alias doesn't exist)"], @bur.errors[:base])
end
end
context "the remove implication command" do
should "remove an implication" do
create(:tag_implication, antecedent_name: "foo", consequent_name: "bar", status: "active")
@bur = create(:bulk_update_request, script: "remove implication foo -> bar")
@bur.approve!(@admin)
@implication = TagImplication.find_by(antecedent_name: "foo", consequent_name: "bar")
assert_equal(true, @implication.present?)
assert_equal(true, @implication.is_deleted?)
end
should "fail if the implication isn't active" do
create(:tag_implication, antecedent_name: "foo", consequent_name: "bar", status: "pending")
@bur = build(:bulk_update_request, script: "remove implication foo -> bar")
assert_equal(false, @bur.valid?)
assert_equal(["Can't remove implication foo -> bar (implication doesn't exist)"], @bur.errors[:base])
end
should "fail if the implication doesn't already exist" do
@bur = build(:bulk_update_request, script: "remove implication foo -> bar")
assert_equal(false, @bur.valid?)
assert_equal(["Can't remove implication foo -> bar (implication doesn't exist)"], @bur.errors[:base])
end
end
context "the mass update command" do
setup do
@post = create(:post, tag_string: "foo")
@bur = create(:bulk_update_request, script: "mass update foo -> bar")
@bur.approve!(@admin)
perform_enqueued_jobs
end
should "update the tags" do
assert_equal("bar", @post.reload.tag_string)
end
should "be case-sensitive" do
@post = create(:post, source: "imageboard")
@bur = create(:bulk_update_request, script: "mass update source:imageboard -> source:Imageboard")
@bur.approve!(@admin)
perform_enqueued_jobs
assert_equal("Imageboard", @post.reload.source)
end
end
context "the rename command" do
setup do
@artist = create(:artist, name: "foo")
@wiki = create(:wiki_page, title: "foo", body: "[[foo]]")
@post = create(:post, tag_string: "foo blah")
@bur = create(:bulk_update_request, script: "rename foo -> bar")
@bur.approve!(@admin)
perform_enqueued_jobs
end
should "rename the tags" do
assert_equal("approved", @bur.status)
assert_equal("bar blah", @post.reload.tag_string)
end
should "move the tag's artist entry and wiki page" do
assert_equal("bar", @artist.reload.name)
assert_equal("bar", @wiki.reload.title)
assert_equal("[[bar]]", @wiki.body)
end
should "fail if the old tag doesn't exist" do
@bur = build(:bulk_update_request, script: "rename aaa -> bbb")
assert_equal(false, @bur.valid?)
assert_equal(["Can't rename aaa -> bbb (the 'aaa' tag doesn't exist)"], @bur.errors.full_messages)
end
context "when renaming a character tag with a *_(cosplay) tag" do
should "move the *_(cosplay) tag as well" do
@post = create(:post, tag_string: "toosaka_rin_(cosplay)")
@wiki = create(:wiki_page, title: "toosaka_rin_(cosplay)")
@ta = create(:tag_alias, antecedent_name: "toosaka_rin", consequent_name: "tohsaka_rin")
@bur = create(:bulk_update_request, script: "rename toosaka_rin -> tohsaka_rin")
@bur.approve!(@admin)
perform_enqueued_jobs
assert_equal("cosplay tohsaka_rin tohsaka_rin_(cosplay)", @post.reload.tag_string)
assert_equal("tohsaka_rin_(cosplay)", @wiki.reload.title)
end
end
end
context "that contains a mass update followed by an alias" do
should "make the alias take effect after the mass update" do
@bur = create(:bulk_update_request, script: "mass update maid_dress -> maid dress\nalias maid_dress -> maid")
@p1 = create(:post, tag_string: "maid_dress")
@p2 = create(:post, tag_string: "maid")
@bur.approve!(@admin)
perform_enqueued_jobs
assert_equal("dress maid", @p1.reload.tag_string)
assert_equal("maid", @p2.reload.tag_string)
end
end
end
context "when validating a script" do
context "an unparseable script" do
should "fail validation" do
@script = <<~EOS
create alias aaa -> 000
create alias bbb > 111
create alias ccc -> 222
EOS
@bur = build(:bulk_update_request, script: @script)
assert_equal(false, @bur.valid?)
assert_equal(["Invalid line: create alias bbb > 111"], @bur.errors[:base])
end
end
context "a script with extra whitespace" do
should "validate" do
@script = %{
create alias aaa -> 000
create alias bbb -> 111
}
@bur = create(:bulk_update_request, script: @script)
assert_equal(true, @bur.valid?)
end
end
context "requesting an implication for an empty tag without a wiki" do
should "succeed" do
@bur = create(:bulk_update_request, script: "imply a -> b")
assert_equal(true, @bur.valid?)
end
end
context "requesting an implication for a populated tag without a wiki" do
should "fail" do
create(:tag, name: "a", post_count: 1)
create(:tag, name: "b", post_count: 1)
@bur = build(:bulk_update_request, script: "imply a -> b")
assert_equal(false, @bur.valid?)
assert_equal(["'a' must have a wiki page; 'b' must have a wiki page"], @bur.errors.full_messages)
end
end
end
context "when the script is updated" do
should "update the BUR's list of affected tags" do
create(:tag_alias, antecedent_name: "ccc", consequent_name: "222")
create(:tag_implication, antecedent_name: "ddd", consequent_name: "333")
create(:tag, name: "iii")
@script = <<~EOS
create alias aaa -> 000
create implication bbb -> 111
remove alias ccc -> 222
remove implication ddd -> 333
mass update eee id:1 -fff ~ggg hhh* -> 444 -555
category iii -> meta
EOS
@bur = create(:bulk_update_request, script: "create alias aaa -> bbb")
assert_equal(%w[aaa bbb], @bur.tags)
@bur.update!(script: @script)
assert_equal(%w(000 111 222 333 444 aaa bbb ccc ddd eee iii), @bur.tags)
end
end
context "on approval" do
setup do
@post = create(:post, tag_string: "foo aaa")
@script = '
create alias foo -> bar
create implication bar -> baz
mass update aaa -> bbb
'
@bur = create(:bulk_update_request, script: @script, user: @admin)
@bur.approve!(@admin)
assert_enqueued_jobs(3)
perform_enqueued_jobs
@ta = TagAlias.where(:antecedent_name => "foo", :consequent_name => "bar").first
@ti = TagImplication.where(:antecedent_name => "bar", :consequent_name => "baz").first
end
should "reference the approver in the automated message" do
assert_match(Regexp.compile(@admin.name), @bur.forum_post.body)
end
should "set the BUR approver" do
assert_equal(@admin.id, @bur.approver.id)
end
should "create aliases/implications" do
assert_equal("active", @ta.status)
assert_equal("active", @ti.status)
end
should "process mass updates" do
assert_equal("bar baz bbb", @post.reload.tag_string)
end
should "set the alias/implication approvers" do
assert_equal(@admin.id, @ta.approver.id)
assert_equal(@admin.id, @ti.approver.id)
end
end
should "create a forum topic" do
bur = create(:bulk_update_request, reason: "zzz", script: "create alias aaa -> bbb")
assert_equal(true, bur.forum_post.present?)
assert_match(/\[bur:#{bur.id}\]/, bur.forum_post.body)
assert_match(/zzz/, bur.forum_post.body)
end
context "with an associated forum topic" do
setup do
@topic = create(:forum_topic, title: "[bulk] hoge", creator: @admin)
@post = create(:forum_post, topic: @topic, creator: @admin)
@req = FactoryBot.create(:bulk_update_request, :script => "create alias AAA -> BBB", :forum_topic_id => @topic.id, :forum_post_id => @post.id, :title => "[bulk] hoge")
end
should "gracefully handle validation errors during approval" do
@req.stubs(:update!).raises(BulkUpdateRequestProcessor::Error.new("blah"))
assert_difference("ForumPost.count", 1) do
@req.approve!(@admin)
end
assert_equal("pending", @req.reload.status)
end
should "leave the BUR pending if there is an unexpected error during approval" do
@req.forum_updater.stubs(:update).raises(RuntimeError.new("blah"))
assert_raises(RuntimeError) { @req.approve!(@admin) }
# XXX Raises "Couldn't find BulkUpdateRequest without an ID". Possible
# rails bug? (cf rails #34637, #34504, #30167, #15018).
# @req.reload
@req = BulkUpdateRequest.find(@req.id)
assert_equal("pending", @req.status)
end
should "update the topic when processed" do
assert_difference("ForumPost.count") do
@req.approve!(@admin)
end
assert_match(/approved/, @post.reload.body)
end
should "update the topic when rejected" do
@req.approver_id = @admin.id
assert_difference("ForumPost.count") do
@req.reject!(@admin)
end
assert_match(/rejected/, @post.reload.body)
end
should "reference the rejector in the automated message" do
@req.reject!(@admin)
assert_match(Regexp.compile(@admin.name), @req.forum_post.body)
end
should "not send @mention dmails to the approver" do
assert_no_difference("Dmail.count") do
@req.approve!(@admin)
end
end
end
context "when searching" do
setup do
@bur1 = FactoryBot.create(:bulk_update_request, title: "foo", script: "create alias aaa -> bbb", user_id: @admin.id)
@bur2 = FactoryBot.create(:bulk_update_request, title: "bar", script: "create implication bbb -> ccc", user_id: @admin.id)
@bur1.approve!(@admin)
end
should "work" do
assert_equal([@bur2.id, @bur1.id], BulkUpdateRequest.search.map(&:id))
assert_equal([@bur1.id], BulkUpdateRequest.search(user_name: @admin.name, approver_name: @admin.name, status: "approved").map(&:id))
end
end
end
end