0
0
mirror of https://github.com/ankidroid/Anki-Android.git synced 2024-09-19 19:42:17 +02:00

Add RetryableException

Allows an operation to be retried
This commit is contained in:
David Allison 2022-04-12 23:31:29 +01:00 committed by Mike Hardy
parent 22a59a72d0
commit 846cd470a5
3 changed files with 94 additions and 0 deletions

View File

@ -82,6 +82,7 @@
<w>replayq</w>
<w>rerender</w>
<w>resync</w>
<w>retryable</w>
<w>servicelayer</w>
<w>sinh</w>
<w>spacebar</w>

View File

@ -0,0 +1,44 @@
/*
* Copyright (c) 2022 David Allison <davidallisongithub@gmail.com>
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 3 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.ichi2.anki.exception
import timber.log.Timber
/**
* An exception wrapper signifying that the operation throwing the wrapped exception may be retried
* @param inner wrapped exception
*/
class RetryableException(private val inner: Throwable) : java.lang.RuntimeException(inner) {
companion object {
/**
* Retries the provided action if a [RetryableException] is thrown
*/
fun retryOnce(action: (() -> Unit)) {
try {
action.invoke()
} catch (e: RetryableException) {
Timber.w(e, "Found retryable exception, retrying")
try {
action.invoke()
} catch (e: RetryableException) {
Timber.w(e, "action was retried once, throwing")
throw e.inner
}
}
}
}
}

View File

@ -0,0 +1,49 @@
/*
* Copyright (c) 2022 David Allison <davidallisongithub@gmail.com>
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 3 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.ichi2.anki.exception
import com.ichi2.testutils.TestException
import com.ichi2.testutils.assertThrows
import org.hamcrest.CoreMatchers.equalTo
import org.hamcrest.MatcherAssert.assertThat
import org.junit.Test
/** Tests [RetryableException] */
class RetryableExceptionTest {
var called = 0
@Test
fun non_throwing_function_works() {
RetryableException.retryOnce { called++ }
assertThat("function should only be called once", called, equalTo(1))
}
@Test
fun conditionally_throwing_function_retries() {
RetryableException.retryOnce { called++; if (called == 1) { throw RetryableException(TestException("throwing_function_retries")) } }
assertThat("function should be called twice", called, equalTo(2))
}
@Test
fun throwing_function_fails_with_inner() {
val exception = assertThrows<TestException> {
RetryableException.retryOnce { called++; throw RetryableException(TestException("throwing_function_retries")) }
}
assertThat("exception message is retained", exception.message, equalTo("throwing_function_retries"))
assertThat("function should be called twice", called, equalTo(2))
}
}