2323import org .apache .atlas .exception .AtlasBaseException ;
2424import org .apache .atlas .model .instance .EntityMutationResponse ;
2525import org .apache .atlas .repository .store .graph .AtlasEntityStore ;
26+ import org .janusgraph .diskstorage .PermanentBackendException ;
2627import org .janusgraph .diskstorage .locking .PermanentLockingException ;
2728import org .mockito .MockedStatic ;
28- import org .testng .annotations .DataProvider ;
2929import org .testng .annotations .Test ;
3030
3131import java .util .Collections ;
4545public class PurgeBatchExecutorTest {
4646 private static final Set <String > BATCH = Collections .singleton ("guid1" );
4747
48- @ DataProvider (name = "retryableLockConflictExceptionClassNames" )
49- public Object [][] retryableLockConflictExceptionClassNames () {
50- return new Object [][] {
51- {"org.janusgraph.diskstorage.locking.PermanentLockingException" },
52- {"com.sleepycat.je.LockTimeoutException" },
53- {"com.sleepycat.je.DeadlockException" },
54- {"org.janusgraph.diskstorage.PermanentBackendException" }
55- };
56- }
57-
5848 @ Test
5949 public void testExecuteBatchSuccess () throws Exception {
6050 AtlasEntityStore mockStore = mock (AtlasEntityStore .class );
@@ -79,30 +69,33 @@ public void testIsRetryableLockConflictReturnsFalseForNonRetryableException() {
7969 }
8070
8171 @ Test
82- public void testIsRetryableLockConflictMatchesWrappedCause () {
72+ public void testIsRetryableLockConflictReturnsFalseForPermanentBackendException () {
73+ PermanentBackendException backendException = new PermanentBackendException ("backend failure" );
74+
75+ assertFalse (PurgeBatchExecutor .isRetryableLockConflict (backendException ));
76+ }
77+
78+ @ Test
79+ public void testIsRetryableLockConflictMatchesPermanentLockingException () {
8380 PermanentLockingException ple = new PermanentLockingException ("lock conflict" );
84- RuntimeException wrapped = new RuntimeException (new AtlasBaseException (AtlasErrorCode .INTERNAL_ERROR , ple ));
8581
86- assertTrue (PurgeBatchExecutor .isRetryableLockConflict (wrapped ));
82+ assertTrue (PurgeBatchExecutor .isRetryableLockConflict (ple ));
8783 }
8884
89- @ Test (dataProvider = "retryableLockConflictExceptionClassNames" )
90- public void testIsRetryableLockConflictMatchesKnownTypes (String className ) throws Exception {
91- Exception conflict = newExceptionByClassName (className , "lock conflict" );
85+ @ Test
86+ public void testIsRetryableLockConflictMatchesWrappedCause () {
87+ PermanentLockingException ple = new PermanentLockingException ("lock conflict" );
88+ RuntimeException wrapped = new RuntimeException (new AtlasBaseException (AtlasErrorCode .INTERNAL_ERROR , ple ));
9289
93- assertTrue (PurgeBatchExecutor .RETRYABLE_LOCK_CONFLICT_EXCEPTION_CLASS_NAMES .contains (className ));
94- assertTrue (PurgeBatchExecutor .isRetryableLockConflict (conflict ));
95- // Use message+cause form: RuntimeException(Throwable) calls cause.toString(), which NPEs on
96- // partially-initialized Berkeley JE DatabaseException instances created for this test.
97- assertTrue (PurgeBatchExecutor .isRetryableLockConflict (wrapWithCause (conflict )));
90+ assertTrue (PurgeBatchExecutor .isRetryableLockConflict (wrapped ));
9891 }
9992
10093 @ Test
10194 public void testExecuteBatchClearsCachesBeforeRetry () throws Exception {
10295 AtlasEntityStore mockStore = mock (AtlasEntityStore .class );
10396 EntityMutationResponse mockResponse = new EntityMutationResponse ();
104- PermanentLockingException ple = new PermanentLockingException ("lock conflict" );
105- AtlasBaseException wrappedException = new AtlasBaseException (AtlasErrorCode .INTERNAL_ERROR , ple );
97+ PermanentLockingException ple = new PermanentLockingException ("lock conflict" );
98+ AtlasBaseException wrappedException = new AtlasBaseException (AtlasErrorCode .INTERNAL_ERROR , ple );
10699
107100 when (mockStore .purgeEntitiesInBatch (BATCH ))
108101 .thenThrow (wrappedException )
@@ -149,24 +142,6 @@ public void testExecuteBatchRetryOnPermanentLockingException() throws Exception
149142 assertTrue (duration >= 1000 , "Expected backoff delays but finished in " + duration + " ms" );
150143 }
151144
152- @ Test (dataProvider = "retryableLockConflictExceptionClassNames" )
153- public void testExecuteBatchRetriesOnKnownLockConflictTypes (String className ) throws Exception {
154- AtlasEntityStore mockStore = mock (AtlasEntityStore .class );
155- EntityMutationResponse mockResponse = new EntityMutationResponse ();
156- Exception conflict = newExceptionByClassName (className , "lock conflict" );
157- AtlasBaseException wrappedException = new AtlasBaseException (AtlasErrorCode .INTERNAL_ERROR , conflict );
158-
159- when (mockStore .purgeEntitiesInBatch (BATCH ))
160- .thenThrow (wrappedException )
161- .thenReturn (mockResponse );
162-
163- PurgeBatchExecutor executor = new PurgeBatchExecutor (mockStore );
164- EntityMutationResponse response = executor .executeBatch (BATCH );
165-
166- assertEquals (response , mockResponse );
167- verify (mockStore , times (2 )).purgeEntitiesInBatch (BATCH );
168- }
169-
170145 @ Test
171146 public void testExecuteBatchFailsAfterMaxLockingConflicts () throws Exception {
172147 AtlasEntityStore mockStore = mock (AtlasEntityStore .class );
@@ -199,27 +174,19 @@ public void testExecuteBatchNoRetryOnNonLockingException() throws Exception {
199174 verify (mockStore , times (1 )).purgeEntitiesInBatch (BATCH );
200175 }
201176
202- private static RuntimeException wrapWithCause (Throwable cause ) {
203- return new RuntimeException ("wrapped" , cause );
204- }
177+ @ Test
178+ public void testExecuteBatchNoRetryOnPermanentBackendException () throws Exception {
179+ AtlasEntityStore mockStore = mock (AtlasEntityStore .class );
180+ PermanentBackendException backendException = new PermanentBackendException ("backend failure" );
181+ AtlasBaseException wrappedException = new AtlasBaseException (AtlasErrorCode .INTERNAL_ERROR , backendException );
205182
206- private static Exception newExceptionByClassName (String className , String message ) throws Exception {
207- try {
208- Class <?> clazz = Class .forName (className );
209- try {
210- return (Exception ) clazz .getConstructor (String .class ).newInstance (message );
211- } catch (NoSuchMethodException e ) {
212- try {
213- return (Exception ) clazz .getConstructor ().newInstance ();
214- } catch (NoSuchMethodException e2 ) {
215- java .lang .reflect .Field f = sun .misc .Unsafe .class .getDeclaredField ("theUnsafe" );
216- f .setAccessible (true );
217- sun .misc .Unsafe unsafe = (sun .misc .Unsafe ) f .get (null );
218- return (Exception ) unsafe .allocateInstance (clazz );
219- }
220- }
221- } catch (ClassNotFoundException e ) {
222- throw new org .testng .SkipException ("Required exception class not on classpath: " + className );
223- }
183+ when (mockStore .purgeEntitiesInBatch (BATCH )).thenThrow (wrappedException );
184+
185+ PurgeBatchExecutor executor = new PurgeBatchExecutor (mockStore );
186+
187+ AtlasBaseException ex = expectThrows (AtlasBaseException .class , () -> executor .executeBatch (BATCH ));
188+
189+ assertEquals (ex .getAtlasErrorCode (), AtlasErrorCode .INTERNAL_ERROR );
190+ verify (mockStore , times (1 )).purgeEntitiesInBatch (BATCH );
224191 }
225192}
0 commit comments