You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by st...@apache.org on 2024/03/27 16:23:18 UTC

(jackrabbit-oak) branch DetailedGC/OAK-10199 updated: OAK-10726 : fix and gctype-parameterize BranchCommitGCTest (#1386)

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

stefanegli pushed a commit to branch DetailedGC/OAK-10199
in repository https://gitbox.apache.org/repos/asf/jackrabbit-oak.git


The following commit(s) were added to refs/heads/DetailedGC/OAK-10199 by this push:
     new a48e138eea OAK-10726 : fix and gctype-parameterize BranchCommitGCTest (#1386)
a48e138eea is described below

commit a48e138eea235b9c0e689d64567a02421821cdda
Author: stefan-egli <st...@apache.org>
AuthorDate: Wed Mar 27 17:23:12 2024 +0100

    OAK-10726 : fix and gctype-parameterize BranchCommitGCTest (#1386)
    
    * OAK-10726 : fix and gctype-parameterize BranchCommitGCTest
    
    * OAK-10726 : add gcType as parameter also for VersionGarbageCollectorIT
---
 .../plugins/document/VersionGarbageCollector.java  |   6 +-
 .../oak/plugins/document/BranchCommitGCTest.java   | 221 ++++++++++----------
 .../oak/plugins/document/DetailGCHelper.java       |   4 +-
 .../document/VersionGarbageCollectorIT.java        | 230 +++++++++++++--------
 4 files changed, 272 insertions(+), 189 deletions(-)

diff --git a/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/VersionGarbageCollector.java b/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/VersionGarbageCollector.java
index 332956d110..11933267a2 100644
--- a/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/VersionGarbageCollector.java
+++ b/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/VersionGarbageCollector.java
@@ -155,7 +155,11 @@ public class VersionGarbageCollector {
         OLDER_THAN_24H_AND_BETWEEN_CHECKPOINTS_MODE
     }
 
-    final static RDGCType revisionDetailedGcType = RDGCType.NO_OLD_PROP_REV_GC;
+    private static RDGCType revisionDetailedGcType = RDGCType.NO_OLD_PROP_REV_GC;
+
+    static RDGCType getRevisionDetailedGcType() {
+        return revisionDetailedGcType;
+    }
 
     private final DocumentNodeStore nodeStore;
     private final DocumentStore ds;
diff --git a/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/BranchCommitGCTest.java b/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/BranchCommitGCTest.java
index e6198a57c9..102bf2f1b5 100644
--- a/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/BranchCommitGCTest.java
+++ b/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/BranchCommitGCTest.java
@@ -17,6 +17,7 @@
 package org.apache.jackrabbit.oak.plugins.document;
 
 import org.apache.jackrabbit.oak.plugins.document.DocumentMK.Builder;
+import org.apache.jackrabbit.oak.plugins.document.VersionGarbageCollector.RDGCType;
 import org.apache.jackrabbit.oak.plugins.document.util.Utils;
 import org.apache.jackrabbit.oak.spi.commit.CommitInfo;
 import org.apache.jackrabbit.oak.spi.commit.EmptyHook;
@@ -26,7 +27,11 @@ import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 
+import java.io.IOException;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
@@ -37,14 +42,22 @@ import java.util.function.Consumer;
 
 import static java.util.concurrent.TimeUnit.HOURS;
 import static org.apache.commons.lang3.reflect.FieldUtils.writeField;
+import static org.apache.commons.lang3.reflect.FieldUtils.writeStaticField;
 import static org.apache.jackrabbit.oak.plugins.document.DetailGCHelper.assertBranchRevisionRemovedFromAllDocuments;
 import static org.apache.jackrabbit.oak.plugins.document.DetailGCHelper.build;
+import static org.apache.jackrabbit.oak.plugins.document.VersionGarbageCollectorIT.noOldPropGc;
+import static org.apache.jackrabbit.oak.plugins.document.VersionGarbageCollectorIT.keepOneFull;
+import static org.apache.jackrabbit.oak.plugins.document.VersionGarbageCollectorIT.keepOneUser;
+import static org.apache.jackrabbit.oak.plugins.document.VersionGarbageCollectorIT.betweenChkp;
+import static org.apache.jackrabbit.oak.plugins.document.VersionGarbageCollectorIT.assertStatsCountsEqual;
+import static org.apache.jackrabbit.oak.plugins.document.VersionGarbageCollectorIT.assertStatsCountsZero;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
+@RunWith(Parameterized.class)
 public class BranchCommitGCTest {
 
     @Rule
@@ -54,8 +67,28 @@ public class BranchCommitGCTest {
     private VersionGarbageCollector gc;
     private VersionGarbageCollector.VersionGCStats stats;
 
+    @Parameterized.Parameters(name="{index}: {0} with {1}")
+    public static java.util.Collection<Object[]> params() throws IOException {
+        java.util.Collection<Object[]> params = new LinkedList<>();
+        for (Object[] fixture : AbstractDocumentStoreTest.fixtures()) {
+            DocumentStoreFixture f = (DocumentStoreFixture)fixture[0];
+            for (RDGCType gcType : RDGCType.values()) {
+                params.add(new Object[] {f, gcType});
+            }
+        }
+        return params;
+    }
+
+    @Parameter(0)
+    public DocumentStoreFixture fixture;
+
+    @Parameter(1)
+    public RDGCType gcType;
+
+    private RDGCType originalGcType;
+
     @Before
-    public void setUp() throws InterruptedException {
+    public void setUp() throws Exception {
         clock = new Clock.Virtual();
         clock.waitUntil(System.currentTimeMillis());
         Revision.setClock(clock);
@@ -63,10 +96,13 @@ public class BranchCommitGCTest {
                 .setLeaseCheckMode(LeaseCheckMode.DISABLED).setDetailedGCEnabled(true)
                 .setAsyncDelay(0).getNodeStore();
         gc = store.getVersionGarbageCollector();
+        originalGcType = VersionGarbageCollector.getRevisionDetailedGcType();
+        writeStaticField(VersionGarbageCollector.class, "revisionDetailedGcType", gcType, true);
     }
 
     @After
     public void tearDown() throws Exception {
+        writeStaticField(VersionGarbageCollector.class, "revisionDetailedGcType", originalGcType, true);
         assertNoEmptyProperties();
         if (store != null) {
             store.dispose();
@@ -92,24 +128,16 @@ public class BranchCommitGCTest {
         // clean everything older than one hour
         VersionGarbageCollector.VersionGCStats stats = gc.gc(1, HOURS);
 
-        assertEquals(2, stats.updatedDetailedGCDocsCount);
-        assertEquals(2, stats.deletedDocGCCount);
-        assertEquals(0, stats.deletedUnmergedBCCount);
-        assertEquals(0, stats.deletedPropRevsCount);
-        assertEquals(0, stats.deletedInternalPropRevsCount);
-        assertEquals(0, stats.deletedPropsCount);
-        assertEquals(0, stats.deletedInternalPropsCount);
+        assertStatsCountsEqual(stats,
+                noOldPropGc(2, 0, 0, 0, 0, 0, 2),
+                keepOneFull(2, 0, 0, 0, 0, 0, 2),
+                keepOneUser(2, 0, 0, 0, 0, 0, 2),
+                betweenChkp(2, 0, 1, 0, 2, 1, 3));
 
         // now do another gc - should not have anything left to clean up though
         clock.waitUntil(clock.getTime() + HOURS.toMillis(2));
         stats = gc.gc(1, HOURS);
-        assertEquals(0, stats.updatedDetailedGCDocsCount);
-        assertEquals(0, stats.deletedDocGCCount);
-        assertEquals(0, stats.deletedUnmergedBCCount);
-        assertEquals(0, stats.deletedPropRevsCount);
-        assertEquals(0, stats.deletedInternalPropRevsCount);
-        assertEquals(0, stats.deletedPropRevsCount);
-        assertEquals(0, stats.deletedInternalPropsCount);
+        assertStatsCountsZero(stats);
         assertNotExists("1:/a");
         assertNotExists("1:/b");
         assertBranchRevisionRemovedFromAllDocuments(store, br);
@@ -149,21 +177,22 @@ public class BranchCommitGCTest {
         clock.waitUntil(clock.getTime() + HOURS.toMillis(2));
         // clean everything older than one hour
         VersionGarbageCollector.VersionGCStats stats = gc.gc(1, HOURS);
-        assertTrue("stats.updatedDetailedGCDocsCount expected 1 or less, was: " + stats.updatedDetailedGCDocsCount,
-                stats.updatedDetailedGCDocsCount <= 1);
-        assertEquals(2, stats.deletedDocGCCount);
-        assertEquals(0, stats.deletedUnmergedBCCount);
+
         if (collisionsBeforeGC == 1) {
             // expects a collision to have happened - which was cleaned up - hence a _bc (but not the _revision I guess)
-            assertEquals(0, stats.deletedPropRevsCount);
             // the collisions cleaned up - with the 1 collision and a _bc
-            assertEquals(0, stats.deletedPropsCount);
-            assertEquals(1, stats.deletedInternalPropsCount);
+            assertStatsCountsEqual(stats,
+                    noOldPropGc(2, 0, 0, 0, 0, 0, 0),
+                    keepOneFull(2, 0, 1, 0, 2, 0, 1),
+                    keepOneUser(2, 0, 0, 0, 0, 0, 0),
+                    betweenChkp(2, 0, 1, 0, 3, 1, 1));
         } else {
             // in this case classic collision cleanup already took care of everything, nothing left
-            assertEquals(0, stats.deletedPropRevsCount);
-            // the collisions cleaned up - even though empty
-            assertEquals(1, stats.deletedPropsCount);
+            assertStatsCountsEqual(stats,
+                    noOldPropGc(2, 0, 0, 0, 0, 0, 0),
+                    keepOneFull(2, 1, 0, 0, 0, 0, 0),
+                    keepOneUser(2, 1, 0, 0, 0, 0, 0),
+                    betweenChkp(2, 1, 0, 0, 0, 0, 0));
         }
 
         assertNotExists("1:/a");
@@ -217,12 +246,11 @@ public class BranchCommitGCTest {
         VersionGarbageCollector.VersionGCStats stats = gc.gc(1, HOURS);
 
         // 6 deleted props: 0:/[_collisions], 1:/foo[p, a], 1:/bar[_bc,prop,_revisions]
-        assertEquals(3, stats.deletedPropsCount);
-        assertEquals(3, stats.deletedInternalPropsCount);
-        assertEquals(1, stats.deletedPropRevsCount);
-        assertEquals(17, stats.deletedInternalPropRevsCount);
-        assertEquals(0, stats.deletedUnmergedBCCount);
-        assertEquals(3, stats.updatedDetailedGCDocsCount);
+        assertStatsCountsEqual(stats,
+                noOldPropGc(0, 3, 0, 0, 0, 0, 2),
+                keepOneFull(0, 3, 3, 1,17, 0, 3),
+                keepOneUser(0, 3, 0, 1, 0, 0, 2),
+                betweenChkp(0, 3, 2, 1,18, 4, 3));
         assertBranchRevisionRemovedFromAllDocuments(store, br1);
         assertBranchRevisionRemovedFromAllDocuments(store, br2);
         assertBranchRevisionRemovedFromAllDocuments(store, br3);
@@ -251,14 +279,11 @@ public class BranchCommitGCTest {
         // clean everything older than one hour
         VersionGarbageCollector.VersionGCStats stats = gc.gc(1, HOURS);
 
-        assertEquals(3, stats.updatedDetailedGCDocsCount);
-        assertEquals(2, stats.deletedDocGCCount);
-        assertEquals(0, stats.deletedUnmergedBCCount);
-        assertEquals(0, stats.deletedPropsCount);
-        assertEquals(1, stats.deletedInternalPropsCount);
-        assertEquals(0, stats.deletedPropRevsCount);
-        assertEquals(0, stats.deletedInternalPropRevsCount);
-        assertEquals(0, stats.deletedPropRevsCount);
+        assertStatsCountsEqual(stats,
+                noOldPropGc(2, 0, 0, 0, 0, 0, 2),
+                keepOneFull(2, 0, 1, 0, 0, 0, 3),
+                keepOneUser(2, 0, 0, 0, 0, 0, 2),
+                betweenChkp(2, 0, 2, 0, 5, 2, 3));
 
         assertNotExists("1:/a");
         assertNotExists("1:/b");
@@ -266,13 +291,7 @@ public class BranchCommitGCTest {
         // now do another gc - should not have anything left to clean up though
         clock.waitUntil(clock.getTime() + HOURS.toMillis(2));
         stats = gc.gc(1, HOURS);
-        assertEquals(0, stats.updatedDetailedGCDocsCount);
-        assertEquals(0, stats.deletedDocGCCount);
-        assertEquals(0, stats.deletedUnmergedBCCount);
-        assertEquals(0, stats.deletedPropRevsCount);
-        assertEquals(0, stats.deletedInternalPropsCount);
-        assertEquals(0, stats.deletedPropRevsCount);
-        assertEquals(0, stats.deletedInternalPropRevsCount);
+        assertStatsCountsZero(stats);
         assertBranchRevisionRemovedFromAllDocuments(store, br1);
         assertBranchRevisionRemovedFromAllDocuments(store, br2);
     }
@@ -306,23 +325,18 @@ public class BranchCommitGCTest {
         // clean everything older than one hour
         VersionGarbageCollector.VersionGCStats stats = gc.gc(1, HOURS);
 
-        assertTrue("should have been 2 or more, was: " + stats.updatedDetailedGCDocsCount,
-                stats.updatedDetailedGCDocsCount >= 2);
-        assertEquals(0, stats.deletedDocGCCount);
-        assertEquals(0, stats.deletedUnmergedBCCount);
-        assertEquals(4, stats.deletedPropRevsCount);
-        assertEquals(12, stats.deletedInternalPropRevsCount);
-
+        assertStatsCountsEqual(stats,
+                noOldPropGc(0, 0, 0, 0, 0, 0, 0),
+                keepOneFull(0, 0, 1, 4,12, 0, 3),
+                keepOneUser(0, 0, 0, 4, 0, 0, 2),
+                betweenChkp(0, 0, 1, 0,18, 2, 3));
         assertExists("1:/a");
         assertExists("1:/b");
 
         // now do another gc to get those documents actually deleted
         clock.waitUntil(clock.getTime() + HOURS.toMillis(2));
         stats = gc.gc(1, HOURS);
-        assertEquals(0, stats.updatedDetailedGCDocsCount);
-        assertEquals(0, stats.deletedDocGCCount);
-        assertEquals(0, stats.deletedUnmergedBCCount);
-        assertEquals(0, stats.deletedPropRevsCount);
+        assertStatsCountsZero(stats);
         assertBranchRevisionRemovedFromAllDocuments(store, br1);
         assertBranchRevisionRemovedFromAllDocuments(store, br2);
     }
@@ -367,22 +381,18 @@ public class BranchCommitGCTest {
         // clean everything older than one hour
         VersionGarbageCollector.VersionGCStats stats = gc.gc(1, HOURS);
 
-        assertEquals(3, stats.updatedDetailedGCDocsCount);
-        assertEquals(0, stats.deletedDocGCCount);
-        assertEquals(8, stats.deletedPropRevsCount);
-        assertEquals(20, stats.deletedInternalPropRevsCount);
-        assertEquals(0, stats.deletedUnmergedBCCount);
-
+        assertStatsCountsEqual(stats,
+                noOldPropGc(0, 0, 0, 0, 0, 0, 0),
+                keepOneFull(0, 0, 1, 8,20, 0, 3),
+                keepOneUser(0, 0, 0, 8, 0, 0, 2),
+                betweenChkp(0, 0, 1, 0,35, 4, 3));
         assertExists("1:/a");
         assertExists("1:/b");
 
         // now do another gc to get those documents actually deleted
         clock.waitUntil(clock.getTime() + HOURS.toMillis(2));
         stats = gc.gc(1, HOURS);
-        assertEquals(0, stats.updatedDetailedGCDocsCount);
-        assertEquals(0, stats.deletedDocGCCount);
-        assertEquals(0, stats.deletedPropRevsCount);
-        assertEquals(0, stats.deletedUnmergedBCCount);
+        assertStatsCountsZero(stats);
         assertBranchRevisionRemovedFromAllDocuments(store, br1);
         assertBranchRevisionRemovedFromAllDocuments(store, br2);
         assertBranchRevisionRemovedFromAllDocuments(store, br3);
@@ -407,20 +417,17 @@ public class BranchCommitGCTest {
         VersionGarbageCollector.VersionGCStats stats = gc.gc(1, HOURS);
 
         // first gc round now deletes it, via orphaned node deletion
-        assertEquals(1, stats.deletedDocGCCount);
-        assertEquals(3, stats.updatedDetailedGCDocsCount);
-        assertEquals(0, stats.deletedUnmergedBCCount);
-        assertEquals(1, stats.deletedPropRevsCount);
-        assertEquals(4, stats.deletedInternalPropRevsCount);
+        assertStatsCountsEqual(stats,
+                noOldPropGc(1, 0, 0, 0, 0, 0, 1),
+                keepOneFull(1, 0, 0, 1, 4, 0, 3),
+                keepOneUser(1, 0, 0, 1, 0, 0, 2),
+                betweenChkp(1, 0, 0, 0, 7, 1, 4));
 
         // wait two hours
         clock.waitUntil(clock.getTime() + HOURS.toMillis(2));
         // now do second gc round - should not have anything left to clean up though
         stats = gc.gc(1, HOURS);
-        assertEquals(0, stats.updatedDetailedGCDocsCount);
-        assertEquals(0, stats.deletedDocGCCount);
-        assertEquals(0, stats.deletedUnmergedBCCount);
-        assertEquals(0, stats.deletedPropRevsCount);
+        assertStatsCountsZero(stats);
         assertBranchRevisionRemovedFromAllDocuments(store, br);
     }
 
@@ -442,12 +449,11 @@ public class BranchCommitGCTest {
         // clean everything older than one hour
         stats = gc.gc(1, HOURS);
 
-        assertEquals(0, stats.deletedPropsCount);
-        assertEquals(0, stats.deletedInternalPropsCount);
-        assertEquals(1, stats.deletedPropRevsCount);
-        assertEquals(4, stats.deletedInternalPropRevsCount);
-        assertEquals(0, stats.deletedUnmergedBCCount);
-        assertEquals(2, stats.updatedDetailedGCDocsCount);
+        assertStatsCountsEqual(stats,
+                noOldPropGc(0, 0, 0, 0, 0, 0, 0),
+                keepOneFull(0, 0, 0, 1, 4, 0, 2),
+                keepOneUser(0, 0, 0, 1, 0, 0, 1),
+                betweenChkp(0, 0, 0, 1, 4, 1, 2));
         assertBranchRevisionRemovedFromAllDocuments(store, br);
     }
 
@@ -462,13 +468,12 @@ public class BranchCommitGCTest {
         // clean everything older than one hour
         stats = gc.gc(1, HOURS);
 
-        assertEquals(1, stats.updatedDetailedGCDocsCount);
         // 1 deleted prop: 1:/foo[a]
-        assertEquals(1, stats.deletedPropsCount);
-        assertEquals(0, stats.deletedInternalPropsCount);
-        assertEquals(0, stats.deletedPropRevsCount);
-        assertEquals(2, stats.deletedInternalPropRevsCount);
-        assertEquals(0, stats.deletedUnmergedBCCount);
+        assertStatsCountsEqual(stats,
+                noOldPropGc(0, 1, 0, 0, 0, 0, 1),
+                keepOneFull(0, 1, 0, 0, 2, 0, 1),
+                keepOneUser(0, 1, 0, 0, 0, 0, 1),
+                betweenChkp(0, 1, 0, 0, 4, 1, 2));
         assertBranchRevisionRemovedFromAllDocuments(store, br);
     }
 
@@ -498,10 +503,11 @@ public class BranchCommitGCTest {
         // clean everything older than one hour
         stats = gc.gc(1, HOURS);
 
-        assertEquals(2, stats.updatedDetailedGCDocsCount);
-        assertEquals(0, stats.deletedUnmergedBCCount);
-        assertEquals(10, stats.deletedPropRevsCount);
-        assertEquals(20, stats.deletedInternalPropRevsCount);
+        assertStatsCountsEqual(stats,
+                noOldPropGc(0, 0, 0, 0, 0, 0, 0),
+                keepOneFull(0, 0, 1,10,20, 0, 2),
+                keepOneUser(0, 0, 0,10, 0, 0, 1),
+                betweenChkp(0, 0, 1, 0,59,10, 2));
 
         doc = store.getDocumentStore().find(Collection.NODES, "1:/foo");
         Long finalModified = doc.getModified();
@@ -540,10 +546,11 @@ public class BranchCommitGCTest {
         // clean everything older than one hour
         stats = gc.gc(1, HOURS);
 
-        assertEquals(2, stats.updatedDetailedGCDocsCount);
-        assertEquals(10, stats.deletedPropRevsCount);
-        assertEquals(20, stats.deletedInternalPropRevsCount);
-        assertEquals(0, stats.deletedUnmergedBCCount);
+        assertStatsCountsEqual(stats,
+                noOldPropGc(0, 0, 0, 0, 0, 0, 0),
+                keepOneFull(0, 0, 1,10,20, 0, 2),
+                keepOneUser(0, 0, 0,10, 0, 0, 1),
+                betweenChkp(0, 0, 2, 0,59,10, 2));
         for (RevisionVector br : brs) {
             assertBranchRevisionRemovedFromAllDocuments(store, br);
         }
@@ -589,25 +596,29 @@ public class BranchCommitGCTest {
         // clean everything older than one hour
         stats = gc.gc(1, HOURS);
 
-        assertEquals(2, stats.updatedDetailedGCDocsCount);
-        assertEquals(0, stats.deletedUnmergedBCCount);
-        assertEquals(0, stats.deletedPropRevsCount);
-        assertEquals(6, stats.deletedInternalPropRevsCount);
+        // deleted props: 0:/[rootProp], 1:/foo[a]
+        // deleted internal prop : 0:/ _collision
         // deleted properties are 0:/ -> rootProp, _collisions & 1:/foo -> a
+        assertStatsCountsEqual(stats,
+                noOldPropGc(0, 2, 0, 0, 0, 0, 2),
+                keepOneFull(0, 2, 1, 0, 6, 0, 2),
+                keepOneUser(0, 2, 0, 0, 0, 0, 2),
+                betweenChkp(0, 2, 1, 0, 5, 1, 2));
         {
             // some flakyness diagnostics
             NodeDocument d = store.getDocumentStore().find(Collection.NODES, "0:/", -1);
             assertNotNull(d);
             assertEquals(0, d.getLocalMap("rootProp").size());
-            assertEquals(0, d.getLocalMap("_collisions").size());
+            if (VersionGarbageCollector.getRevisionDetailedGcType() == RDGCType.KEEP_ONE_FULL_MODE
+                    || VersionGarbageCollector.getRevisionDetailedGcType() == RDGCType.OLDER_THAN_24H_AND_BETWEEN_CHECKPOINTS_MODE) {
+                assertEquals(0, d.getLocalMap("_collisions").size());
+            } else {
+                assertEquals(1, d.getLocalMap("_collisions").size());
+            }
             d = store.getDocumentStore().find(Collection.NODES, "1:/foo", -1);
             assertNotNull(d);
             assertEquals(0, d.getLocalMap("a").size());
         }
-        // deleted props: 0:/[rootProp], 1:/foo[a]
-        assertEquals(2, stats.deletedPropsCount);
-        // deleted prop : 0:/ _collision
-        assertEquals(1, stats.deletedInternalPropsCount);
         assertBranchRevisionRemovedFromAllDocuments(store, br);
     }
 
diff --git a/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/DetailGCHelper.java b/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/DetailGCHelper.java
index 9c22f28a63..6bbda403d6 100644
--- a/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/DetailGCHelper.java
+++ b/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/DetailGCHelper.java
@@ -74,7 +74,7 @@ public class DetailGCHelper {
             final DocumentNodeStore store, final RevisionVector br,
             final String... exceptIds) {
         assertTrue(br.isBranch());
-        if (VersionGarbageCollector.revisionDetailedGcType == RDGCType.NO_OLD_PROP_REV_GC) {
+        if (VersionGarbageCollector.getRevisionDetailedGcType() == RDGCType.NO_OLD_PROP_REV_GC) {
             // then we must skip these asserts, as we cannot guarantee
             // that all revisions are cleaned up in this mode
             return;
@@ -96,7 +96,7 @@ public class DetailGCHelper {
             for (Entry<String, Object> e : target.data.entrySet()) {
                 String k = e.getKey();
                 final boolean internal = k.startsWith("_");
-                final boolean dgcSupportsInternalPropCleanup = (VersionGarbageCollector.revisionDetailedGcType != RDGCType.KEEP_ONE_CLEANUP_USER_PROPERTIES_ONLY_MODE);
+                final boolean dgcSupportsInternalPropCleanup = (VersionGarbageCollector.getRevisionDetailedGcType() != RDGCType.KEEP_ONE_CLEANUP_USER_PROPERTIES_ONLY_MODE);
                 if (internal && !dgcSupportsInternalPropCleanup) {
                     // skip
                     continue;
diff --git a/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/VersionGarbageCollectorIT.java b/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/VersionGarbageCollectorIT.java
index fdc53cb5f0..854ad7b69b 100644
--- a/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/VersionGarbageCollectorIT.java
+++ b/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/VersionGarbageCollectorIT.java
@@ -23,6 +23,7 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashSet;
 import java.util.Iterator;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
@@ -46,6 +47,7 @@ import static java.util.concurrent.TimeUnit.MILLISECONDS;
 import static java.util.stream.Collectors.toList;
 import static java.util.stream.StreamSupport.stream;
 import static org.apache.commons.lang3.reflect.FieldUtils.writeField;
+import static org.apache.commons.lang3.reflect.FieldUtils.writeStaticField;
 import static org.apache.jackrabbit.guava.common.base.Strings.repeat;
 import static org.apache.jackrabbit.guava.common.collect.Iterables.filter;
 import static org.apache.jackrabbit.guava.common.collect.Iterables.size;
@@ -130,11 +132,12 @@ import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 
 @RunWith(Parameterized.class)
 public class VersionGarbageCollectorIT {
 
-    private class GCCounts {
+    static class GCCounts {
         RDGCType mode;
         int deletedDocGCCount, deletedPropsCount, deletedInternalPropsCount,
                 deletedPropRevsCount, deletedInternalPropRevsCount,
@@ -145,6 +148,21 @@ public class VersionGarbageCollectorIT {
                 int deletedInternalPropRevsCount, int deletedUnmergedBCCount,
                 int updatedDetailedGCDocsCount) {
             this.mode = mode;
+            assertTrue(deletedDocGCCount != -1);
+            assertTrue(deletedPropsCount != -1);
+            assertTrue(deletedInternalPropsCount != -1);
+            assertTrue(deletedPropRevsCount != -1);
+            assertTrue(deletedInternalPropRevsCount != -1);
+            assertTrue(deletedUnmergedBCCount != -1);
+            assertTrue(updatedDetailedGCDocsCount != -1);
+            if (mode == RDGCType.NO_OLD_PROP_REV_GC) {
+                assertEquals(0, deletedPropRevsCount);
+                assertEquals(0, deletedInternalPropRevsCount);
+                assertEquals(0, deletedUnmergedBCCount);
+            } else if (mode == RDGCType.KEEP_ONE_CLEANUP_USER_PROPERTIES_ONLY_MODE) {
+                assertEquals(0, deletedInternalPropsCount);
+                assertEquals(0, deletedInternalPropRevsCount);
+            }
             this.deletedDocGCCount = deletedDocGCCount;
             this.deletedPropsCount = deletedPropsCount;
             this.deletedInternalPropsCount = deletedInternalPropsCount;
@@ -155,7 +173,11 @@ public class VersionGarbageCollectorIT {
         }
     }
 
-    private final DocumentStoreFixture fixture;
+    @Parameter(0)
+    public DocumentStoreFixture fixture;
+
+    @Parameter(1)
+    public RDGCType gcType;
 
     private Clock clock;
 
@@ -169,17 +191,22 @@ public class VersionGarbageCollectorIT {
 
     private ExecutorService execService;
 
-    public VersionGarbageCollectorIT(DocumentStoreFixture fixture) {
-        this.fixture = fixture;
-    }
+    private RDGCType originalGcType;
 
-    @Parameterized.Parameters(name="{0}")
-    public static Collection<Object[]> fixtures() throws IOException {
-        return AbstractDocumentStoreTest.fixtures();
+    @Parameterized.Parameters(name="{index}: {0} with {1}")
+    public static java.util.Collection<Object[]> params() throws IOException {
+        java.util.Collection<Object[]> params = new LinkedList<>();
+        for (Object[] fixture : AbstractDocumentStoreTest.fixtures()) {
+            DocumentStoreFixture f = (DocumentStoreFixture)fixture[0];
+            for (RDGCType gcType : RDGCType.values()) {
+                params.add(new Object[] {f, gcType});
+            }
+        }
+        return params;
     }
 
     @Before
-    public void setUp() throws InterruptedException {
+    public void setUp() throws Exception {
         execService = Executors.newCachedThreadPool();
         clock = new Clock.Virtual();
         clock.waitUntil(System.currentTimeMillis());
@@ -195,10 +222,14 @@ public class VersionGarbageCollectorIT {
         // test using a virtual clock
         MongoTestUtils.setReadPreference(store1, ReadPreference.primary());
         gc = store1.getVersionGarbageCollector();
+
+        originalGcType = VersionGarbageCollector.getRevisionDetailedGcType();
+        writeStaticField(VersionGarbageCollector.class, "revisionDetailedGcType", gcType, true);
     }
 
     @After
     public void tearDown() throws Exception {
+        writeStaticField(VersionGarbageCollector.class, "revisionDetailedGcType", originalGcType, true);
         if (store2 != null) {
             store2.dispose();
         }
@@ -451,7 +482,11 @@ public class VersionGarbageCollectorIT {
         // 6. Now run gc after checkpoint and see removed properties gets collected
         clock.waitUntil(clock.getTime() + delta*2);
         VersionGCStats stats = gc(gc, delta, MILLISECONDS);
-        assertStatsCountsEqual(stats, 0, 1, 0, 0, 0, 0, 1);
+        assertStatsCountsEqual(stats,
+                noOldPropGc(0, 1, 0, 0, 0, 0, 1),
+                keepOneFull(0, 1, 0, 0, 0, 0, 1),
+                keepOneUser(0, 1, 0, 0, 0, 0, 1),
+                betweenChkp(0, 1, 0, 0, 0, 0, 1));
         assertTrue(stats.ignoredGCDueToCheckPoint);
         assertTrue(stats.ignoredDetailedGCDueToCheckPoint);
         assertTrue(stats.canceled);
@@ -484,7 +519,7 @@ public class VersionGarbageCollectorIT {
         //1. Go past GC age and check no GC done as nothing deleted
         clock.waitUntil(getCurrentTimestamp() + maxAge);
         VersionGCStats stats = gc(gc, maxAge, HOURS);
-        assertStatsCountsEqual(stats, 0, 0, 0, 0, 0, 0, 0);
+        assertStatsCountsZero(stats);
 
         //Remove property
         NodeBuilder b2 = store1.getRoot().builder();
@@ -497,13 +532,17 @@ public class VersionGarbageCollectorIT {
         //Clock cannot move back (it moved forward in #1) so double the maxAge
         clock.waitUntil(clock.getTime() + delta);
         stats = gc(gc, maxAge*2, HOURS);
-        assertStatsCountsEqual(stats, 0, 0, 0, 0, 0, 0, 0);
+        assertStatsCountsZero(stats);
 
         //3. Check that deleted property does get collected post maxAge
         clock.waitUntil(clock.getTime() + HOURS.toMillis(maxAge*2) + delta);
 
         stats = gc(gc, maxAge*2, HOURS);
-        assertStatsCountsEqual(stats, 0, 1, 0, 0, 0, 0, 1);
+        assertStatsCountsEqual(stats,
+                noOldPropGc(0, 1, 0, 0, 0, 0, 1),
+                keepOneFull(0, 1, 0, 0, 0, 0, 1),
+                keepOneUser(0, 1, 0, 0, 0, 0, 1),
+                betweenChkp(0, 1, 0, 0, 0, 0, 1));
         assertEquals(MIN_ID_VALUE, stats.oldestModifiedDocId);
 
         //4. Check that a revived property (deleted and created again) does not get gc
@@ -559,7 +598,11 @@ public class VersionGarbageCollectorIT {
         clock.waitUntil(clock.getTime() + HOURS.toMillis(maxAge*2) + delta);
 
         VersionGCStats stats = gc(gc, maxAge*2, HOURS);
-        assertStatsCountsEqual(stats, 0, 50_000, 0, 0, 0, 0, 5_000);
+        assertStatsCountsEqual(stats,
+                noOldPropGc(0, 50_000, 0, 0, 0, 0, 5_000),
+                keepOneFull(0, 50_000, 0, 0, 0, 0, 5_000),
+                keepOneUser(0, 50_000, 0, 0, 0, 0, 5_000),
+                betweenChkp(0, 50_000, 0, 0, 0, 0, 5_000));
         assertEquals(MIN_ID_VALUE, stats.oldestModifiedDocId);
     }
 
@@ -601,7 +644,11 @@ public class VersionGarbageCollectorIT {
         clock.waitUntil(clock.getTime() + HOURS.toMillis(maxAge*2) + delta);
 
         VersionGCStats stats = gc(gc, maxAge, HOURS);
-        assertStatsCountsEqual(stats, 0, 50_000, 0, 0, 0, 0, 5_000);
+        assertStatsCountsEqual(stats,
+                noOldPropGc(0, 50_000, 0, 0, 0, 0, 5_000),
+                keepOneFull(0, 50_000, 0, 0, 0, 0, 5_000),
+                keepOneUser(0, 50_000, 0, 0, 0, 0, 5_000),
+                betweenChkp(0, 50_000, 0, 0, 0, 0, 5_000));
         assertEquals(MIN_ID_VALUE, stats.oldestModifiedDocId);
     }
 
@@ -663,7 +710,7 @@ public class VersionGarbageCollectorIT {
         //1. Go past GC age and check no GC done as nothing deleted
         clock.waitUntil(getCurrentTimestamp() + maxAge);
         VersionGCStats stats = gc(gc, maxAge, HOURS);
-        assertStatsCountsEqual(stats, 0, 0, 0, 0, 0, 0, 0);
+        assertStatsCountsZero(stats);
 
         //Remove property
         NodeBuilder b2 = store1.getRoot().builder();
@@ -677,7 +724,11 @@ public class VersionGarbageCollectorIT {
         clock.waitUntil(clock.getTime() + HOURS.toMillis(maxAge*2) + delta);
 
         stats = gc(gc, maxAge*2, HOURS);
-        assertStatsCountsEqual(stats, 0, 10, 0, 0, 0, 0, 10);
+        assertStatsCountsEqual(stats,
+                noOldPropGc(0, 10, 0, 0, 0, 0, 10),
+                keepOneFull(0, 10, 0, 0, 0, 0, 10),
+                keepOneUser(0, 10, 0, 0, 0, 0, 10),
+                betweenChkp(0, 10, 0, 0, 0, 0, 10));
         assertEquals(MIN_ID_VALUE, stats.oldestModifiedDocId);
 
         //3. now reCreate those properties again
@@ -701,7 +752,11 @@ public class VersionGarbageCollectorIT {
         // increment the clock again by more than 2 hours + delta
         clock.waitUntil(clock.getTime() + HOURS.toMillis(maxAge*2) + delta);
         stats = gc(gc, maxAge*2, HOURS);
-        assertStatsCountsEqual(stats, 0, 10, 0, 0, 0, 0, 10);
+        assertStatsCountsEqual(stats,
+                noOldPropGc(0, 10, 0, 0, 0, 0, 10),
+                keepOneFull(0, 10, 0, 0, 0, 0, 10),
+                keepOneUser(0, 10, 0, 0, 0, 0, 10),
+                betweenChkp(0, 10, 0, 0, 0, 0, 10));
         assertEquals(MIN_ID_VALUE, stats.oldestModifiedDocId);
     }
 
@@ -771,7 +826,11 @@ public class VersionGarbageCollectorIT {
         // increment the clock again by more than 2 hours + delta
         clock.waitUntil(clock.getTime() + HOURS.toMillis(maxAge*2) + delta);
         VersionGCStats stats = gc(gc, maxAge*2, HOURS);
-        assertStatsCountsEqual(stats, 0, 10, 0, 0, 0, 0, 10);
+        assertStatsCountsEqual(stats,
+                noOldPropGc(0, 10, 0, 0, 0, 0, 10),
+                keepOneFull(0, 10, 0, 0, 0, 0, 10),
+                keepOneUser(0, 10, 0, 0, 0, 0, 10),
+                betweenChkp(0, 10, 0, 0, 0, 0, 10));
         assertEquals(MIN_ID_VALUE, stats.oldestModifiedDocId);
     }
 
@@ -793,7 +852,7 @@ public class VersionGarbageCollectorIT {
         //1. Go past GC age and check no GC done as nothing deleted
         clock.waitUntil(getCurrentTimestamp() + maxAge);
         VersionGCStats stats = gc(gc, maxAge, HOURS);
-        assertStatsCountsEqual(stats, 0, 0, 0, 0, 0, 0, 0);
+        assertStatsCountsZero(stats);
 
         //Remove property
         NodeBuilder b2 = store1.getRoot().builder();
@@ -808,13 +867,17 @@ public class VersionGarbageCollectorIT {
         //Clock cannot move back (it moved forward in #1) so double the maxAge
         clock.waitUntil(clock.getTime() + delta);
         stats = gc(gc, maxAge*2, HOURS);
-        assertStatsCountsEqual(stats, 0, 0, 0, 0, 0, 0, 0);
+        assertStatsCountsZero(stats);
 
         //3. Check that deleted property does get collected post maxAge
         clock.waitUntil(clock.getTime() + HOURS.toMillis(maxAge*2) + delta);
 
         stats = gc(gc, maxAge*2, HOURS);
-        assertStatsCountsEqual(stats, 0, 10, 0, 0, 0, 0, 1);
+        assertStatsCountsEqual(stats,
+                noOldPropGc(0, 10, 0, 0, 0, 0, 1),
+                keepOneFull(0, 10, 0, 0, 0, 0, 1),
+                keepOneUser(0, 10, 0, 0, 0, 0, 1),
+                betweenChkp(0, 10, 0, 0, 0, 0, 1));
 
         //4. Check that a revived property (deleted and created again) does not get gc
         NodeBuilder b4 = store1.getRoot().builder();
@@ -825,7 +888,7 @@ public class VersionGarbageCollectorIT {
 
         clock.waitUntil(clock.getTime() + HOURS.toMillis(maxAge*2) + delta);
         stats = gc(gc, maxAge*2, HOURS);
-        assertStatsCountsEqual(stats, 0, 0, 0, 0, 0, 0, 0);
+        assertStatsCountsZero(stats);
     }
 
     @Test
@@ -848,7 +911,7 @@ public class VersionGarbageCollectorIT {
         //1. Go past GC age and check no GC done as nothing deleted
         clock.waitUntil(getCurrentTimestamp() + maxAge);
         VersionGCStats stats = gc(gc, maxAge, HOURS);
-        assertStatsCountsEqual(stats, 0, 0, 0, 0, 0, 0, 0);
+        assertStatsCountsZero(stats);
 
         //Remove property
         NodeBuilder b2 = store1.getRoot().builder();
@@ -863,13 +926,17 @@ public class VersionGarbageCollectorIT {
         //Clock cannot move back (it moved forward in #1) so double the maxAge
         clock.waitUntil(clock.getTime() + delta);
         stats = gc(gc, maxAge*2, HOURS);
-        assertStatsCountsEqual(stats, 0, 0, 0, 0, 0, 0, 0);
+        assertStatsCountsZero(stats);
 
         //3. Check that deleted property does get collected post maxAge
         clock.waitUntil(clock.getTime() + HOURS.toMillis(maxAge*2) + delta);
 
         stats = gc(gc, maxAge*2, HOURS);
-        assertStatsCountsEqual(stats, 0, 10, 0, 0, 0, 0, 1);
+        assertStatsCountsEqual(stats,
+                noOldPropGc(0, 10, 0, 0, 0, 0, 1),
+                keepOneFull(0, 10, 0, 0, 0, 0, 1),
+                keepOneUser(0, 10, 0, 0, 0, 0, 1),
+                betweenChkp(0, 10, 0, 0, 0, 0, 1));
 
         //4. Check that a revived property (deleted and created again) does not get gc
         NodeBuilder b4 = store1.getRoot().builder();
@@ -880,7 +947,7 @@ public class VersionGarbageCollectorIT {
 
         clock.waitUntil(clock.getTime() + HOURS.toMillis(maxAge*2) + delta);
         stats = gc(gc, maxAge*2, HOURS);
-        assertStatsCountsEqual(stats, 0, 0, 0, 0, 0, 0, 0);
+        assertStatsCountsZero(stats);
     }
 
     @Test
@@ -912,7 +979,7 @@ public class VersionGarbageCollectorIT {
         //1. Go past GC age and check no GC done as nothing deleted
         clock.waitUntil(getCurrentTimestamp() + maxAge);
         VersionGCStats stats = gc(gc, maxAge, HOURS);
-        assertStatsCountsEqual(stats, 0, 0, 0, 0, 0, 0, 0);
+        assertStatsCountsZero(stats);
 
         //Remove property
         NodeBuilder b2 = store1.getRoot().builder();
@@ -927,13 +994,17 @@ public class VersionGarbageCollectorIT {
         //Clock cannot move back (it moved forward in #1) so double the maxAge
         clock.waitUntil(clock.getTime() + delta);
         stats = gc(gc, maxAge*2, HOURS);
-        assertStatsCountsEqual(stats, 0, 0, 0, 0, 0, 0, 0);
+        assertStatsCountsZero(stats);
 
         //3. Check that deleted property does get collected post maxAge
         clock.waitUntil(clock.getTime() + HOURS.toMillis(maxAge*2) + delta);
 
         stats = gc(gc, maxAge*2, HOURS);
-        assertStatsCountsEqual(stats, 0, 10, 0, 0, 0, 0, 1);
+        assertStatsCountsEqual(stats,
+                noOldPropGc(0, 10, 0, 0, 0, 0, 1),
+                keepOneFull(0, 10, 0, 0, 0, 0, 1),
+                keepOneUser(0, 10, 0, 0, 0, 0, 1),
+                betweenChkp(0, 10, 0, 0, 0, 0, 1));
     }
 
     @Test
@@ -975,7 +1046,7 @@ public class VersionGarbageCollectorIT {
         //1. Go past GC age and check no GC done as nothing deleted
         clock.waitUntil(getCurrentTimestamp() + maxAge);
         VersionGCStats stats = gc(gc, maxAge, HOURS);
-        assertStatsCountsEqual(stats, 0, 0, 0, 0, 0, 0, 0);
+        assertStatsCountsZero(stats);
 
         x = store1.getRoot().getChildNode("x");
         assertTrue(x.exists());
@@ -999,7 +1070,7 @@ public class VersionGarbageCollectorIT {
         //Clock cannot move back (it moved forward in #1) so double the maxAge
         clock.waitUntil(clock.getTime() + delta);
         stats = gc(gc, maxAge*2, HOURS);
-        assertStatsCountsEqual(stats, 0, 0, 0, 0, 0, 0, 0);
+        assertStatsCountsZero(stats);
 
         x = store1.getRoot().getChildNode("x");
         assertTrue(x.exists());
@@ -1014,7 +1085,11 @@ public class VersionGarbageCollectorIT {
         clock.waitUntil(clock.getTime() + HOURS.toMillis(maxAge*2) + delta);
 
         stats = gc(gc, maxAge*2, HOURS);
-        assertStatsCountsEqual(stats, 0, 10, 0, 0, 0, 0, 1);
+        assertStatsCountsEqual(stats,
+                noOldPropGc(0, 10, 0, 0, 0, 0, 1),
+                keepOneFull(0, 10, 0, 0, 0, 0, 1),
+                keepOneUser(0, 10, 0, 0, 0, 0, 1),
+                betweenChkp(0, 10, 0, 0, 0, 0, 1));
 
         x = store1.getRoot().getChildNode("x");
         assertTrue(x.exists());
@@ -1026,10 +1101,16 @@ public class VersionGarbageCollectorIT {
         assertFalse(jcrContent.hasProperty("prop0"));
     }
 
-    private void assertStatsCountsEqual(VersionGCStats stats, GCCounts... counts) {
+    static void assertStatsCountsZero(VersionGCStats stats) {
+        GCCounts c = new GCCounts(VersionGarbageCollector.getRevisionDetailedGcType(),
+                0, 0, 0, 0, 0, 0, 0);
+        assertStatsCountsEqual(stats, c);
+    }
+
+    static void assertStatsCountsEqual(VersionGCStats stats, GCCounts... counts) {
         GCCounts c = null;
         for (GCCounts a : counts) {
-            if (a.mode == VersionGarbageCollector.revisionDetailedGcType) {
+            if (a.mode == VersionGarbageCollector.getRevisionDetailedGcType()) {
                 c = a;
                 break;
             }
@@ -1038,42 +1119,13 @@ public class VersionGarbageCollectorIT {
         assertNotNull(c);
         assertEquals(c.deletedDocGCCount, stats.deletedDocGCCount);
         assertEquals(c.deletedPropsCount, stats.deletedPropsCount);
-        if (c.deletedInternalPropsCount >= 0) {
-            assertEquals(c.deletedInternalPropsCount, stats.deletedInternalPropsCount);
-        }
+        assertEquals(c.deletedInternalPropsCount, stats.deletedInternalPropsCount);
         assertEquals(c.deletedPropRevsCount, stats.deletedPropRevsCount);
         assertEquals(c.deletedInternalPropRevsCount, stats.deletedInternalPropRevsCount);
         assertEquals(c.deletedUnmergedBCCount, stats.deletedUnmergedBCCount);
         assertEquals(c.updatedDetailedGCDocsCount, stats.updatedDetailedGCDocsCount);
     }
 
-    private void assertStatsCountsEqual(VersionGCStats stats,
-            int deletedDocGCCount,
-            int deletedPropsCount,
-            int deletedInternalPropsCount,
-            int deletedPropRevsCount,
-            int deletedInternalPropRevsCount,
-            int deletedUnmergedBCCount,
-            int updatedDetailedGCDocsCount) {
-        assertNotNull(stats);
-        assertEquals(deletedDocGCCount, stats.deletedDocGCCount);
-        assertEquals(deletedPropsCount, stats.deletedPropsCount);
-        if (VersionGarbageCollector.revisionDetailedGcType == RDGCType.KEEP_ONE_FULL_MODE) {
-            assertEquals(deletedInternalPropsCount, stats.deletedInternalPropsCount);
-        }
-        assertEquals(deletedPropRevsCount, stats.deletedPropRevsCount);
-        if (VersionGarbageCollector.revisionDetailedGcType == RDGCType.KEEP_ONE_FULL_MODE) {
-            assertEquals(deletedInternalPropRevsCount, stats.deletedInternalPropRevsCount);
-        }
-        assertEquals(deletedUnmergedBCCount, stats.deletedUnmergedBCCount);
-        if (VersionGarbageCollector.revisionDetailedGcType != RDGCType.KEEP_ONE_CLEANUP_USER_PROPERTIES_ONLY_MODE) {
-            // TODO: unfortunately, in cleanup-user-props-only mode the expected count below
-            // is inaccurate. So either we extend this assert methods to get values per mode,
-            // or we ignore this for now. not nice but should only be temporary
-            assertEquals(updatedDetailedGCDocsCount, stats.updatedDetailedGCDocsCount);
-        }
-    }
-
     @Test
     public void testGCDeletedPropsWhenModifiedConcurrently() throws Exception {
         //1. Create nodes with properties
@@ -1161,7 +1213,7 @@ public class VersionGarbageCollectorIT {
         //1. Go past GC age and check no GC done as nothing deleted
         clock.waitUntil(getCurrentTimestamp() + maxAge);
         VersionGCStats stats = gc(gc, maxAge, HOURS);
-        assertStatsCountsEqual(stats, 0, 0, 0, 0, 0, 0, 0);
+        assertStatsCountsZero(stats);
 
         //Remove property
         NodeBuilder b2 = store1.getRoot().builder();
@@ -1295,7 +1347,7 @@ public class VersionGarbageCollectorIT {
         NodeState node1 = store2.getRoot().getChildNode("node1");
         assertEquals("1", node1.getProperty("a").getValue(Type.STRING));
         assertFalse(node1.hasProperty("b"));
-        assertStatsCountsEqual(stats, 0, 0, 0, 0, 0, 0, 0);
+        assertStatsCountsZero(stats);
     }
 
     @Test
@@ -1401,7 +1453,7 @@ public class VersionGarbageCollectorIT {
         assertStatsCountsEqual(stats,
                 noOldPropGc(0, 3, 0, 0, 0, 0, 2),
                 keepOneFull(0, 3, 2, 1, 9, 0, 3),
-                keepOneUser(0, 3,-1, 1, 0, 0, 2),
+                keepOneUser(0, 3, 0, 1, 0, 0, 2),
                 betweenChkp(0, 3, 1, 1, 8, 2, 3));
         assertBranchRevisionRemovedFromAllDocuments(store1, br1);
         assertBranchRevisionRemovedFromAllDocuments(store1, br4);
@@ -1442,7 +1494,7 @@ public class VersionGarbageCollectorIT {
         assertStatsCountsEqual(stats,
                 noOldPropGc(0, 3, 0, 0,  0, 0, 2),
                 keepOneFull(0, 3, 3, 1, 17, 0, 3),
-                keepOneUser(0, 3,-1, 1,  0, 0, 2),
+                keepOneUser(0, 3, 0, 1,  0, 0, 2),
                 betweenChkp(0, 3, 2, 1, 18, 4, 3));
         assertBranchRevisionRemovedFromAllDocuments(store1, br1);
         assertBranchRevisionRemovedFromAllDocuments(store1, br2);
@@ -1631,7 +1683,7 @@ public class VersionGarbageCollectorIT {
                 betweenChkp(0, 2, 1, 2, 13, 3, 2));
     }
 
-    private GCCounts noOldPropGc(int deletedDocGCCount, int deletedPropsCount,
+    static GCCounts noOldPropGc(int deletedDocGCCount, int deletedPropsCount,
             int deletedInternalPropsCount, int deletedPropRevsCount,
             int deletedInternalPropRevsCount, int deletedUnmergedBCCount,
             int updatedDetailedGCDocsCount) {
@@ -1645,7 +1697,7 @@ public class VersionGarbageCollectorIT {
                 updatedDetailedGCDocsCount);
     }
 
-    private GCCounts keepOneFull(int deletedDocGCCount, int deletedPropsCount,
+    static GCCounts keepOneFull(int deletedDocGCCount, int deletedPropsCount,
             int deletedInternalPropsCount, int deletedPropRevsCount,
             int deletedInternalPropRevsCount, int deletedUnmergedBCCount,
             int updatedDetailedGCDocsCount) {
@@ -1655,7 +1707,7 @@ public class VersionGarbageCollectorIT {
                 updatedDetailedGCDocsCount);
     }
 
-    private GCCounts keepOneUser(int deletedDocGCCount, int deletedPropsCount,
+    static GCCounts keepOneUser(int deletedDocGCCount, int deletedPropsCount,
             int deletedInternalPropsCount, int deletedPropRevsCount,
             int deletedInternalPropRevsCount, int deletedUnmergedBCCount,
             int updatedDetailedGCDocsCount) {
@@ -1665,7 +1717,7 @@ public class VersionGarbageCollectorIT {
                 deletedUnmergedBCCount, updatedDetailedGCDocsCount);
     }
 
-    private GCCounts betweenChkp(int deletedDocGCCount, int deletedPropsCount,
+    static GCCounts betweenChkp(int deletedDocGCCount, int deletedPropsCount,
             int deletedInternalPropsCount, int deletedPropRevsCount,
             int deletedInternalPropRevsCount, int deletedUnmergedBCCount,
             int updatedDetailedGCDocsCount) {
@@ -1737,8 +1789,8 @@ public class VersionGarbageCollectorIT {
 
         NodeDocument doc = store1.getDocumentStore().find(NODES, "1:/x", -1);
         assertNotNull(doc);
-        if (VersionGarbageCollector.revisionDetailedGcType == RDGCType.OLDER_THAN_24H_AND_BETWEEN_CHECKPOINTS_MODE
-                || VersionGarbageCollector.revisionDetailedGcType == RDGCType.NO_OLD_PROP_REV_GC) {
+        if (VersionGarbageCollector.getRevisionDetailedGcType() == RDGCType.OLDER_THAN_24H_AND_BETWEEN_CHECKPOINTS_MODE
+                || VersionGarbageCollector.getRevisionDetailedGcType() == RDGCType.NO_OLD_PROP_REV_GC) {
             // this mode doesn't currently delete all revisions,
             // thus would fail below assert.
             return;
@@ -1778,7 +1830,11 @@ public class VersionGarbageCollectorIT {
         clock.waitUntil(clock.getTime() + HOURS.toMillis(maxAge*2) + delta);
 
         VersionGCStats stats = gc(gc, maxAge*2, HOURS);
-        assertStatsCountsEqual(stats, 0, 1, 0, 0, 0, 0, 1);
+        assertStatsCountsEqual(stats,
+                noOldPropGc(0, 1, 0, 0, 0, 0, 1),
+                keepOneFull(0, 1, 0, 0, 0, 0, 1),
+                keepOneUser(0, 1, 0, 0, 0, 0, 1),
+                betweenChkp(0, 1, 0, 0, 0, 0, 1));
         assertEquals(MIN_ID_VALUE, stats.oldestModifiedDocId);
 
         // 4. Save values of detailedGC settings collection fields
@@ -1804,7 +1860,7 @@ public class VersionGarbageCollectorIT {
         final String oldestModifiedDryRunDocId = stats.oldestModifiedDocId;
         final long oldestModifiedDocDryRunTimeStamp = stats.oldestModifiedDocTimeStamp;
 
-        assertStatsCountsEqual(stats, 0, 0, 0, 0, 0, 0, 0);
+        assertStatsCountsZero(stats);
         assertEquals(MIN_ID_VALUE, stats.oldestModifiedDocId);
         assertTrue(stats.detailedGCDryRunMode);
 
@@ -1849,7 +1905,7 @@ public class VersionGarbageCollectorIT {
         clock.waitUntil(clock.getTime() + HOURS.toMillis(2));
         // clean everything older than one hour
         VersionGCStats stats = gc(gc, 1, HOURS);
-        assertStatsCountsEqual(stats, 0, 0, 0, 0, 0, 0, 0);
+        assertStatsCountsZero(stats);
         assertTrue(stats.detailedGCDryRunMode);
 
         assertBranchRevisionNotRemovedFromAllDocuments(store1, br1);
@@ -1891,7 +1947,11 @@ public class VersionGarbageCollectorIT {
         VersionGCStats stats = gc(store1.getVersionGarbageCollector(), 1, HOURS);
         assertFalse(store1.getRoot().getChildNode("bar").hasProperty("prop"));
         assertNotNull(stats);
-        assertStatsCountsEqual(stats, 0, 1, 0, 0, 0, 0, 1);
+        assertStatsCountsEqual(stats,
+                noOldPropGc(0, 1, 0, 0, 0, 0, 1),
+                keepOneFull(0, 1, 0, 0, 0, 0, 1),
+                keepOneUser(0, 1, 0, 0, 0, 0, 1),
+                betweenChkp(0, 1, 0, 0, 0, 0, 1));
         assertDocumentsExist(of("/bar"));
     }
 
@@ -1928,7 +1988,11 @@ public class VersionGarbageCollectorIT {
         // since we have updated a totally unrelated path i.e. "/a",
         // we should still be seeing the garbage from late write and
         // thus it will be collected.
-        assertStatsCountsEqual(stats, 0, 1, 0, 0, 0, 0, 1);
+        assertStatsCountsEqual(stats,
+                noOldPropGc(0, 1, 0, 0, 0, 0, 1),
+                keepOneFull(0, 1, 0, 0, 0, 0, 1),
+                keepOneUser(0, 1, 0, 0, 0, 0, 1),
+                betweenChkp(0, 1, 0, 0, 0, 0, 1));
 
         assertDocumentsExist(of("/foo/bar/baz"));
     }
@@ -2066,7 +2130,11 @@ public class VersionGarbageCollectorIT {
         assertNotNull(stats);
         // we should be able to remove the property since we have updated an related path that has lead to an update
         // of common ancestor and this would make late write visible
-        assertStatsCountsEqual(stats, 0, 1, 0, 0, 0, 0, 1);
+        assertStatsCountsEqual(stats,
+                noOldPropGc(0, 1, 0, 0, 0, 0, 1),
+                keepOneFull(0, 1, 0, 0, 0, 0, 1),
+                keepOneUser(0, 1, 0, 0, 0, 0, 1),
+                betweenChkp(0, 1, 0, 0, 0, 0, 1));
 
         assertDocumentsExist(of("/bar"));
     }