diff --git a/backend/spec/requests/tag_description_wiki_write_spec.rb b/backend/spec/requests/tag_description_wiki_write_spec.rb index 6d83347..0b86adb 100644 --- a/backend/spec/requests/tag_description_wiki_write_spec.rb +++ b/backend/spec/requests/tag_description_wiki_write_spec.rb @@ -70,27 +70,12 @@ RSpec.describe 'Tag description Wiki dual writes', type: :request do tag_name:, body: 'before', created_by_user: user) end let!(:first_revision) { page.current_revision } - let!(:current_revision) do - # Repeated bodies create revisions, but no extra WikiVersion snapshot. - Wiki::Commit.content!(page:, body: 'before', created_user: user, - base_revision_id: first_revision.id) - end + let!(:description) do - TagDescription.create!( - id: page.id, tag:, language_code: 'ja', body: 'before', version_no: 2, - created_by_user_id: user.id, updated_by_user_id: user.id) + TagDescription.find_by!(tag_id: tag.id, language_code: 'ja') end - before do - [first_revision, current_revision].each_with_index do |revision, index| - TagDescriptionVersion.create!( - id: revision.id, tag_id: tag.id, language_code: 'ja', version_no: index + 1, - body: 'before', event_type: index.zero? ? 'create' : 'update', - created_by_user_id: user.id, created_at: revision.created_at) - end - end - - def update_description body: 'after', title: tag_name.name, base: current_revision.id + def update_description body: 'after', title: tag_name.name, base: first_revision.id put "/wiki/#{ page.id }", params: { title:, body:, message: 'edit', base_revision_id: base }, headers: headers @@ -98,7 +83,7 @@ RSpec.describe 'Tag description Wiki dual writes', type: :request do it 'increments the independent description sequence and shares revision identity' do expect(page.reload.version_no).to eq(1) - expect(description.version_no).to eq(2) + expect(description.version_no).to eq(1) expect { update_description } .to change(WikiRevision, :count).by(1) .and change(WikiVersion, :count).by(1) @@ -107,56 +92,116 @@ RSpec.describe 'Tag description Wiki dual writes', type: :request do revision = page.reload.current_revision version = TagDescriptionVersion.find(revision.id) - expect(description.reload).to have_attributes(body: 'after', version_no: 3) + expect(description.reload).to have_attributes(body: 'after', version_no: 2) expect(version).to have_attributes( - body: 'after', version_no: 3, event_type: 'update', created_by_user_id: user.id) + body: 'after', version_no: 2, event_type: 'update', created_by_user_id: user.id) expect(page).to have_attributes(body: 'after', version_no: 2) expect(revision.body).to eq(version.body) expect(page.wiki_versions.order(:version_no).last.body).to eq(version.body) end - it 'mirrors the Wiki revision for a title-only update despite identical bodies' do - expect { update_description(body: 'before', title: 'description_renamed') } - .to change(WikiRevision, :count).by(1) - .and change(TagDescriptionVersion, :count).by(1) + it 'does not add body history for a title-only update' do + revision_count = WikiRevision.count + wiki_version_count = WikiVersion.count + description_version_count = TagDescriptionVersion.count + wiki_version_no = page.reload.version_no + description_version_no = description.version_no + current_revision_id = page.current_revision.id + page_state = page.attributes + description_state = description.attributes + + update_description(body: 'before', title: 'description_renamed') + expect(response).to have_http_status(:ok) expect(tag_name.reload.name).to eq('description_renamed') - expect(description.reload).to have_attributes(body: 'before', version_no: 3) - - revision = page.reload.current_revision - version = TagDescriptionVersion.find(revision.id) - expect(revision.body).to eq('before') - expect(version).to have_attributes( - tag_id: tag.id, language_code: 'ja', body: 'before', version_no: 3, - event_type: 'update', created_by_user_id: user.id) - expect(TagDescriptionVersion.where(tag_id: tag.id, language_code: 'ja').order(:id).ids) - .to eq(page.wiki_revisions.order(:id).ids) + expect(WikiRevision.count).to eq(revision_count) + expect(WikiVersion.count).to eq(wiki_version_count) + expect(TagDescriptionVersion.count).to eq(description_version_count) + expect(page.reload).to have_attributes(body: 'before', version_no: wiki_version_no) + expect(page.current_revision.id).to eq(current_revision_id) + expect(page.reload.attributes).to eq(page_state) + expect(description.reload).to have_attributes( + body: 'before', version_no: description_version_no) + expect(description.reload.attributes).to eq(description_state) end - it 'does not add a description version for a TagName rename through tags' do - expect do - patch "/tags/#{ tag.id }", params: { name: 'description_tag_renamed' }, headers: headers - end.not_to change(TagDescriptionVersion, :count) + it 'does not add body history for a TagName rename through tags' do + revision_count = WikiRevision.count + wiki_version_count = WikiVersion.count + description_version_count = TagDescriptionVersion.count + page_version_no = page.reload.version_no + current_revision_id = page.current_revision.id + + patch "/tags/#{ tag.id }", + params: { name: 'description_tag_renamed' }, + headers: + expect(response).to have_http_status(:ok) expect(tag_name.reload.name).to eq('description_tag_renamed') - expect(description.reload).to have_attributes(body: 'before', version_no: 2) + expect(WikiRevision.count).to eq(revision_count) + expect(WikiVersion.count).to eq(wiki_version_count) + expect(TagDescriptionVersion.count).to eq(description_version_count) + expect(page.reload.version_no).to eq(page_version_no) + expect(page.current_revision.id).to eq(current_revision_id) + expect(description.reload).to have_attributes( + body: 'before', version_no: 1) end it 'keeps both systems and the title unchanged on a stale revision conflict' do + update_description(body: 'current body', base: first_revision.id) + expect(response).to have_http_status(:ok) + + stale_revision_id = first_revision.id before_state = stored_state - update_description(title: 'conflicting_rename', base: first_revision.id) + + update_description( + body: 'conflicting body', + title: 'conflicting_rename', + base: stale_revision_id) + expect(response).to have_http_status(:conflict) expect(stored_state).to eq(before_state) + expect(tag_name.reload.name).not_to eq('conflicting_rename') end [WikiPage, WikiRevision, WikiVersion, TagDescription, TagDescriptionVersion].each do |model| it "rolls back both systems when #{ model.name } persistence fails" do before_state = stored_state aggregate_failures do - fail_save(model) { update_description(title: 'rollback_rename') } + fail_save(model) do + update_description(body: 'rollback body', title: 'rollback_rename') + end expect(stored_state).to eq(before_state) end end end + + [['identical body', 'before'], + ['normalised-equivalent body', "before\n\n"]].each do |label, body| + it "does not write histories for #{ label }" do + before_state = stored_state + page_state = page.reload.attributes + description_state = description.reload.attributes + current_revision_id = page.current_revision.id + wiki_lines = WikiLine.order(:id).map(&:attributes) + revision_lines = WikiRevisionLine.order(:id).map(&:attributes) + page_version_no = page.version_no + description_version_no = description.version_no + + update_description(body:) + + expect(response).to have_http_status(:ok) + expect(WikiRevision.count).to eq(before_state[1].length) + expect(WikiVersion.count).to eq(before_state[2].length) + expect(TagDescriptionVersion.count).to eq(before_state[4].length) + expect(page.reload.version_no).to eq(page_version_no) + expect(description.reload.version_no).to eq(description_version_no) + expect(page.current_revision.id).to eq(current_revision_id) + expect(page.reload.attributes).to eq(page_state) + expect(description.reload.attributes).to eq(description_state) + expect(WikiLine.order(:id).map(&:attributes)).to eq(wiki_lines) + expect(WikiRevisionLine.order(:id).map(&:attributes)).to eq(revision_lines) + end + end end end diff --git a/backend/spec/requests/tag_descriptions_spec.rb b/backend/spec/requests/tag_descriptions_spec.rb index 104ef56..88d1a83 100644 --- a/backend/spec/requests/tag_descriptions_spec.rb +++ b/backend/spec/requests/tag_descriptions_spec.rb @@ -264,38 +264,49 @@ RSpec.describe 'Tag description native API', type: :request do tag Wiki::Commit.create_content!(tag_name:, body: 'before', created_by_user: author) end - let!(:second_revision) do - Wiki::Commit.content!(page:, body: 'before', created_user: author) - end let!(:description) do TagDescription.find_by!(tag_id: tag.id, language_code: 'ja') end - ['after', 'before'].each do |body| - it "appends matching revisions for body '#{ body }'" do - history = TagDescriptionVersion.where(tag_id: tag.id).order(:version_no).map(&:attributes) - expect(page.reload.version_no).to eq(1) - expect(description.version_no).to eq(2) - expect { native_write(:put, body:) } - .to change(WikiRevision, :count).by(1) - .and change(TagDescriptionVersion, :count).by(1) - expect(response).to have_http_status(:ok) - expect(description.reload).to have_attributes( - body:, version_no: 3, created_by_user_id: author.id, updated_by_user_id: editor.id) - expect(page.reload.body).to eq(body) - revision = page.current_revision - version = TagDescriptionVersion.find(revision.id) - expect(version).to have_attributes( - tag_id: tag.id, language_code: 'ja', version_no: 3, event_type: 'update', - body:, created_by_user_id: editor.id) - expect(revision.body).to eq(body) - expect(page.wiki_versions.order(:version_no).last.body).to eq(body) - expect(TagDescriptionVersion.where(id: history.pluck('id')).order(:version_no) - .map(&:attributes)).to eq(history) + it 'writes matching histories when the body changes' do + expect(page.reload.version_no).to eq(1) + expect(description.version_no).to eq(1) + expect { native_write(:put, body: 'after') } + .to change(WikiRevision, :count).by(1) + .and change(WikiVersion, :count).by(1) + .and change(TagDescriptionVersion, :count).by(1) + expect(response).to have_http_status(:ok) + expect(description.reload).to have_attributes( + body: 'after', version_no: 2, + created_by_user_id: author.id, updated_by_user_id: editor.id) + expect(page.reload).to have_attributes(body: 'after', version_no: 2) + + revision = page.current_revision + version = TagDescriptionVersion.find(revision.id) + expect(version).to have_attributes( + tag_id: tag.id, language_code: 'ja', version_no: 2, event_type: 'update', + body: 'after', created_by_user_id: editor.id) + expect(revision.body).to eq(version.body) + expect(page.wiki_versions.order(:version_no).last.body).to eq(version.body) + get "/wiki/#{ description.id }" + expect(response).to have_http_status(:ok) + expect(json).to include('body' => 'after', 'revision_id' => version.id) + end + + ['before', "before\n\n"].each do |body| + it 'does not write histories when the normalised body is unchanged' do + before_state = stored_state + page_state = page.reload.attributes + description_state = description.reload.attributes + current_revision_id = page.current_revision.id + + native_write(:put, body:) - get "/wiki/#{ description.id }" expect(response).to have_http_status(:ok) - expect(json).to include('body' => body, 'revision_id' => version.id) + expect(stored_state).to eq(before_state) + expect(page.reload.attributes).to eq(page_state) + expect(description.reload.attributes).to eq(description_state) + expect(page.current_revision.id).to eq(current_revision_id) end end