summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorerdgeist <erdgeist@erdgeist.org>2026-07-08 16:22:17 +0200
committererdgeist <erdgeist@erdgeist.org>2026-07-08 16:22:17 +0200
commita006440f59bf99380e179cc2963cb98d4d894d3a (patch)
treeae74b9bdf00e7218b90a6cb2c119504419fa8ae4 /test
parent08b4cdb711ffe39153264a5c4024fac95cd8d91a (diff)
Add head/draft/autosave hierarchy to Node
Introduces autosave_id as a third, unversioned layer above draft/head, with lock_for_editing!, autosave!, and save_draft! as the new entry points. Also fixes a real bug in wipe_draft!: its "no draft" branch unconditionally released the lock, which was safe when "no draft" only ever meant "nothing is happening" — no longer true now that a lock can exist with only an autosave beneath it. lock_for_editing! deliberately does not call wipe_draft! at all, for the same reason: an intruder calling it while a lock was genuinely held would otherwise silently steal it via wipe_draft!'s own unlock side effect, caught by the new two-user lock test.
Diffstat (limited to 'test')
-rw-r--r--test/models/node_test.rb96
1 files changed, 96 insertions, 0 deletions
diff --git a/test/models/node_test.rb b/test/models/node_test.rb
index 514ba3f..2953f8f 100644
--- a/test/models/node_test.rb
+++ b/test/models/node_test.rb
@@ -98,6 +98,7 @@ class NodeTest < ActiveSupport::TestCase
98 assert_not_nil node.draft 98 assert_not_nil node.draft
99 assert_nil node.draft.user 99 assert_nil node.draft.user
100 assert_nil node.head 100 assert_nil node.head
101 assert_nil node.autosave
101 end 102 end
102 103
103 def test_create_new_draft_of_published_page 104 def test_create_new_draft_of_published_page
@@ -280,6 +281,101 @@ class NodeTest < ActiveSupport::TestCase
280 node = Node.root.children.create( :slug => "wow" ) 281 node = Node.root.children.create( :slug => "wow" )
281 assert_nil node.draft.published_at 282 assert_nil node.draft.published_at
282 end 283 end
284
285 test "lock_for_editing! acquires the lock without creating a draft or autosave" do
286 node = create_node_with_published_page
287
288 node.lock_for_editing!(@user1)
289
290 assert_equal @user1, node.lock_owner
291 assert_nil node.draft
292 assert_nil node.autosave
293 end
294
295 test "autosave! creates a buffer that never appears among a node's pages, leaving the draft untouched" do
296 node = create_node_with_draft
297 node.lock_for_editing!(@user1)
298 page_count_before = node.pages.count
299
300 node.autosave!({ :title => "in progress" }, @user1)
301 node.reload
302
303 assert_not_nil node.autosave
304 assert_nil node.autosave.node_id
305 assert_equal page_count_before, node.pages.count
306 assert_not_equal "in progress", node.draft.title
307 end
308
309 test "save_draft! promotes an autosave into an existing draft without creating a new revision" do
310 node = create_node_with_draft
311 node.lock_for_editing!(@user1)
312 node.autosave!({ :title => "in progress" }, @user1)
313 page_count_before = node.pages.count
314
315 node.save_draft!(@user1)
316 node.reload
317
318 assert_nil node.autosave
319 assert_equal "in progress", node.draft.title
320 assert_equal page_count_before, node.pages.count
321 end
322
323 test "save_draft! promotes an autosave into a brand new, correctly-revisioned draft when none exists" do
324 node = create_node_with_published_page
325 head_revision = node.head.revision
326
327 node.lock_for_editing!(@user1)
328 node.autosave!({ :title => "updated version" }, @user1)
329 node.reload
330
331 assert_nil node.draft
332 assert_nil node.autosave.node_id
333
334 node.save_draft!(@user1)
335 node.reload
336
337 assert_not_nil node.draft
338 assert_equal head_revision + 1, node.draft.revision
339 assert_equal head_revision, node.head.revision
340 assert_nil node.autosave
341 assert_equal 2, node.pages.count
342 end
343
344 test "autosave!, save_draft!, and lock_for_editing! raise LockedByAnotherUser for a second user" do
345 node = create_node_with_published_page
346 node.lock_for_editing!(@user1)
347
348 assert_raise(LockedByAnotherUser) { node.autosave!({ :title => "x" }, @user2) }
349 assert_raise(LockedByAnotherUser) { node.save_draft!(@user2) }
350 assert_raise(LockedByAnotherUser) { node.lock_for_editing!(@user2) }
351
352 assert_equal @user1, node.reload.lock_owner
353 end
354
355 test "wipe_draft! leaves a fresh autosave and its lock untouched" do
356 node = create_node_with_published_page
357 node.lock_for_editing!(@user1)
358 node.autosave!({ :title => "still typing" }, @user1)
359
360 node.wipe_draft!
361 node.reload
362
363 assert_not_nil node.autosave
364 assert_equal @user1, node.lock_owner
365 end
366
367 test "wipe_draft! destroys a stale, orphaned autosave and releases its lock" do
368 node = create_node_with_published_page
369 node.lock_for_editing!(@user1)
370 node.autosave!({ :title => "abandoned mid-session" }, @user1)
371 node.autosave.update_column(:updated_at, 2.days.ago)
372
373 node.wipe_draft!
374 node.reload
375
376 assert_nil node.autosave
377 assert_nil node.lock_owner
378 end
283 379
284 def create_revisions node, count 380 def create_revisions node, count
285 count.times do 381 count.times do