This is an automated email from the ASF dual-hosted git repository.

pjfanning pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/pekko-persistence-r2dbc.git


The following commit(s) were added to refs/heads/main by this push:
     new 2603950  Add negative tests for upsert after deleteObject with 
revision (#369)
2603950 is described below

commit 2603950c98304e48447a7ae674e7068feff124c7
Author: PJ Fanning <[email protected]>
AuthorDate: Thu May 14 17:33:36 2026 +0100

    Add negative tests for upsert after deleteObject with revision (#369)
    
    * Add negative tests for upsert after deleteObject with revision
    
    Agent-Logs-Url: 
https://github.com/pjfanning/incubator-pekko-persistence-r2dbc/sessions/e7b60541-a5d0-4608-8313-b253744ad670
    
    Co-authored-by: pjfanning <[email protected]>
    
    * Remove invalid revision=1 insert test after soft delete
    
    Agent-Logs-Url: 
https://github.com/pjfanning/incubator-pekko-persistence-r2dbc/sessions/a7b48548-1726-4355-871a-f8f89b8271ef
    
    Co-authored-by: pjfanning <[email protected]>
    
    ---------
    
    Co-authored-by: copilot-swe-agent[bot] 
<[email protected]>
    Co-authored-by: pjfanning <[email protected]>
---
 .../r2dbc/state/DurableStateStoreSpec.scala        | 52 ++++++++++++++++++++++
 1 file changed, 52 insertions(+)

diff --git 
a/core/src/test/scala/org/apache/pekko/persistence/r2dbc/state/DurableStateStoreSpec.scala
 
b/core/src/test/scala/org/apache/pekko/persistence/r2dbc/state/DurableStateStoreSpec.scala
index 4d12e1b..991edea 100644
--- 
a/core/src/test/scala/org/apache/pekko/persistence/r2dbc/state/DurableStateStoreSpec.scala
+++ 
b/core/src/test/scala/org/apache/pekko/persistence/r2dbc/state/DurableStateStoreSpec.scala
@@ -167,6 +167,58 @@ class DurableStateStoreSpec
       store.getObject(persistenceId).futureValue should 
be(GetObjectResult(None, 5L))
     }
 
+    "upsert with correct revision after delete succeeds" in {
+      val entityType = nextEntityType()
+      val persistenceId = PersistenceId(entityType, 
"to-be-deleted-then-re-inserted").id
+      val value1 = "initial value"
+      store.upsertObject(persistenceId, 1L, value1, unusedTag).futureValue
+      store.getObject(persistenceId).futureValue should 
be(GetObjectResult(Some(value1), 1L))
+      store.deleteObject(persistenceId, revision = 2L).futureValue
+      store.getObject(persistenceId).futureValue should 
be(GetObjectResult(None, 2L))
+
+      val value2 = "new value after delete"
+      store.upsertObject(persistenceId, 3L, value2, unusedTag).futureValue
+      store.getObject(persistenceId).futureValue should 
be(GetObjectResult(Some(value2), 3L))
+    }
+
+    "reject upsert with same revision as delete revision" in {
+      if (!stateSettings.durableStateAssertSingleWriter)
+        pending
+
+      val entityType = nextEntityType()
+      val persistenceId = PersistenceId(entityType, 
"to-be-deleted-then-bad-update-same-rev").id
+      val value = "initial value"
+      store.upsertObject(persistenceId, 1L, value, unusedTag).futureValue
+      store.getObject(persistenceId).futureValue should 
be(GetObjectResult(Some(value), 1L))
+      store.deleteObject(persistenceId, revision = 2L).futureValue
+      store.getObject(persistenceId).futureValue should 
be(GetObjectResult(None, 2L))
+
+      // revision=2 is already used by the delete; next valid revision is 3
+      val failure =
+        store.upsertObject(persistenceId, revision = 2L, "wrong value", 
unusedTag).failed.futureValue
+      failure.getMessage should include(
+        s"Update failed: durable state for persistence id [$persistenceId] 
could not be updated to revision [2]")
+    }
+
+    "reject upsert with skipped revision after delete" in {
+      if (!stateSettings.durableStateAssertSingleWriter)
+        pending
+
+      val entityType = nextEntityType()
+      val persistenceId = PersistenceId(entityType, 
"to-be-deleted-then-bad-update-skipped-rev").id
+      val value = "initial value"
+      store.upsertObject(persistenceId, 1L, value, unusedTag).futureValue
+      store.getObject(persistenceId).futureValue should 
be(GetObjectResult(Some(value), 1L))
+      store.deleteObject(persistenceId, revision = 2L).futureValue
+      store.getObject(persistenceId).futureValue should 
be(GetObjectResult(None, 2L))
+
+      // revision=4 skips revision 3; the correct next revision after delete 
at 2 is 3
+      val failure =
+        store.upsertObject(persistenceId, revision = 4L, "wrong value", 
unusedTag).failed.futureValue
+      failure.getMessage should include(
+        s"Update failed: durable state for persistence id [$persistenceId] 
could not be updated to revision [4]")
+    }
+
     "detect and reject concurrent delete of revision 1" in {
       val entityType = nextEntityType()
       val persistenceId = PersistenceId(entityType, 
"id-to-be-deleted-concurrently")


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to