diff --git a/AndroidLib/src/main/kotlin/com/bloomberg/selekt/android/SQLiteDatabase.kt b/AndroidLib/src/main/kotlin/com/bloomberg/selekt/android/SQLiteDatabase.kt index 76e5f0ba06..5b8749a37c 100644 --- a/AndroidLib/src/main/kotlin/com/bloomberg/selekt/android/SQLiteDatabase.kt +++ b/AndroidLib/src/main/kotlin/com/bloomberg/selekt/android/SQLiteDatabase.kt @@ -17,7 +17,6 @@ package com.bloomberg.selekt.android import android.content.ContentValues -import android.util.Log import androidx.annotation.IntRange import androidx.annotation.Size import com.bloomberg.selekt.CommonThreadLocalRandom @@ -37,32 +36,8 @@ import java.io.File import java.io.InputStream import java.io.OutputStream import java.util.Locale -import javax.annotation.concurrent.GuardedBy import javax.annotation.concurrent.ThreadSafe -internal object SQLiteDatabaseRegistry { - private val lock = Any() - @GuardedBy("lock") - private val store = mutableSetOf() - - fun register(database: SQLiteDatabase) = synchronized(lock) { - check(store.add(database)) { "Failed to register a database, ${store.count()} registered." } - } - - fun unregister(database: SQLiteDatabase) = synchronized(lock) { - check(store.remove(database)) { "Failed to unregister a database, ${store.count()} registered." } - } - - fun releaseMemory(priority: Priority) { - synchronized(lock) { store.toList() }.run { - forEach { - it.releaseMemory(priority) - } - Log.d(Selekt.TAG, "Released resources from ${count()} databases.") - } - } -} - /** * @since v0.1.0. */ diff --git a/AndroidLib/src/main/kotlin/com/bloomberg/selekt/android/SQLiteDatabaseRegistry.kt b/AndroidLib/src/main/kotlin/com/bloomberg/selekt/android/SQLiteDatabaseRegistry.kt new file mode 100644 index 0000000000..cac98c502e --- /dev/null +++ b/AndroidLib/src/main/kotlin/com/bloomberg/selekt/android/SQLiteDatabaseRegistry.kt @@ -0,0 +1,44 @@ +/* + * Copyright 2021 Bloomberg Finance L.P. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.bloomberg.selekt.android + +import android.util.Log +import com.bloomberg.selekt.pools.Priority +import javax.annotation.concurrent.GuardedBy + +internal object SQLiteDatabaseRegistry { + private val lock = Any() + @GuardedBy("lock") + private val store = mutableSetOf() + + fun register(database: SQLiteDatabase) = synchronized(lock) { + check(store.add(database)) { "Failed to register a database, ${store.count()} registered." } + } + + fun unregister(database: SQLiteDatabase) = synchronized(lock) { + check(store.remove(database)) { "Failed to unregister a database, ${store.count()} registered." } + } + + fun releaseMemory(priority: Priority) { + synchronized(lock) { store.toList() }.run { + forEach { + it.releaseMemory(priority) + } + Log.d(Selekt.TAG, "Released resources from ${count()} databases.") + } + } +} diff --git a/AndroidLib/src/test/kotlin/com/bloomberg/selekt/android/CursorWrapperTest.kt b/AndroidLib/src/test/kotlin/com/bloomberg/selekt/android/CursorWrapperTest.kt index 25ca7bd6bd..5ac3216304 100644 --- a/AndroidLib/src/test/kotlin/com/bloomberg/selekt/android/CursorWrapperTest.kt +++ b/AndroidLib/src/test/kotlin/com/bloomberg/selekt/android/CursorWrapperTest.kt @@ -19,11 +19,11 @@ package com.bloomberg.selekt.android import android.database.Cursor import com.bloomberg.selekt.ColumnType import com.bloomberg.selekt.ICursor -import com.nhaarman.mockitokotlin2.doReturn -import com.nhaarman.mockitokotlin2.eq -import com.nhaarman.mockitokotlin2.times -import com.nhaarman.mockitokotlin2.verify -import com.nhaarman.mockitokotlin2.whenever +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.eq +import org.mockito.kotlin.times +import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever import org.junit.Assert import org.junit.Assert.assertArrayEquals import org.junit.Before @@ -50,7 +50,7 @@ internal class CursorWrapperTest { @Before fun setUp() { - MockitoAnnotations.initMocks(this) + MockitoAnnotations.openMocks(this) doReturn(emptyArray()).whenever(cursor).columnNames() wrapper = cursor.asAndroidCursor() } diff --git a/AndroidLib/src/test/kotlin/com/bloomberg/selekt/android/MemoryComponentCallbackTest.kt b/AndroidLib/src/test/kotlin/com/bloomberg/selekt/android/MemoryComponentCallbackTest.kt index fcd7a4835d..f35f0f7eed 100644 --- a/AndroidLib/src/test/kotlin/com/bloomberg/selekt/android/MemoryComponentCallbackTest.kt +++ b/AndroidLib/src/test/kotlin/com/bloomberg/selekt/android/MemoryComponentCallbackTest.kt @@ -24,12 +24,12 @@ import android.content.ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW import android.content.ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE import android.content.ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN import com.bloomberg.selekt.pools.Priority -import com.nhaarman.mockitokotlin2.any -import com.nhaarman.mockitokotlin2.mock -import com.nhaarman.mockitokotlin2.never -import com.nhaarman.mockitokotlin2.same -import com.nhaarman.mockitokotlin2.times -import com.nhaarman.mockitokotlin2.verify +import org.mockito.kotlin.any +import org.mockito.kotlin.mock +import org.mockito.kotlin.never +import org.mockito.kotlin.same +import org.mockito.kotlin.times +import org.mockito.kotlin.verify import org.junit.Test import org.junit.runner.RunWith import org.robolectric.RobolectricTestRunner diff --git a/AndroidLib/src/test/kotlin/com/bloomberg/selekt/android/SQLDatabaseTest.kt b/AndroidLib/src/test/kotlin/com/bloomberg/selekt/android/SQLDatabaseTest.kt index 773b65fcbb..e8fcb49862 100644 --- a/AndroidLib/src/test/kotlin/com/bloomberg/selekt/android/SQLDatabaseTest.kt +++ b/AndroidLib/src/test/kotlin/com/bloomberg/selekt/android/SQLDatabaseTest.kt @@ -24,7 +24,7 @@ import com.bloomberg.selekt.ContentValues import com.bloomberg.selekt.SQLDatabase import com.bloomberg.selekt.SQLiteJournalMode import com.bloomberg.selekt.SimpleSQLQuery -import com.nhaarman.mockitokotlin2.mock +import org.mockito.kotlin.mock import org.assertj.core.api.Assertions.assertThatExceptionOfType import org.junit.After import org.junit.Assert diff --git a/AndroidLib/src/test/kotlin/com/bloomberg/selekt/android/SQLDatabaseTransactionTest.kt b/AndroidLib/src/test/kotlin/com/bloomberg/selekt/android/SQLDatabaseTransactionTest.kt index 55144df550..e2ad179c6a 100644 --- a/AndroidLib/src/test/kotlin/com/bloomberg/selekt/android/SQLDatabaseTransactionTest.kt +++ b/AndroidLib/src/test/kotlin/com/bloomberg/selekt/android/SQLDatabaseTransactionTest.kt @@ -22,10 +22,10 @@ import com.bloomberg.selekt.ContentValues import com.bloomberg.selekt.SQLDatabase import com.bloomberg.selekt.SQLTransactionListener import com.bloomberg.selekt.SQLiteJournalMode -import com.nhaarman.mockitokotlin2.mock -import com.nhaarman.mockitokotlin2.never -import com.nhaarman.mockitokotlin2.times -import com.nhaarman.mockitokotlin2.verify +import org.mockito.kotlin.mock +import org.mockito.kotlin.never +import org.mockito.kotlin.times +import org.mockito.kotlin.verify import org.assertj.core.api.Assertions.assertThatExceptionOfType import org.junit.After import org.junit.Before diff --git a/AndroidLib/src/test/kotlin/com/bloomberg/selekt/android/SQLiteDatabaseRegistryTest.kt b/AndroidLib/src/test/kotlin/com/bloomberg/selekt/android/SQLiteDatabaseRegistryTest.kt new file mode 100644 index 0000000000..dfddfafc77 --- /dev/null +++ b/AndroidLib/src/test/kotlin/com/bloomberg/selekt/android/SQLiteDatabaseRegistryTest.kt @@ -0,0 +1,44 @@ +/* + * Copyright 2021 Bloomberg Finance L.P. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.bloomberg.selekt.android + +import org.assertj.core.api.Assertions.assertThatExceptionOfType +import org.junit.Test +import org.mockito.kotlin.mock + +internal class SQLiteDatabaseRegistryTest { + @Test + fun registeringTwiceThrows() { + mock().let { + SQLiteDatabaseRegistry.register(it) + try { + assertThatExceptionOfType(IllegalStateException::class.java).isThrownBy { + SQLiteDatabaseRegistry.register(it) + } + } finally { + SQLiteDatabaseRegistry.unregister(it) + } + } + } + + @Test + fun unregisterThrows() { + assertThatExceptionOfType(IllegalStateException::class.java).isThrownBy { + SQLiteDatabaseRegistry.unregister(mock()) + } + } +} diff --git a/AndroidLib/src/test/kotlin/com/bloomberg/selekt/android/SQLiteDatabaseTransactionTest.kt b/AndroidLib/src/test/kotlin/com/bloomberg/selekt/android/SQLiteDatabaseTransactionTest.kt index 33bfbdc017..f6a0fe598c 100644 --- a/AndroidLib/src/test/kotlin/com/bloomberg/selekt/android/SQLiteDatabaseTransactionTest.kt +++ b/AndroidLib/src/test/kotlin/com/bloomberg/selekt/android/SQLiteDatabaseTransactionTest.kt @@ -22,14 +22,14 @@ import com.bloomberg.selekt.SQLTransactionListener import com.bloomberg.selekt.commons.deleteDatabase import com.bloomberg.selekt.SQLiteJournalMode import com.bloomberg.selekt.SQLiteTransactionMode -import com.nhaarman.mockitokotlin2.any -import com.nhaarman.mockitokotlin2.doReturn -import com.nhaarman.mockitokotlin2.doThrow -import com.nhaarman.mockitokotlin2.mock -import com.nhaarman.mockitokotlin2.never -import com.nhaarman.mockitokotlin2.times -import com.nhaarman.mockitokotlin2.verify -import com.nhaarman.mockitokotlin2.whenever +import org.mockito.kotlin.any +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.doThrow +import org.mockito.kotlin.mock +import org.mockito.kotlin.never +import org.mockito.kotlin.times +import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever import org.assertj.core.api.Assertions.assertThatExceptionOfType import org.junit.After import org.junit.Rule diff --git a/AndroidLib/src/test/kotlin/com/bloomberg/selekt/android/SQLiteDatabaseWALTest.kt b/AndroidLib/src/test/kotlin/com/bloomberg/selekt/android/SQLiteDatabaseWALTest.kt index ee5ba8c634..83d8ffe2a4 100644 --- a/AndroidLib/src/test/kotlin/com/bloomberg/selekt/android/SQLiteDatabaseWALTest.kt +++ b/AndroidLib/src/test/kotlin/com/bloomberg/selekt/android/SQLiteDatabaseWALTest.kt @@ -23,11 +23,12 @@ import com.bloomberg.selekt.Experimental import com.bloomberg.selekt.SQLTransactionListener import com.bloomberg.selekt.SQLiteAutoVacuumMode import com.bloomberg.selekt.SQLiteJournalMode -import com.nhaarman.mockitokotlin2.doThrow -import com.nhaarman.mockitokotlin2.mock -import com.nhaarman.mockitokotlin2.times -import com.nhaarman.mockitokotlin2.verify -import com.nhaarman.mockitokotlin2.whenever +import com.bloomberg.selekt.commons.deleteDatabase +import org.mockito.kotlin.doThrow +import org.mockito.kotlin.mock +import org.mockito.kotlin.times +import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever import org.assertj.core.api.Assertions.assertThatExceptionOfType import org.junit.After import org.junit.Before @@ -68,6 +69,12 @@ internal class SQLiteDatabaseWALTest { } } + @Test + fun deleteDatabase() { + SQLiteDatabase.deleteDatabase(file) + assertFalse(file.exists()) + } + @Test fun journalMode(): Unit = database.run { assertEquals(SQLiteJournalMode.WAL, journalMode) diff --git a/AndroidLib/src/test/kotlin/com/bloomberg/selekt/android/SQLiteOpenHelperCallbackTest.kt b/AndroidLib/src/test/kotlin/com/bloomberg/selekt/android/SQLiteOpenHelperCallbackTest.kt index 8570b240af..354fa71c76 100644 --- a/AndroidLib/src/test/kotlin/com/bloomberg/selekt/android/SQLiteOpenHelperCallbackTest.kt +++ b/AndroidLib/src/test/kotlin/com/bloomberg/selekt/android/SQLiteOpenHelperCallbackTest.kt @@ -17,7 +17,7 @@ package com.bloomberg.selekt.android import android.database.sqlite.SQLiteException -import com.nhaarman.mockitokotlin2.mock +import org.mockito.kotlin.mock import org.assertj.core.api.Assertions.assertThatExceptionOfType import org.junit.Test diff --git a/AndroidLib/src/test/kotlin/com/bloomberg/selekt/android/SQLiteOpenHelperTest.kt b/AndroidLib/src/test/kotlin/com/bloomberg/selekt/android/SQLiteOpenHelperTest.kt index f336c5fdbc..3dbf1eb3e6 100644 --- a/AndroidLib/src/test/kotlin/com/bloomberg/selekt/android/SQLiteOpenHelperTest.kt +++ b/AndroidLib/src/test/kotlin/com/bloomberg/selekt/android/SQLiteOpenHelperTest.kt @@ -19,16 +19,16 @@ package com.bloomberg.selekt.android import android.content.Context import com.bloomberg.selekt.commons.deleteDatabase import com.bloomberg.selekt.SQLiteJournalMode -import com.nhaarman.mockitokotlin2.any -import com.nhaarman.mockitokotlin2.doReturn -import com.nhaarman.mockitokotlin2.eq -import com.nhaarman.mockitokotlin2.inOrder -import com.nhaarman.mockitokotlin2.mock -import com.nhaarman.mockitokotlin2.never -import com.nhaarman.mockitokotlin2.same -import com.nhaarman.mockitokotlin2.times -import com.nhaarman.mockitokotlin2.verify -import com.nhaarman.mockitokotlin2.whenever +import org.mockito.kotlin.any +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.eq +import org.mockito.kotlin.inOrder +import org.mockito.kotlin.mock +import org.mockito.kotlin.never +import org.mockito.kotlin.same +import org.mockito.kotlin.times +import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever import org.assertj.core.api.Assertions.assertThatExceptionOfType import org.junit.After import org.junit.Rule diff --git a/AndroidLib/src/test/kotlin/com/bloomberg/selekt/android/SelektTest.kt b/AndroidLib/src/test/kotlin/com/bloomberg/selekt/android/SelektTest.kt index 28fcd35293..0d2d0e679c 100644 --- a/AndroidLib/src/test/kotlin/com/bloomberg/selekt/android/SelektTest.kt +++ b/AndroidLib/src/test/kotlin/com/bloomberg/selekt/android/SelektTest.kt @@ -18,10 +18,10 @@ package com.bloomberg.selekt.android import android.app.Application import com.bloomberg.selekt.Experimental -import com.nhaarman.mockitokotlin2.mock -import com.nhaarman.mockitokotlin2.same -import com.nhaarman.mockitokotlin2.times -import com.nhaarman.mockitokotlin2.verify +import org.mockito.kotlin.mock +import org.mockito.kotlin.same +import org.mockito.kotlin.times +import org.mockito.kotlin.verify import org.junit.Rule import org.junit.Test import org.junit.rules.DisableOnDebug diff --git a/AndroidLib/src/test/kotlin/com/bloomberg/selekt/android/support/SupportSQLiteDatabaseTest.kt b/AndroidLib/src/test/kotlin/com/bloomberg/selekt/android/support/SupportSQLiteDatabaseTest.kt index 06f54251af..e7e254561d 100644 --- a/AndroidLib/src/test/kotlin/com/bloomberg/selekt/android/support/SupportSQLiteDatabaseTest.kt +++ b/AndroidLib/src/test/kotlin/com/bloomberg/selekt/android/support/SupportSQLiteDatabaseTest.kt @@ -24,18 +24,18 @@ import androidx.sqlite.db.SupportSQLiteQuery import com.bloomberg.selekt.SQLiteJournalMode import com.bloomberg.selekt.android.ConflictAlgorithm import com.bloomberg.selekt.android.SQLiteDatabase -import com.nhaarman.mockitokotlin2.any -import com.nhaarman.mockitokotlin2.anyOrNull -import com.nhaarman.mockitokotlin2.doReturn -import com.nhaarman.mockitokotlin2.eq -import com.nhaarman.mockitokotlin2.isNull -import com.nhaarman.mockitokotlin2.mock -import com.nhaarman.mockitokotlin2.only -import com.nhaarman.mockitokotlin2.same -import com.nhaarman.mockitokotlin2.times -import com.nhaarman.mockitokotlin2.verify -import com.nhaarman.mockitokotlin2.verifyNoMoreInteractions -import com.nhaarman.mockitokotlin2.whenever +import org.mockito.kotlin.any +import org.mockito.kotlin.anyOrNull +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.eq +import org.mockito.kotlin.isNull +import org.mockito.kotlin.mock +import org.mockito.kotlin.only +import org.mockito.kotlin.same +import org.mockito.kotlin.times +import org.mockito.kotlin.verify +import org.mockito.kotlin.verifyNoMoreInteractions +import org.mockito.kotlin.whenever import org.assertj.core.api.Assertions.assertThatExceptionOfType import org.junit.Before import org.junit.Rule @@ -65,7 +65,7 @@ internal class SupportSQLiteDatabaseTest { @Before fun setUp() { - MockitoAnnotations.initMocks(this) + MockitoAnnotations.openMocks(this) supportDatabase = database.asSupportSQLiteDatabase() } diff --git a/AndroidLib/src/test/kotlin/com/bloomberg/selekt/android/support/SupportSQLiteOpenHelperCallbackTest.kt b/AndroidLib/src/test/kotlin/com/bloomberg/selekt/android/support/SupportSQLiteOpenHelperCallbackTest.kt index 0ead30f3a4..0546afd2c9 100644 --- a/AndroidLib/src/test/kotlin/com/bloomberg/selekt/android/support/SupportSQLiteOpenHelperCallbackTest.kt +++ b/AndroidLib/src/test/kotlin/com/bloomberg/selekt/android/support/SupportSQLiteOpenHelperCallbackTest.kt @@ -17,11 +17,11 @@ package com.bloomberg.selekt.android.support import androidx.sqlite.db.SupportSQLiteOpenHelper -import com.nhaarman.mockitokotlin2.any -import com.nhaarman.mockitokotlin2.eq -import com.nhaarman.mockitokotlin2.mock -import com.nhaarman.mockitokotlin2.times -import com.nhaarman.mockitokotlin2.verify +import org.mockito.kotlin.any +import org.mockito.kotlin.eq +import org.mockito.kotlin.mock +import org.mockito.kotlin.times +import org.mockito.kotlin.verify import org.junit.Test internal class SupportSQLiteOpenHelperCallbackTest { diff --git a/AndroidLib/src/test/kotlin/com/bloomberg/selekt/android/support/SupportSQLiteOpenHelperFactoryTest.kt b/AndroidLib/src/test/kotlin/com/bloomberg/selekt/android/support/SupportSQLiteOpenHelperFactoryTest.kt index 62e35a3415..0f759ad5e5 100644 --- a/AndroidLib/src/test/kotlin/com/bloomberg/selekt/android/support/SupportSQLiteOpenHelperFactoryTest.kt +++ b/AndroidLib/src/test/kotlin/com/bloomberg/selekt/android/support/SupportSQLiteOpenHelperFactoryTest.kt @@ -30,10 +30,10 @@ import androidx.room.Room import androidx.room.RoomDatabase import com.bloomberg.selekt.SQLiteJournalMode import com.bloomberg.selekt.android.SQLiteDatabase -import com.nhaarman.mockitokotlin2.any -import com.nhaarman.mockitokotlin2.doReturn -import com.nhaarman.mockitokotlin2.mock -import com.nhaarman.mockitokotlin2.whenever +import org.mockito.kotlin.any +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.mock +import org.mockito.kotlin.whenever import org.assertj.core.api.Assertions.assertThatExceptionOfType import org.junit.After import org.junit.Rule diff --git a/AndroidLib/src/test/kotlin/com/bloomberg/selekt/android/support/SupportSQLiteOpenHelperKtTest.kt b/AndroidLib/src/test/kotlin/com/bloomberg/selekt/android/support/SupportSQLiteOpenHelperKtTest.kt index f97596a686..6a52b7bbf0 100644 --- a/AndroidLib/src/test/kotlin/com/bloomberg/selekt/android/support/SupportSQLiteOpenHelperKtTest.kt +++ b/AndroidLib/src/test/kotlin/com/bloomberg/selekt/android/support/SupportSQLiteOpenHelperKtTest.kt @@ -17,7 +17,7 @@ package com.bloomberg.selekt.android.support import androidx.sqlite.db.SupportSQLiteOpenHelper -import com.nhaarman.mockitokotlin2.mock +import org.mockito.kotlin.mock import org.assertj.core.api.Assertions.assertThatExceptionOfType import org.junit.Test diff --git a/AndroidLib/src/test/kotlin/com/bloomberg/selekt/android/support/SupportSQLiteOpenHelperTest.kt b/AndroidLib/src/test/kotlin/com/bloomberg/selekt/android/support/SupportSQLiteOpenHelperTest.kt index f86a2da47a..ed45028395 100644 --- a/AndroidLib/src/test/kotlin/com/bloomberg/selekt/android/support/SupportSQLiteOpenHelperTest.kt +++ b/AndroidLib/src/test/kotlin/com/bloomberg/selekt/android/support/SupportSQLiteOpenHelperTest.kt @@ -18,12 +18,12 @@ package com.bloomberg.selekt.android.support import com.bloomberg.selekt.android.ISQLiteOpenHelper import com.bloomberg.selekt.android.SQLiteDatabase -import com.nhaarman.mockitokotlin2.doReturn -import com.nhaarman.mockitokotlin2.mock -import com.nhaarman.mockitokotlin2.times -import com.nhaarman.mockitokotlin2.verify -import com.nhaarman.mockitokotlin2.verifyNoMoreInteractions -import com.nhaarman.mockitokotlin2.whenever +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.mock +import org.mockito.kotlin.times +import org.mockito.kotlin.verify +import org.mockito.kotlin.verifyNoMoreInteractions +import org.mockito.kotlin.whenever import org.junit.Test import kotlin.test.assertSame diff --git a/AndroidLib/src/test/kotlin/com/bloomberg/selekt/android/support/SupportSQLiteProgramKtTest.kt b/AndroidLib/src/test/kotlin/com/bloomberg/selekt/android/support/SupportSQLiteProgramKtTest.kt index c4367208b1..ee45847438 100644 --- a/AndroidLib/src/test/kotlin/com/bloomberg/selekt/android/support/SupportSQLiteProgramKtTest.kt +++ b/AndroidLib/src/test/kotlin/com/bloomberg/selekt/android/support/SupportSQLiteProgramKtTest.kt @@ -17,10 +17,10 @@ package com.bloomberg.selekt.android.support import com.bloomberg.selekt.ISQLProgram -import com.nhaarman.mockitokotlin2.eq -import com.nhaarman.mockitokotlin2.same -import com.nhaarman.mockitokotlin2.times -import com.nhaarman.mockitokotlin2.verify +import org.mockito.kotlin.eq +import org.mockito.kotlin.same +import org.mockito.kotlin.times +import org.mockito.kotlin.verify import org.junit.Before import org.junit.Test import org.mockito.Mock @@ -32,7 +32,7 @@ internal class SupportSQLiteProgramKtTest { @Before fun setUp() { - MockitoAnnotations.initMocks(this) + MockitoAnnotations.openMocks(this) } @Test diff --git a/AndroidLib/src/test/kotlin/com/bloomberg/selekt/android/support/SupportSQLiteQueryKtTest.kt b/AndroidLib/src/test/kotlin/com/bloomberg/selekt/android/support/SupportSQLiteQueryKtTest.kt index 2c28350df9..9eba57758c 100644 --- a/AndroidLib/src/test/kotlin/com/bloomberg/selekt/android/support/SupportSQLiteQueryKtTest.kt +++ b/AndroidLib/src/test/kotlin/com/bloomberg/selekt/android/support/SupportSQLiteQueryKtTest.kt @@ -18,13 +18,13 @@ package com.bloomberg.selekt.android.support import androidx.sqlite.db.SupportSQLiteQuery import com.bloomberg.selekt.ISQLProgram -import com.nhaarman.mockitokotlin2.any -import com.nhaarman.mockitokotlin2.atLeastOnce -import com.nhaarman.mockitokotlin2.doReturn -import com.nhaarman.mockitokotlin2.mock -import com.nhaarman.mockitokotlin2.times -import com.nhaarman.mockitokotlin2.verify -import com.nhaarman.mockitokotlin2.whenever +import org.mockito.kotlin.any +import org.mockito.kotlin.atLeastOnce +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.mock +import org.mockito.kotlin.times +import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever import org.junit.Before import org.junit.Test import org.mockito.Mock @@ -37,7 +37,7 @@ internal class SupportSQLiteQueryKtTest { @Before fun setUp() { - MockitoAnnotations.initMocks(this) + MockitoAnnotations.openMocks(this) doReturn(42).whenever(query).argCount doReturn("SELECT * FROM Foo").whenever(query).sql } diff --git a/AndroidLib/src/test/kotlin/com/bloomberg/selekt/android/support/SupportSQLiteStatementKtTest.kt b/AndroidLib/src/test/kotlin/com/bloomberg/selekt/android/support/SupportSQLiteStatementKtTest.kt index bd54ec4aea..1bcf6685f3 100644 --- a/AndroidLib/src/test/kotlin/com/bloomberg/selekt/android/support/SupportSQLiteStatementKtTest.kt +++ b/AndroidLib/src/test/kotlin/com/bloomberg/selekt/android/support/SupportSQLiteStatementKtTest.kt @@ -17,10 +17,10 @@ package com.bloomberg.selekt.android.support import com.bloomberg.selekt.ISQLStatement -import com.nhaarman.mockitokotlin2.eq -import com.nhaarman.mockitokotlin2.same -import com.nhaarman.mockitokotlin2.times -import com.nhaarman.mockitokotlin2.verify +import org.mockito.kotlin.eq +import org.mockito.kotlin.same +import org.mockito.kotlin.times +import org.mockito.kotlin.verify import org.junit.Before import org.junit.Test import org.mockito.Mock @@ -32,7 +32,7 @@ internal class SupportSQLiteStatementKtTest { @Before fun setUp() { - MockitoAnnotations.initMocks(this) + MockitoAnnotations.openMocks(this) } @Test diff --git a/AndroidLib/src/test/kotlin/com/bloomberg/selekt/android/support/WrappedSQLiteTransactionListenerTest.kt b/AndroidLib/src/test/kotlin/com/bloomberg/selekt/android/support/WrappedSQLiteTransactionListenerTest.kt index 4205a9ffcd..5eaadec732 100644 --- a/AndroidLib/src/test/kotlin/com/bloomberg/selekt/android/support/WrappedSQLiteTransactionListenerTest.kt +++ b/AndroidLib/src/test/kotlin/com/bloomberg/selekt/android/support/WrappedSQLiteTransactionListenerTest.kt @@ -17,10 +17,10 @@ package com.bloomberg.selekt.android.support import android.database.sqlite.SQLiteTransactionListener -import com.nhaarman.mockitokotlin2.mock -import com.nhaarman.mockitokotlin2.never -import com.nhaarman.mockitokotlin2.times -import com.nhaarman.mockitokotlin2.verify +import org.mockito.kotlin.mock +import org.mockito.kotlin.never +import org.mockito.kotlin.times +import org.mockito.kotlin.verify import org.junit.Test import kotlin.test.assertEquals import kotlin.test.assertNotEquals diff --git a/CHANGELOG.md b/CHANGELOG.md index e362765241..a2c9e1d570 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,28 @@ Change Log ========== +## Version 0.13.0 + +### Fixes + +* Throw if we try to make a connection when the connection factory is closed. +* Scheduled eviction from the connection pool respects any cancellation of the eviction future. +* In `Mutex` only ever test the remaining available waiting time if the specified wait interval was non-negative to begin with. +* In `CommonObjectPool` decrement the internal connection count if making a connection should result in a thrown exception. +* In `CommonObjectPool` increment the internal connection count and then attempt to schedule for eviction, rather than the other way round. + +### Features + +* Support Java 11. + +### Dependencies + +* Android Gradle Plugin 4.2.1. +* Gradle 7.0.2. +* JaCoCo 0.8.7. +* Mockito 3.9.0. +* Mockito-Kotlin 3.2.0. + ## Version 0.12.7 ### Fixes diff --git a/Lib/src/main/kotlin/com/bloomberg/selekt/Databases.kt b/Lib/src/main/kotlin/com/bloomberg/selekt/Databases.kt index 68db4dddf4..3e664bd31d 100644 --- a/Lib/src/main/kotlin/com/bloomberg/selekt/Databases.kt +++ b/Lib/src/main/kotlin/com/bloomberg/selekt/Databases.kt @@ -16,6 +16,7 @@ package com.bloomberg.selekt +import com.bloomberg.selekt.annotations.Generated import com.bloomberg.selekt.commons.ManagedStringBuilder import com.bloomberg.selekt.commons.forUntil import com.bloomberg.selekt.pools.Priority @@ -32,6 +33,7 @@ private object SharedSqlBuilder { override fun initialValue() = ManagedStringBuilder() } + @Generated inline fun use(block: StringBuilder.() -> T) = threadLocal.get().use { block(this) } } @@ -44,7 +46,7 @@ private object SharedSqlBuilder { * * This is the same strategy Google employs in the Android SDK. * - * @link [Android's SQLiteDatabase](https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/database/sqlite/SQLiteDatabase.java) + * @link [Android's SQLiteDatabase](https://cs.android.com/android/platform/superproject/+/master:frameworks/base/core/java/android/database/sqlite/SQLiteDatabase.java) */ @ThreadSafe class SQLDatabase constructor( diff --git a/Lib/src/main/kotlin/com/bloomberg/selekt/Key.kt b/Lib/src/main/kotlin/com/bloomberg/selekt/Key.kt index 009ce04966..63b65b5875 100644 --- a/Lib/src/main/kotlin/com/bloomberg/selekt/Key.kt +++ b/Lib/src/main/kotlin/com/bloomberg/selekt/Key.kt @@ -18,6 +18,7 @@ package com.bloomberg.selekt import com.bloomberg.selekt.annotations.Generated import com.bloomberg.selekt.commons.zero +import javax.annotation.concurrent.GuardedBy private const val KEY_SIZE = 32 @@ -27,14 +28,21 @@ internal class Key(value: ByteArray) { } private val lock = Any() + @GuardedBy("lock") private val value: ByteArray = value.copyOf() + @GuardedBy("lock") + private var isDestroyed = false fun zero() = synchronized(lock) { - value.fill(0) + if (!isDestroyed) { + value.zero() + isDestroyed = true + } } @Generated inline fun use(action: (ByteArray) -> R) = synchronized(lock) { + check(!isDestroyed) { "Key is destroyed." } value.copyOf() }.let { try { diff --git a/Lib/src/main/kotlin/com/bloomberg/selekt/Pools.kt b/Lib/src/main/kotlin/com/bloomberg/selekt/Pools.kt index 21291b2009..07ccb5d816 100644 --- a/Lib/src/main/kotlin/com/bloomberg/selekt/Pools.kt +++ b/Lib/src/main/kotlin/com/bloomberg/selekt/Pools.kt @@ -63,7 +63,7 @@ private fun DatabaseConfiguration.toPoolConfiguration() = PoolConfiguration( ) @ThreadSafe -private class SQLConnectionFactory( +internal class SQLConnectionFactory( private val path: String, private val sqlite: SQLite, private val configuration: DatabaseConfiguration, @@ -72,28 +72,19 @@ private class SQLConnectionFactory( ) : IObjectFactory { private val busyLock = Any() - private var createdCount = 0 - private var destroyedCount = 0 - override fun close() { key?.zero() } override fun destroyObject(obj: CloseableSQLExecutor) = synchronized(busyLock) { - obj.close().also { - ++destroyedCount - } + obj.close() } override fun makeObject() = synchronized(busyLock) { - SQLConnection(path, sqlite, configuration, SQL_OPEN_READONLY, random, key).also { - ++createdCount - } + SQLConnection(path, sqlite, configuration, SQL_OPEN_READONLY, random, key) } override fun makePrimaryObject() = synchronized(busyLock) { - SQLConnection(path, sqlite, configuration, SQL_OPEN_READWRITE or SQL_OPEN_CREATE, random, key).also { - ++createdCount - } + SQLConnection(path, sqlite, configuration, SQL_OPEN_READWRITE or SQL_OPEN_CREATE, random, key) } } diff --git a/Lib/src/main/kotlin/com/bloomberg/selekt/SQLBlob.kt b/Lib/src/main/kotlin/com/bloomberg/selekt/SQLBlob.kt index ae1cef8ab8..28b2f37b08 100644 --- a/Lib/src/main/kotlin/com/bloomberg/selekt/SQLBlob.kt +++ b/Lib/src/main/kotlin/com/bloomberg/selekt/SQLBlob.kt @@ -88,11 +88,10 @@ internal class BlobInputStream( destination: ByteArray, offset: Int, length: Int - ): Int { - if (offset < 0 || length < 0) { - throw ArrayIndexOutOfBoundsException("Offset: $offset; length: $length") - } - return available().let { + ) = if (offset < 0 || length < 0) { + throw ArrayIndexOutOfBoundsException("Offset: $offset; length: $length") + } else { + available().let { if (it > 0) { minOf(it, length).also { len -> if (offset + len > destination.size) { diff --git a/Lib/src/main/kotlin/com/bloomberg/selekt/SharedCloseable.kt b/Lib/src/main/kotlin/com/bloomberg/selekt/SharedCloseable.kt index b91ee27bf4..218ce00cfe 100644 --- a/Lib/src/main/kotlin/com/bloomberg/selekt/SharedCloseable.kt +++ b/Lib/src/main/kotlin/com/bloomberg/selekt/SharedCloseable.kt @@ -50,8 +50,7 @@ abstract class SharedCloseable : Closeable { } private companion object { - const val RETAIN_COUNT = "retainCount" val retainCountUpdater: AtomicIntegerFieldUpdater = AtomicIntegerFieldUpdater.newUpdater( - SharedCloseable::class.java, RETAIN_COUNT) + SharedCloseable::class.java, "retainCount") } } diff --git a/Lib/src/main/kotlin/com/bloomberg/selekt/pools/CommonObjectPool.kt b/Lib/src/main/kotlin/com/bloomberg/selekt/pools/CommonObjectPool.kt index 1409a2ef5f..b1ccbeab9e 100644 --- a/Lib/src/main/kotlin/com/bloomberg/selekt/pools/CommonObjectPool.kt +++ b/Lib/src/main/kotlin/com/bloomberg/selekt/pools/CommonObjectPool.kt @@ -82,8 +82,8 @@ class CommonObjectPool>( return it } if (count < configuration.maxTotal) { - attemptScheduleEviction() ++count + attemptScheduleEviction() return@withLockInterruptibly Unit } otherPool.borrowObjectOrNull()?.let { return it } @@ -93,7 +93,13 @@ class CommonObjectPool>( } null }?.let { - return factory.makeObject() + return runCatching { factory.makeObject() }.getOrElse { + lock.withLock { + --count + available.signal() + } + throw it + } } error("Pool is closed.") } @@ -189,9 +195,6 @@ class CommonObjectPool>( private infix fun T.shouldBeRemovedAt( priority: Priority? ) = (this@shouldBeRemovedAt.tag != this@CommonObjectPool.tag).let { - priority == null && it && future?.isCancelled == false || - isClosed.get() || - priority.isHigh() || - it + it && (priority != null || !future!!.isCancelled) || isClosed.get() || priority.isHigh() } } diff --git a/Lib/src/main/kotlin/com/bloomberg/selekt/pools/Mutex.kt b/Lib/src/main/kotlin/com/bloomberg/selekt/pools/Mutex.kt index 8d1ca8f1cf..df4dce9112 100644 --- a/Lib/src/main/kotlin/com/bloomberg/selekt/pools/Mutex.kt +++ b/Lib/src/main/kotlin/com/bloomberg/selekt/pools/Mutex.kt @@ -133,11 +133,12 @@ internal class Mutex { } else if (isCancellable && isCancelled()) { removeThisWaiterNotifyingNext() cancellationError() - } - remainingNanos = (deadlineNanos - System.nanoTime()).also { - if (it <= 0L) { - removeThisWaiterNotifyingNext() - return false + } else if (intervalNanos > 0L) { + remainingNanos = (deadlineNanos - System.nanoTime()).also { + if (it <= 0L) { + removeThisWaiterNotifyingNext() + return false + } } } } @@ -161,13 +162,11 @@ internal class Mutex { @Suppress("unused") private val ensureLoaded: Class<*> = LockSupport::class.java - const val IS_LOCKED = "isLocked" val isLockedUpdater: AtomicIntegerFieldUpdater = AtomicIntegerFieldUpdater.newUpdater( - Mutex::class.java, IS_LOCKED) + Mutex::class.java, "isLocked") - const val IS_CANCELLED = "isCancelled" val isCancelledUpdater: AtomicIntegerFieldUpdater = AtomicIntegerFieldUpdater.newUpdater( - Mutex::class.java, IS_CANCELLED) + Mutex::class.java, "isCancelled") fun cancellationError(): Nothing = error("Mutex received cancellation signal.") } diff --git a/Lib/src/main/kotlin/com/bloomberg/selekt/pools/SingleObjectPool.kt b/Lib/src/main/kotlin/com/bloomberg/selekt/pools/SingleObjectPool.kt index 8d71efc478..3c1d26fe28 100644 --- a/Lib/src/main/kotlin/com/bloomberg/selekt/pools/SingleObjectPool.kt +++ b/Lib/src/main/kotlin/com/bloomberg/selekt/pools/SingleObjectPool.kt @@ -110,7 +110,7 @@ class SingleObjectPool>( @GuardedBy("mutex") private fun attemptScheduleEviction() { - if (future?.isCancelled == false || evictionIntervalMillis < 0L || isClosed) { + if (evictionIntervalMillis < 0L || isClosed) { return } future = executor.scheduleAtFixedRate( @@ -149,10 +149,6 @@ class SingleObjectPool>( } } - private infix fun T.shouldBeRemovedAt(priority: Priority?) = canEvict.let { - priority == null && it && future?.isCancelled == false || - isClosed || - priority.isHigh() || - it - } + private infix fun T.shouldBeRemovedAt(priority: Priority?) = + canEvict && (priority != null || !future!!.isCancelled) || isClosed || priority.isHigh() } diff --git a/Lib/src/test/kotlin/com/bloomberg/selekt/ForwardCursorTest.kt b/Lib/src/test/kotlin/com/bloomberg/selekt/ForwardCursorTest.kt index f8143b6b4c..dd331830ef 100644 --- a/Lib/src/test/kotlin/com/bloomberg/selekt/ForwardCursorTest.kt +++ b/Lib/src/test/kotlin/com/bloomberg/selekt/ForwardCursorTest.kt @@ -16,16 +16,16 @@ package com.bloomberg.selekt -import com.nhaarman.mockitokotlin2.any -import com.nhaarman.mockitokotlin2.doAnswer -import com.nhaarman.mockitokotlin2.doReturn -import com.nhaarman.mockitokotlin2.eq -import com.nhaarman.mockitokotlin2.mock -import com.nhaarman.mockitokotlin2.times -import com.nhaarman.mockitokotlin2.verify -import com.nhaarman.mockitokotlin2.whenever import org.assertj.core.api.Assertions.assertThatExceptionOfType import org.junit.jupiter.api.Test +import org.mockito.kotlin.any +import org.mockito.kotlin.doAnswer +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.eq +import org.mockito.kotlin.mock +import org.mockito.kotlin.times +import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever import org.mockito.stubbing.Answer import kotlin.test.assertEquals import kotlin.test.assertFalse diff --git a/Lib/src/test/kotlin/com/bloomberg/selekt/KeyTest.kt b/Lib/src/test/kotlin/com/bloomberg/selekt/KeyTest.kt new file mode 100644 index 0000000000..dad94bdc81 --- /dev/null +++ b/Lib/src/test/kotlin/com/bloomberg/selekt/KeyTest.kt @@ -0,0 +1,49 @@ +/* + * Copyright 2021 Bloomberg Finance L.P. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.bloomberg.selekt + +import org.assertj.core.api.Assertions.assertThatExceptionOfType +import org.junit.jupiter.api.Test +import kotlin.test.assertEquals +import kotlin.test.assertNotSame + +internal class KeyTest { + @Test + fun makesCopy() { + val raw = ByteArray(32) { 0x42 } + Key(raw).use { + assertEquals(raw.first(), it.first()) + assertEquals(raw.size, it.size) + assertNotSame(raw, it) + } + } + + @Test + fun zerosAfterUse() { + assertEquals(0, Key(ByteArray(32) { 0x42 }).use { it }.first()) + } + + @Test + fun zeroThenUseThrows() { + Key(ByteArray(32) { 0x42 }).apply { + zero() + assertThatExceptionOfType(IllegalStateException::class.java).isThrownBy { + use {} + } + } + } +} diff --git a/Lib/src/test/kotlin/com/bloomberg/selekt/LruCacheTest.kt b/Lib/src/test/kotlin/com/bloomberg/selekt/LruCacheTest.kt index 9f1ab75d24..d325497fa8 100644 --- a/Lib/src/test/kotlin/com/bloomberg/selekt/LruCacheTest.kt +++ b/Lib/src/test/kotlin/com/bloomberg/selekt/LruCacheTest.kt @@ -16,20 +16,20 @@ package com.bloomberg.selekt -import com.nhaarman.mockitokotlin2.anyOrNull -import com.nhaarman.mockitokotlin2.doReturn -import com.nhaarman.mockitokotlin2.inOrder -import com.nhaarman.mockitokotlin2.mock -import com.nhaarman.mockitokotlin2.never -import com.nhaarman.mockitokotlin2.same -import com.nhaarman.mockitokotlin2.times -import com.nhaarman.mockitokotlin2.verify -import com.nhaarman.mockitokotlin2.whenever import org.junit.Rule import org.junit.jupiter.api.Test import org.junit.rules.DisableOnDebug import org.junit.rules.RuleChain import org.junit.rules.Timeout +import org.mockito.kotlin.anyOrNull +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.inOrder +import org.mockito.kotlin.mock +import org.mockito.kotlin.never +import org.mockito.kotlin.same +import org.mockito.kotlin.times +import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever import kotlin.test.assertFalse import kotlin.test.assertSame import kotlin.test.assertTrue diff --git a/Lib/src/test/kotlin/com/bloomberg/selekt/SQLBlobInputStreamTest.kt b/Lib/src/test/kotlin/com/bloomberg/selekt/SQLBlobInputStreamTest.kt index 9f6b193bc2..8e74a0e4c9 100644 --- a/Lib/src/test/kotlin/com/bloomberg/selekt/SQLBlobInputStreamTest.kt +++ b/Lib/src/test/kotlin/com/bloomberg/selekt/SQLBlobInputStreamTest.kt @@ -16,15 +16,15 @@ package com.bloomberg.selekt -import com.nhaarman.mockitokotlin2.any -import com.nhaarman.mockitokotlin2.doAnswer -import com.nhaarman.mockitokotlin2.doReturn -import com.nhaarman.mockitokotlin2.mock -import com.nhaarman.mockitokotlin2.never -import com.nhaarman.mockitokotlin2.verify -import com.nhaarman.mockitokotlin2.whenever import org.assertj.core.api.Assertions.assertThatExceptionOfType import org.junit.jupiter.api.Test +import org.mockito.kotlin.any +import org.mockito.kotlin.doAnswer +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.mock +import org.mockito.kotlin.never +import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever import kotlin.test.assertEquals internal class SQLBlobInputStreamTest { diff --git a/Lib/src/test/kotlin/com/bloomberg/selekt/SQLBlobOutputStreamTest.kt b/Lib/src/test/kotlin/com/bloomberg/selekt/SQLBlobOutputStreamTest.kt index b1087a2cdd..3f68edd733 100644 --- a/Lib/src/test/kotlin/com/bloomberg/selekt/SQLBlobOutputStreamTest.kt +++ b/Lib/src/test/kotlin/com/bloomberg/selekt/SQLBlobOutputStreamTest.kt @@ -16,19 +16,19 @@ package com.bloomberg.selekt -import com.nhaarman.mockitokotlin2.any -import com.nhaarman.mockitokotlin2.argThat -import com.nhaarman.mockitokotlin2.doAnswer -import com.nhaarman.mockitokotlin2.doReturn -import com.nhaarman.mockitokotlin2.eq -import com.nhaarman.mockitokotlin2.mock -import com.nhaarman.mockitokotlin2.never -import com.nhaarman.mockitokotlin2.same -import com.nhaarman.mockitokotlin2.times -import com.nhaarman.mockitokotlin2.verify -import com.nhaarman.mockitokotlin2.whenever -import org.junit.jupiter.api.Test import org.assertj.core.api.Assertions.assertThatExceptionOfType +import org.junit.jupiter.api.Test +import org.mockito.kotlin.any +import org.mockito.kotlin.argThat +import org.mockito.kotlin.doAnswer +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.eq +import org.mockito.kotlin.mock +import org.mockito.kotlin.never +import org.mockito.kotlin.same +import org.mockito.kotlin.times +import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever internal class SQLBlobOutputStreamTest { @Test diff --git a/Lib/src/test/kotlin/com/bloomberg/selekt/SQLBlobTest.kt b/Lib/src/test/kotlin/com/bloomberg/selekt/SQLBlobTest.kt index a328f05e38..76d42f4c52 100644 --- a/Lib/src/test/kotlin/com/bloomberg/selekt/SQLBlobTest.kt +++ b/Lib/src/test/kotlin/com/bloomberg/selekt/SQLBlobTest.kt @@ -16,16 +16,16 @@ package com.bloomberg.selekt -import com.nhaarman.mockitokotlin2.any -import com.nhaarman.mockitokotlin2.doReturn -import com.nhaarman.mockitokotlin2.eq -import com.nhaarman.mockitokotlin2.mock -import com.nhaarman.mockitokotlin2.same -import com.nhaarman.mockitokotlin2.times -import com.nhaarman.mockitokotlin2.verify -import com.nhaarman.mockitokotlin2.whenever import org.assertj.core.api.Assertions.assertThatExceptionOfType import org.junit.jupiter.api.Test +import org.mockito.kotlin.any +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.eq +import org.mockito.kotlin.mock +import org.mockito.kotlin.same +import org.mockito.kotlin.times +import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever import kotlin.test.assertEquals import kotlin.test.assertFalse import kotlin.test.assertTrue diff --git a/Lib/src/test/kotlin/com/bloomberg/selekt/SQLConnectionFactoryTest.kt b/Lib/src/test/kotlin/com/bloomberg/selekt/SQLConnectionFactoryTest.kt new file mode 100644 index 0000000000..47a4332925 --- /dev/null +++ b/Lib/src/test/kotlin/com/bloomberg/selekt/SQLConnectionFactoryTest.kt @@ -0,0 +1,43 @@ +/* + * Copyright 2021 Bloomberg Finance L.P. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.bloomberg.selekt + +import org.assertj.core.api.Assertions.assertThatExceptionOfType +import org.junit.jupiter.api.Test +import org.mockito.kotlin.mock + +internal class SQLConnectionFactoryTest { + @Test + fun closeThenMakePrimaryThrows() { + SQLConnectionFactory("", mock(), mock(), mock(), mock()).apply { + close() + assertThatExceptionOfType(IllegalStateException::class.java).isThrownBy { + makePrimaryObject() + } + } + } + + @Test + fun closeThenMakeThrows() { + SQLConnectionFactory("", mock(), mock(), mock(), mock()).apply { + close() + assertThatExceptionOfType(IllegalStateException::class.java).isThrownBy { + makeObject() + } + } + } +} diff --git a/Lib/src/test/kotlin/com/bloomberg/selekt/SQLConnectionTest.kt b/Lib/src/test/kotlin/com/bloomberg/selekt/SQLConnectionTest.kt index d029f5534d..33ccc6b6f6 100644 --- a/Lib/src/test/kotlin/com/bloomberg/selekt/SQLConnectionTest.kt +++ b/Lib/src/test/kotlin/com/bloomberg/selekt/SQLConnectionTest.kt @@ -16,28 +16,27 @@ package com.bloomberg.selekt -import com.nhaarman.mockitokotlin2.any -import com.nhaarman.mockitokotlin2.doAnswer -import com.nhaarman.mockitokotlin2.doReturn -import com.nhaarman.mockitokotlin2.doThrow -import com.nhaarman.mockitokotlin2.eq -import com.nhaarman.mockitokotlin2.isNull -import com.nhaarman.mockitokotlin2.mock -import com.nhaarman.mockitokotlin2.times -import com.nhaarman.mockitokotlin2.verify -import com.nhaarman.mockitokotlin2.whenever import org.assertj.core.api.Assertions.assertThatExceptionOfType -import org.junit.jupiter.api.BeforeEach import org.junit.Rule +import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.junit.rules.DisableOnDebug import org.junit.rules.Timeout import org.mockito.Mock import org.mockito.MockitoAnnotations +import org.mockito.kotlin.any +import org.mockito.kotlin.doAnswer +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.doThrow +import org.mockito.kotlin.eq +import org.mockito.kotlin.isNull +import org.mockito.kotlin.mock +import org.mockito.kotlin.times +import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever import org.mockito.stubbing.Answer -import java.lang.IllegalArgumentException -import kotlin.test.assertEquals import java.util.concurrent.TimeUnit +import kotlin.test.assertEquals import kotlin.test.assertFalse import kotlin.test.assertTrue @@ -56,7 +55,7 @@ internal class SQLConnectionTest { @BeforeEach fun setUp() { - MockitoAnnotations.initMocks(this) + MockitoAnnotations.openMocks(this) whenever(sqlite.openV2(any(), any(), any())).thenAnswer { requireNotNull(it.arguments[2] as? LongArray)[0] = DB 0 @@ -205,6 +204,66 @@ internal class SQLConnectionTest { } } + @Test + fun executeForInt() { + val value = 7 + val statement = 43L + whenever(sqlite.openV2(any(), any(), any())) doAnswer Answer { + (it.arguments[2] as LongArray)[0] = 42L + 0 + } + whenever(sqlite.prepareV2(any(), any(), any())) doAnswer Answer { + (it.arguments[2] as LongArray)[0] = statement + 0 + } + whenever(sqlite.step(any())) doReturn SQL_ROW + whenever(sqlite.columnInt(any(), any())) doReturn value + SQLConnection("file::memory:", sqlite, databaseConfiguration, 0, CommonThreadLocalRandom, null).use { + assertEquals(value, it.executeForInt("SELECT * FROM Foo LIMIT 1")) + } + verify(sqlite, times(1)).columnInt(eq(statement), eq(0)) + } + + @Test + fun executeForLong() { + val value = 7L + val statement = 43L + whenever(sqlite.openV2(any(), any(), any())) doAnswer Answer { + (it.arguments[2] as LongArray)[0] = 42L + 0 + } + whenever(sqlite.prepareV2(any(), any(), any())) doAnswer Answer { + (it.arguments[2] as LongArray)[0] = statement + 0 + } + whenever(sqlite.step(any())) doReturn SQL_ROW + whenever(sqlite.columnInt64(any(), any())) doReturn value + SQLConnection("file::memory:", sqlite, databaseConfiguration, 0, CommonThreadLocalRandom, null).use { + assertEquals(value, it.executeForLong("SELECT * FROM Foo LIMIT 1")) + } + verify(sqlite, times(1)).columnInt64(eq(statement), eq(0)) + } + + @Test + fun executeForString() { + val text = "hello" + val statement = 43L + whenever(sqlite.openV2(any(), any(), any())) doAnswer Answer { + (it.arguments[2] as LongArray)[0] = 42L + 0 + } + whenever(sqlite.prepareV2(any(), any(), any())) doAnswer Answer { + (it.arguments[2] as LongArray)[0] = statement + 0 + } + whenever(sqlite.step(any())) doReturn SQL_ROW + whenever(sqlite.columnText(any(), any())) doReturn text + SQLConnection("file::memory:", sqlite, databaseConfiguration, 0, CommonThreadLocalRandom, null).use { + assertEquals(text, it.executeForString("SELECT * FROM Foo LIMIT 1")) + } + verify(sqlite, times(1)).columnText(eq(statement), eq(0)) + } + @Test fun executeForBlobReadOnly() { whenever(sqlite.openV2(any(), any(), any())) doAnswer Answer { diff --git a/Lib/src/test/kotlin/com/bloomberg/selekt/SQLDatabaseTest.kt b/Lib/src/test/kotlin/com/bloomberg/selekt/SQLDatabaseTest.kt index 222d1f1504..3b548e4abc 100644 --- a/Lib/src/test/kotlin/com/bloomberg/selekt/SQLDatabaseTest.kt +++ b/Lib/src/test/kotlin/com/bloomberg/selekt/SQLDatabaseTest.kt @@ -16,23 +16,22 @@ package com.bloomberg.selekt -import com.nhaarman.mockitokotlin2.any -import com.nhaarman.mockitokotlin2.doReturn -import com.nhaarman.mockitokotlin2.eq -import com.nhaarman.mockitokotlin2.inOrder -import com.nhaarman.mockitokotlin2.times -import com.nhaarman.mockitokotlin2.whenever import org.assertj.core.api.Assertions.assertThatExceptionOfType +import org.junit.Rule import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.BeforeEach -import org.junit.Rule import org.junit.jupiter.api.Test import org.junit.rules.DisableOnDebug import org.junit.rules.RuleChain import org.junit.rules.Timeout import org.mockito.Mock import org.mockito.MockitoAnnotations -import kotlin.IllegalStateException +import org.mockito.kotlin.any +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.eq +import org.mockito.kotlin.inOrder +import org.mockito.kotlin.times +import org.mockito.kotlin.whenever import kotlin.test.assertFalse import kotlin.test.assertTrue @@ -55,7 +54,7 @@ internal class SQLDatabaseTest { @BeforeEach fun setUp() { - MockitoAnnotations.initMocks(this) + MockitoAnnotations.openMocks(this) whenever(sqlite.openV2(any(), any(), any())).thenAnswer { requireNotNull(it.arguments[2] as? LongArray)[0] = DB 0 diff --git a/Lib/src/test/kotlin/com/bloomberg/selekt/SQLPreparedStatementTest.kt b/Lib/src/test/kotlin/com/bloomberg/selekt/SQLPreparedStatementTest.kt index 27ae4dd38d..7b295b9f74 100644 --- a/Lib/src/test/kotlin/com/bloomberg/selekt/SQLPreparedStatementTest.kt +++ b/Lib/src/test/kotlin/com/bloomberg/selekt/SQLPreparedStatementTest.kt @@ -16,17 +16,17 @@ package com.bloomberg.selekt -import com.nhaarman.mockitokotlin2.any -import com.nhaarman.mockitokotlin2.doAnswer -import com.nhaarman.mockitokotlin2.doReturn -import com.nhaarman.mockitokotlin2.eq -import com.nhaarman.mockitokotlin2.mock -import com.nhaarman.mockitokotlin2.times -import com.nhaarman.mockitokotlin2.verify -import com.nhaarman.mockitokotlin2.whenever import org.assertj.core.api.Assertions.assertThatExceptionOfType import org.junit.jupiter.api.Test import org.mockito.invocation.InvocationOnMock +import org.mockito.kotlin.any +import org.mockito.kotlin.doAnswer +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.eq +import org.mockito.kotlin.mock +import org.mockito.kotlin.times +import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever import org.mockito.stubbing.Answer import kotlin.test.assertEquals import kotlin.test.assertFalse diff --git a/Lib/src/test/kotlin/com/bloomberg/selekt/SQLQueryTest.kt b/Lib/src/test/kotlin/com/bloomberg/selekt/SQLQueryTest.kt index bfbeda4e36..c7787139e1 100644 --- a/Lib/src/test/kotlin/com/bloomberg/selekt/SQLQueryTest.kt +++ b/Lib/src/test/kotlin/com/bloomberg/selekt/SQLQueryTest.kt @@ -16,8 +16,8 @@ package com.bloomberg.selekt -import com.nhaarman.mockitokotlin2.mock import org.junit.jupiter.api.Test +import org.mockito.kotlin.mock import kotlin.test.assertEquals import kotlin.test.assertNull import kotlin.test.assertSame diff --git a/Lib/src/test/kotlin/com/bloomberg/selekt/SimpleSQLQueryTest.kt b/Lib/src/test/kotlin/com/bloomberg/selekt/SimpleSQLQueryTest.kt index 10b421b89d..f7fa942eed 100644 --- a/Lib/src/test/kotlin/com/bloomberg/selekt/SimpleSQLQueryTest.kt +++ b/Lib/src/test/kotlin/com/bloomberg/selekt/SimpleSQLQueryTest.kt @@ -16,14 +16,14 @@ package com.bloomberg.selekt -import com.nhaarman.mockitokotlin2.eq -import com.nhaarman.mockitokotlin2.mock -import com.nhaarman.mockitokotlin2.same -import com.nhaarman.mockitokotlin2.times -import com.nhaarman.mockitokotlin2.verify import org.assertj.core.api.Assertions.assertThatExceptionOfType import org.junit.Test import org.junit.jupiter.api.assertThrows +import org.mockito.kotlin.eq +import org.mockito.kotlin.mock +import org.mockito.kotlin.same +import org.mockito.kotlin.times +import org.mockito.kotlin.verify internal class SimpleSQLQueryTest { @Test diff --git a/Lib/src/test/kotlin/com/bloomberg/selekt/WindowedCursorTest.kt b/Lib/src/test/kotlin/com/bloomberg/selekt/WindowedCursorTest.kt index 2c7466042f..6e8434296e 100644 --- a/Lib/src/test/kotlin/com/bloomberg/selekt/WindowedCursorTest.kt +++ b/Lib/src/test/kotlin/com/bloomberg/selekt/WindowedCursorTest.kt @@ -16,13 +16,13 @@ package com.bloomberg.selekt -import com.nhaarman.mockitokotlin2.doReturn -import com.nhaarman.mockitokotlin2.eq -import com.nhaarman.mockitokotlin2.mock -import com.nhaarman.mockitokotlin2.times -import com.nhaarman.mockitokotlin2.verify -import com.nhaarman.mockitokotlin2.whenever import org.junit.jupiter.api.Test +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.eq +import org.mockito.kotlin.mock +import org.mockito.kotlin.times +import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever import kotlin.test.assertEquals import kotlin.test.assertFalse import kotlin.test.assertSame diff --git a/Lib/src/test/kotlin/com/bloomberg/selekt/commons/DatabaseKtTest.kt b/Lib/src/test/kotlin/com/bloomberg/selekt/commons/DatabaseKtTest.kt index 99563e2d30..ae70b3451f 100644 --- a/Lib/src/test/kotlin/com/bloomberg/selekt/commons/DatabaseKtTest.kt +++ b/Lib/src/test/kotlin/com/bloomberg/selekt/commons/DatabaseKtTest.kt @@ -16,13 +16,13 @@ package com.bloomberg.selekt.commons -import com.nhaarman.mockitokotlin2.doReturn -import com.nhaarman.mockitokotlin2.mock -import com.nhaarman.mockitokotlin2.whenever import org.assertj.core.api.Assertions.assertThatExceptionOfType import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertDoesNotThrow +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.mock +import org.mockito.kotlin.whenever import java.io.File import java.nio.file.Files import kotlin.test.assertEquals diff --git a/Lib/src/test/kotlin/com/bloomberg/selekt/commons/NativeResourcesKtTest.kt b/Lib/src/test/kotlin/com/bloomberg/selekt/commons/NativeResourcesKtTest.kt index 72538930f5..c55811a147 100644 --- a/Lib/src/test/kotlin/com/bloomberg/selekt/commons/NativeResourcesKtTest.kt +++ b/Lib/src/test/kotlin/com/bloomberg/selekt/commons/NativeResourcesKtTest.kt @@ -18,7 +18,6 @@ package com.bloomberg.selekt.commons import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertThrows -import java.lang.IllegalStateException import kotlin.test.assertEquals import kotlin.test.assertTrue diff --git a/Lib/src/test/kotlin/com/bloomberg/selekt/pools/CommonObjectPoolTest.kt b/Lib/src/test/kotlin/com/bloomberg/selekt/pools/CommonObjectPoolTest.kt index b0d89e5f0f..f77daf05be 100644 --- a/Lib/src/test/kotlin/com/bloomberg/selekt/pools/CommonObjectPoolTest.kt +++ b/Lib/src/test/kotlin/com/bloomberg/selekt/pools/CommonObjectPoolTest.kt @@ -16,13 +16,6 @@ package com.bloomberg.selekt.pools -import com.nhaarman.mockitokotlin2.doReturn -import com.nhaarman.mockitokotlin2.mock -import com.nhaarman.mockitokotlin2.same -import com.nhaarman.mockitokotlin2.times -import com.nhaarman.mockitokotlin2.verify -import com.nhaarman.mockitokotlin2.verifyZeroInteractions -import com.nhaarman.mockitokotlin2.whenever import org.assertj.core.api.Assertions.assertThatExceptionOfType import org.junit.After import org.junit.Before @@ -31,11 +24,22 @@ import org.junit.Test import org.junit.jupiter.api.assertDoesNotThrow import org.junit.rules.DisableOnDebug import org.junit.rules.Timeout -import java.lang.IllegalArgumentException +import org.mockito.kotlin.doAnswer +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.mock +import org.mockito.kotlin.same +import org.mockito.kotlin.times +import org.mockito.kotlin.verify +import org.mockito.kotlin.verifyZeroInteractions +import org.mockito.kotlin.whenever +import org.mockito.stubbing.Answer +import java.io.IOException import java.util.Collections import java.util.concurrent.Executors +import java.util.concurrent.ScheduledExecutorService import java.util.concurrent.TimeUnit import kotlin.concurrent.thread +import kotlin.test.assertEquals import kotlin.test.assertFalse import kotlin.test.assertNotSame import kotlin.test.assertSame @@ -361,6 +365,45 @@ internal class CommonObjectPoolTest { } } + @Test + fun interleavedBorrowSchedulesEvictionIfCancelled() { + @Suppress("JoinDeclarationAndAssignment") + lateinit var pool: CommonObjectPool + val executor = object : ScheduledExecutorService by this@CommonObjectPoolTest.executor { + var count = 0 + + override fun scheduleAtFixedRate( + command: Runnable, + initialDelay: Long, + period: Long, + unit: TimeUnit + ) = this@CommonObjectPoolTest.executor.scheduleAtFixedRate(command, initialDelay, period, unit).also { + if (count++ == 0) { + it.cancel(false) + } + } + } + pool = CommonObjectPool(object : IObjectFactory { + private var count = 0 + + override fun close() = Unit + + override fun destroyObject(obj: PooledObject) = Unit + + override fun makeObject() = PooledObject().also { + if (count++ == 0) { + pool.borrowObject() + } + } + + override fun makePrimaryObject() = makeObject() + }, executor, configuration, mock()) + pool.use { + it.borrowObject() + assertEquals(2, executor.count) + } + } + @Test fun returnOnAnotherThread(): Unit = pool.run { borrowObject().let { @@ -418,6 +461,28 @@ internal class CommonObjectPoolTest { evictionThread.join() } + @Test + fun evictionFailsIfCancelled() { + val executor = object : ScheduledExecutorService by this@CommonObjectPoolTest.executor { + override fun scheduleAtFixedRate( + command: Runnable, + initialDelay: Long, + period: Long, + unit: TimeUnit + ) = this@CommonObjectPoolTest.executor.scheduleAtFixedRate(command, initialDelay, period, unit).also { + it.cancel(false) + } + } + CommonObjectPool(mock>().apply { + whenever(makeObject()) doAnswer Answer { PooledObject() } + }, executor, configuration, mock()).use { + val obj = it.borrowObject().apply { it.returnObject(this) } + it.evict() + it.evict() + assertSame(obj, it.borrowObject()) + } + } + @Test fun clearHighPriorityEvictsIdle(): Unit = pool.run { val obj = borrowObject().also { returnObject(it) } @@ -434,10 +499,19 @@ internal class CommonObjectPoolTest { assertSame(obj, borrowObject()) } + @Test + fun clearLowPriorityAfterEvictionAttemptClearsIdle(): Unit = pool.run { + val obj = borrowObject().also { returnObject(it) } + evict() + clear(Priority.LOW) + Thread.sleep(200L) + assertNotSame(obj, borrowObject()) + } + @Test fun clearLowPriorityReleasesMemoryFromEach() { val obj = mock() - SingleObjectPool(object : IObjectFactory { + CommonObjectPool(object : IObjectFactory { override fun close() = Unit override fun destroyObject(obj: PooledObject) = Unit @@ -445,13 +519,66 @@ internal class CommonObjectPoolTest { override fun makeObject() = obj override fun makePrimaryObject() = obj - }, executor, Long.MAX_VALUE, Long.MAX_VALUE).use { + }, executor, configuration, other).use { it.borrowObject().apply { it.returnObject(this) } it.clear(Priority.LOW) Thread.sleep(200L) verify(obj, times(1)).releaseMemory() } } + + @Test + fun factoryMakeObjectIOExceptionPropagates() { + CommonObjectPool(object : IObjectFactory { + override fun close() = Unit + + override fun destroyObject(obj: PooledObject) = Unit + + override fun makeObject() = throw IOException("Oh no!") + + override fun makePrimaryObject() = throw IOException("Oh no!") + }, executor, configuration, other).use { + assertThatExceptionOfType(IOException::class.java).isThrownBy { + it.borrowObject() + } + } + } + + @Test + fun factoryMakeObjectIOExceptionResetsCount() { + CommonObjectPool(object : IObjectFactory { + override fun close() = Unit + + override fun destroyObject(obj: PooledObject) = Unit + + override fun makeObject() = throw IOException("Oh no!") + + override fun makePrimaryObject() = throw IOException("Oh no!") + }, executor, configuration, other).use { + repeat(configuration.maxTotal + 1) { _ -> + runCatching { it.borrowObject() } + } + } + } + + @Test + fun factoryDestroyObjectIOExceptionPropagates() { + val obj = mock() + CommonObjectPool(object : IObjectFactory { + override fun close() = Unit + + override fun destroyObject(obj: PooledObject) = throw IOException("Oh no!") + + override fun makeObject() = obj + + override fun makePrimaryObject() = obj + }, executor, configuration, other).use { + it.borrowObject().apply { it.returnObject(this) } + assertThatExceptionOfType(IOException::class.java).isThrownBy { + it.evict(Priority.HIGH) + } + } + } } internal class CommonObjectPoolAsSingleObjectPoolTest { diff --git a/Lib/src/test/kotlin/com/bloomberg/selekt/pools/PoolsKtTest.kt b/Lib/src/test/kotlin/com/bloomberg/selekt/pools/PoolsKtTest.kt index 24e85fb454..aa8628a299 100644 --- a/Lib/src/test/kotlin/com/bloomberg/selekt/pools/PoolsKtTest.kt +++ b/Lib/src/test/kotlin/com/bloomberg/selekt/pools/PoolsKtTest.kt @@ -16,8 +16,8 @@ package com.bloomberg.selekt.pools -import com.nhaarman.mockitokotlin2.mock import org.junit.jupiter.api.Test +import org.mockito.kotlin.mock import java.util.concurrent.ScheduledExecutorService internal class PoolsKtTest { diff --git a/Lib/src/test/kotlin/com/bloomberg/selekt/pools/SingleObjectPoolTest.kt b/Lib/src/test/kotlin/com/bloomberg/selekt/pools/SingleObjectPoolTest.kt index 1ed7e17ce5..a61637be6e 100644 --- a/Lib/src/test/kotlin/com/bloomberg/selekt/pools/SingleObjectPoolTest.kt +++ b/Lib/src/test/kotlin/com/bloomberg/selekt/pools/SingleObjectPoolTest.kt @@ -16,15 +16,6 @@ package com.bloomberg.selekt.pools -import com.nhaarman.mockitokotlin2.any -import com.nhaarman.mockitokotlin2.doReturn -import com.nhaarman.mockitokotlin2.doThrow -import com.nhaarman.mockitokotlin2.mock -import com.nhaarman.mockitokotlin2.never -import com.nhaarman.mockitokotlin2.same -import com.nhaarman.mockitokotlin2.times -import com.nhaarman.mockitokotlin2.verify -import com.nhaarman.mockitokotlin2.whenever import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.launch @@ -36,8 +27,20 @@ import org.junit.Rule import org.junit.Test import org.junit.jupiter.api.assertDoesNotThrow import org.junit.rules.DisableOnDebug +import org.mockito.kotlin.any +import org.mockito.kotlin.doAnswer +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.doThrow +import org.mockito.kotlin.mock +import org.mockito.kotlin.never +import org.mockito.kotlin.same +import org.mockito.kotlin.times +import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever +import org.mockito.stubbing.Answer import java.io.IOException import java.util.concurrent.Executors +import java.util.concurrent.ScheduledExecutorService import java.util.concurrent.Semaphore import java.util.concurrent.TimeUnit import kotlin.concurrent.thread @@ -349,6 +352,28 @@ internal class SingleObjectPoolTest { } } + @Test + fun evictionFailsIfCancelled() { + val executor = object : ScheduledExecutorService by this@SingleObjectPoolTest.executor { + override fun scheduleAtFixedRate( + command: Runnable, + initialDelay: Long, + period: Long, + unit: TimeUnit + ) = this@SingleObjectPoolTest.executor.scheduleAtFixedRate(command, initialDelay, period, unit).also { + it.cancel(false) + } + } + SingleObjectPool(mock>().apply { + whenever(makePrimaryObject()) doAnswer Answer { PooledObject() } + }, executor, 1_000L, 20_000L).use { + val obj = it.borrowObject().apply { it.returnObject(this) } + it.evict() + it.evict() + assertSame(obj, it.borrowObject()) + } + } + @Test fun closeNotifiesAllWaiters(): Unit = pool.run { borrowObject() @@ -361,6 +386,28 @@ internal class SingleObjectPoolTest { } } + @Test + fun borrowAsClosingDoesNotScheduleEviction() { + @Suppress("JoinDeclarationAndAssignment") + lateinit var pool: SingleObjectPool + val executor = mock() + pool = SingleObjectPool(object : IObjectFactory { + override fun close() = Unit + + override fun destroyObject(obj: PooledObject) = Unit + + override fun makeObject() = PooledObject().also { + pool.close() + } + + override fun makePrimaryObject() = makeObject() + }, executor, 1_000L, 20_000L) + pool.use { + it.borrowObject() + verify(executor, never()).scheduleAtFixedRate(any(), any(), any(), any()) + } + } + @Test fun interruptBorrowerThenReturn(): Unit = pool.run { borrowObject().let { @@ -427,6 +474,15 @@ internal class SingleObjectPoolTest { assertSame(obj, borrowObject()) } + @Test + fun clearLowPriorityAfterEvictionAttemptClearsIdle(): Unit = pool.run { + val obj = borrowObject().also { returnObject(it) } + evict() + clear(Priority.LOW) + Thread.sleep(200L) + assertNotSame(obj, borrowObject()) + } + @Test fun clearLowPriorityReleasesMemoryFromEach() { val obj = mock() @@ -445,4 +501,30 @@ internal class SingleObjectPoolTest { verify(obj, times(1)).releaseMemory() } } + + @Test + fun evictLowPriorityWhenEmptyDoesNotThrow(): Unit = pool.run { + assertDoesNotThrow { + evict(Priority.LOW) + } + } + + @Test + fun factoryDestroyObjectIOExceptionPropagates() { + val obj = mock() + SingleObjectPool(object : IObjectFactory { + override fun close() = Unit + + override fun destroyObject(obj: PooledObject) = throw IOException("Oh no!") + + override fun makeObject() = obj + + override fun makePrimaryObject() = obj + }, executor, Long.MAX_VALUE, Long.MAX_VALUE).use { + it.borrowObject().apply { it.returnObject(this) } + assertThatExceptionOfType(IOException::class.java).isThrownBy { + it.evict(Priority.HIGH) + } + } + } } diff --git a/Lib/src/test/kotlin/com/bloomberg/selekt/pools/TieredObjectPoolTest.kt b/Lib/src/test/kotlin/com/bloomberg/selekt/pools/TieredObjectPoolTest.kt index 70a8e619cb..e6eda2e416 100644 --- a/Lib/src/test/kotlin/com/bloomberg/selekt/pools/TieredObjectPoolTest.kt +++ b/Lib/src/test/kotlin/com/bloomberg/selekt/pools/TieredObjectPoolTest.kt @@ -16,17 +16,17 @@ package com.bloomberg.selekt.pools -import com.nhaarman.mockitokotlin2.doReturn -import com.nhaarman.mockitokotlin2.mock -import com.nhaarman.mockitokotlin2.same -import com.nhaarman.mockitokotlin2.times -import com.nhaarman.mockitokotlin2.verify -import com.nhaarman.mockitokotlin2.verifyZeroInteractions -import com.nhaarman.mockitokotlin2.whenever import org.junit.Rule import org.junit.Test import org.junit.rules.DisableOnDebug import org.junit.rules.Timeout +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.mock +import org.mockito.kotlin.same +import org.mockito.kotlin.times +import org.mockito.kotlin.verify +import org.mockito.kotlin.verifyZeroInteractions +import org.mockito.kotlin.whenever import java.util.concurrent.TimeUnit internal class TieredObjectPoolTest { @@ -85,4 +85,12 @@ internal class TieredObjectPoolTest { verify(commonObjectPool, times(1)).returnObject(same(obj)) verifyZeroInteractions(singleObjectPool) } + + @Test + fun clearsAllPools() { + val priority = Priority.HIGH + pool.clear(priority) + verify(singleObjectPool, times(1)).clear(same(priority)) + verify(commonObjectPool, times(1)).clear(same(priority)) + } } diff --git a/build.gradle.kts b/build.gradle.kts index dd29d3e78c..99847f4d49 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -230,12 +230,12 @@ tasks.register("jacocoSelektCoverageVerification") { limit { counter = "LINE" value = "COVEREDRATIO" - minimum = "0.9684".toBigDecimal() // Does not include inlined blocks. Jacoco can't yet cover these. + minimum = "0.9761".toBigDecimal() // Does not include inlined blocks. Jacoco can't yet cover these. } limit { counter = "BRANCH" value = "COVEREDRATIO" - minimum = "0.9041".toBigDecimal() // Does not include inlined blocks. Jacoco can't yet cover these. + minimum = "0.9326".toBigDecimal() // Does not include inlined blocks. Jacoco can't yet cover these. } } } diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 34432dddd2..67bb9a8ccc 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -47,5 +47,5 @@ dependencies { compileOnly(gradleApi()) implementation(kotlin("stdlib-jdk8", version = kotlinVersion)) implementation(kotlin("gradle-plugin", version = kotlinVersion)) - implementation("com.android.tools.build:gradle:4.2.0") + implementation("com.android.tools.build:gradle:4.2.1") } diff --git a/buildSrc/src/main/kotlin/SelektPlugin.kt b/buildSrc/src/main/kotlin/SelektPlugin.kt index 51cd582d28..2fbaa71a3b 100644 --- a/buildSrc/src/main/kotlin/SelektPlugin.kt +++ b/buildSrc/src/main/kotlin/SelektPlugin.kt @@ -69,7 +69,7 @@ class SelektPlugin : Plugin { configurations.getByName("androidTestImplementation") { add(name, kotlin("test", Versions.KOTLIN.version)) add(name, kotlin("test-junit", Versions.KOTLIN.version)) - add(name, "com.nhaarman.mockitokotlin2:mockito-kotlin:${Versions.MOCKITO_KOTLIN}") + add(name, "org.mockito.kotlin:mockito-kotlin:${Versions.MOCKITO_KOTLIN}") } } androidExtension().apply { @@ -105,8 +105,8 @@ class SelektPlugin : Plugin { add(name, kotlinX("coroutines-core", Versions.KOTLIN_COROUTINES.version)) add(name, kotlinX("coroutines-jdk8", Versions.KOTLIN_COROUTINES.version)) add(name, "org.assertj:assertj-core:${Versions.ASSERT_J}") - add(name, "org.mockito:mockito-core:${Versions.MOCKITO_CORE}") - add(name, "com.nhaarman.mockitokotlin2:mockito-kotlin:${Versions.MOCKITO_KOTLIN}") + add(name, "org.mockito:mockito-core:${Versions.MOCKITO}") + add(name, "org.mockito.kotlin:mockito-kotlin:${Versions.MOCKITO_KOTLIN}") } } } diff --git a/buildSrc/src/main/kotlin/Versions.kt b/buildSrc/src/main/kotlin/Versions.kt index 263574f762..7321969e7a 100644 --- a/buildSrc/src/main/kotlin/Versions.kt +++ b/buildSrc/src/main/kotlin/Versions.kt @@ -21,7 +21,7 @@ enum class Versions( private val url: URL ) { ANDROID_BUILD_TOOLS("30.0.3", URL("https://developer.android.com/studio/releases/build-tools")), - ANDROID_GRADLE_PLUGIN("4.2.0", URL("https://developer.android.com/tools/revisions/gradle-plugin.html")), + ANDROID_GRADLE_PLUGIN("4.2.1", URL("https://developer.android.com/tools/revisions/gradle-plugin.html")), ANDROID_LINT("30.0.0-alpha07", URL("https://github.com/googlesamples/android-custom-lint-rules")), ANDROID_SDK("30", URL("https://developer.android.com/sdk")), ANDROIDX_LIVE_DATA("2.2.0", URL("https://developer.android.com/topic/libraries/architecture/livedata")), @@ -33,7 +33,7 @@ enum class Versions( DOKKA("1.4.10.2", URL("https://github.com/Kotlin/dokka")), ESPRESSO_CORE("3.1.1", URL("https://android.googlesource.com/platform/frameworks/testing/+/android-support-test/espresso")), - JACOCO("0.8.6", URL("https://www.jacoco.org/jacoco/trunk/doc/changes.html")), + JACOCO("0.8.7", URL("https://www.jacoco.org/jacoco/trunk/doc/changes.html")), JSR_305("3.0.2", URL("https://code.google.com/archive/p/jsr-305/")), JUNIT4("4.13.1", URL("https://github.com/junit-team/junit4")), JUNIT5("5.7.0", URL("https://junit.org/junit5/")), @@ -41,9 +41,8 @@ enum class Versions( KOTLIN("1.4.32", URL("https://github.com/JetBrains/kotlin")), KOTLIN_COROUTINES("1.4.3", URL("https://github.com/Kotlin/kotlinx.coroutines")), KTLINT("0.35.0", URL("https://github.com/pinterest/ktlint")), - MOCKITO_ANDROID("3.0.0", URL("https://github.com/mockito/mockito")), - MOCKITO_CORE("3.0.0", URL("https://github.com/mockito/mockito")), - MOCKITO_KOTLIN("2.1.0", URL("https://github.com/nhaarman/mockito-kotlin")), + MOCKITO("3.9.0", URL("https://github.com/mockito/mockito")), + MOCKITO_KOTLIN("3.2.0", URL("https://github.com/nhaarman/mockito-kotlin")), NEXUS_PLUGIN("1.0.0", URL("https://github.com/gradle-nexus/publish-plugin")), ROBOLECTRIC("4.5.1", URL("https://github.com/robolectric/robolectric")); diff --git a/gradle.properties b/gradle.properties index 92dae808db..f6fc4ad681 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -selekt.versionName=0.12.7 +selekt.versionName=0.13.0 openssl.version=1.1.1 openssl.version.suffix=d diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 1bd5be8709..297f2fec36 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-all.zip