mirror of
https://github.com/discourse/discourse.git
synced 2024-12-12 12:03:39 +08:00
9b0cfa99c5
* DEV: Gracefully handle remaps which violate DB column constraints This change implements length constraint enforcement to skip remaps which exceed column max lengths * DEV: Only perform skipped column stats lookup when verbose is true * DEV: Tidy up specs * DEV: Make skipping violating remap behaviour opt-in This change introduces a new `skip_max_length_violations` param for `remap`, set to `false` by default to ensure we still continue to fail hard when max lenth constraints are violated. To aid in quick resolution when remaps fail, this change also adds more context to the exception message to include the offending table and column information * Apply suggestions from code review Co-authored-by: Gerhard Schlager <gerhard.schlager@discourse.org> * FIX: Various fixes - Linter errors - Remap status "logger" early return condition --------- Co-authored-by: Gerhard Schlager <gerhard.schlager@discourse.org>
102 lines
3.1 KiB
Ruby
102 lines
3.1 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
RSpec.describe DbHelper do
|
|
describe ".remap" do
|
|
fab!(:bookmark1) { Fabricate(:bookmark, name: "short-bookmark") }
|
|
fab!(:bookmark2) { Fabricate(:bookmark, name: "another-bookmark") }
|
|
let(:bookmark_name_limit) { Bookmark.columns_hash["name"].limit }
|
|
let(:long_bookmark_name) { "a" * (bookmark_name_limit + 1) }
|
|
|
|
it "should remap columns properly" do
|
|
post = Fabricate(:post, cooked: "this is a specialcode that I included")
|
|
post_attributes = post.reload.attributes
|
|
|
|
badge = Fabricate(:badge, query: "specialcode")
|
|
badge_attributes = badge.reload.attributes
|
|
|
|
DbHelper.remap("specialcode", "codespecial")
|
|
|
|
post.reload
|
|
|
|
expect(post.cooked).to include("codespecial")
|
|
|
|
badge.reload
|
|
|
|
expect(badge.query).to eq("codespecial")
|
|
|
|
expect(badge_attributes.except("query")).to eq(badge.attributes.except("query"))
|
|
end
|
|
|
|
it "allows tables to be excluded from scanning" do
|
|
post = Fabricate(:post, cooked: "test")
|
|
|
|
DbHelper.remap("test", "something else", excluded_tables: %w[posts])
|
|
|
|
expect(post.reload.cooked).to eq("test")
|
|
end
|
|
|
|
it "does not remap readonly columns" do
|
|
post = Fabricate(:post, raw: "This is a test", cooked: "This is a test")
|
|
|
|
Migration::ColumnDropper.mark_readonly("posts", "cooked")
|
|
|
|
DbHelper.remap("test", "something else")
|
|
|
|
post.reload
|
|
|
|
expect(post.raw).to eq("This is a something else")
|
|
expect(post.cooked).to eq("This is a test")
|
|
|
|
DB.exec "DROP FUNCTION #{Migration::BaseDropper.readonly_function_name("posts", "cooked")} CASCADE"
|
|
end
|
|
|
|
context "when skip_max_length_violations is false" do
|
|
it "raises an exception if remap exceeds column length constraint by default" do
|
|
expect { DbHelper.remap("bookmark", long_bookmark_name) }.to raise_error(
|
|
PG::StringDataRightTruncation,
|
|
/value too long.*table: bookmarks,.*name/,
|
|
)
|
|
end
|
|
end
|
|
|
|
context "when skip_max_length_violations is true" do
|
|
it "skips a remap eligible row if new value exceeds column length constraint" do
|
|
DbHelper.remap("bookmark", long_bookmark_name, skip_max_length_violations: true)
|
|
|
|
bookmark1.reload
|
|
bookmark2.reload
|
|
|
|
expect(bookmark1.name).to eq("short-bookmark")
|
|
expect(bookmark2.name).to eq("another-bookmark")
|
|
end
|
|
|
|
it "logs skipped remaps due to max length constraints when verbose is true" do
|
|
expect {
|
|
DbHelper.remap(
|
|
"bookmark",
|
|
long_bookmark_name,
|
|
verbose: true,
|
|
skip_max_length_violations: true,
|
|
)
|
|
}.to output(/SKIPPED:/).to_stdout
|
|
|
|
bookmark1.reload
|
|
bookmark2.reload
|
|
|
|
expect(bookmark1.name).to eq("short-bookmark")
|
|
expect(bookmark2.name).to eq("another-bookmark")
|
|
end
|
|
end
|
|
end
|
|
|
|
describe ".regexp_replace" do
|
|
it "should remap columns correctly" do
|
|
post = Fabricate(:post, raw: "this is a [img]test[/img] post")
|
|
|
|
DbHelper.regexp_replace("\\[img\\]test\\[/img\\]", "[img]something[/img]")
|
|
|
|
expect(post.reload.raw).to include("[img]something[/img]")
|
|
end
|
|
end
|
|
end
|