From ab81ee9849e01da0ecceccce5416e4b983cae7ca Mon Sep 17 00:00:00 2001 From: Grzegorz Orczykowski Date: Tue, 29 Oct 2024 11:55:50 +0100 Subject: [PATCH 1/8] Changed var to val --- .../org/odk/collect/android/formmanagement/FormsDataService.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/collect_app/src/main/java/org/odk/collect/android/formmanagement/FormsDataService.kt b/collect_app/src/main/java/org/odk/collect/android/formmanagement/FormsDataService.kt index 4c2f982e5f1..6e909fe53c4 100644 --- a/collect_app/src/main/java/org/odk/collect/android/formmanagement/FormsDataService.kt +++ b/collect_app/src/main/java/org/odk/collect/android/formmanagement/FormsDataService.kt @@ -58,7 +58,7 @@ class FormsDataService( progressReporter: (Int, Int) -> Unit, isCancelled: () -> Boolean ): Map { - var results = mutableMapOf() + val results = mutableMapOf() val projectDependencyModule = projectDependencyModuleFactory.create(projectId) projectDependencyModule.formsLock.withLock { acquiredLock -> From a1b0cb8158ef76bba1e0c00274b3914255ca08b2 Mon Sep 17 00:00:00 2001 From: Grzegorz Orczykowski Date: Tue, 29 Oct 2024 11:57:01 +0100 Subject: [PATCH 2/8] Revert "Keep ChangeLock inteface and its only implementation in one file" This reverts commit 6cceed30adf60860dd5b9f8db44375b5a2f6b20b. --- .../odk/collect/shared/locks/ChangeLock.kt | 33 ----------------- .../locks/ThreadSafeBooleanChangeLock.kt | 36 +++++++++++++++++++ 2 files changed, 36 insertions(+), 33 deletions(-) create mode 100644 shared/src/main/java/org/odk/collect/shared/locks/ThreadSafeBooleanChangeLock.kt diff --git a/shared/src/main/java/org/odk/collect/shared/locks/ChangeLock.kt b/shared/src/main/java/org/odk/collect/shared/locks/ChangeLock.kt index 5fe800085c6..c2c806f6f76 100644 --- a/shared/src/main/java/org/odk/collect/shared/locks/ChangeLock.kt +++ b/shared/src/main/java/org/odk/collect/shared/locks/ChangeLock.kt @@ -14,36 +14,3 @@ interface ChangeLock { fun unlock() } - -class ThreadSafeBooleanChangeLock : ChangeLock { - private var locked = false - - override fun withLock(function: Function): T { - val acquired = tryLock() - - return try { - function.apply(acquired) - } finally { - if (acquired) { - unlock() - } - } - } - - override fun tryLock(): Boolean { - return synchronized(this) { - if (locked) { - false - } else { - locked = true - true - } - } - } - - override fun unlock() { - synchronized(this) { - locked = false - } - } -} diff --git a/shared/src/main/java/org/odk/collect/shared/locks/ThreadSafeBooleanChangeLock.kt b/shared/src/main/java/org/odk/collect/shared/locks/ThreadSafeBooleanChangeLock.kt new file mode 100644 index 00000000000..3ba1a628f1b --- /dev/null +++ b/shared/src/main/java/org/odk/collect/shared/locks/ThreadSafeBooleanChangeLock.kt @@ -0,0 +1,36 @@ +package org.odk.collect.shared.locks + +import java.util.function.Function + +class ThreadSafeBooleanChangeLock : ChangeLock { + private var locked = false + + override fun withLock(function: Function): T { + val acquired = tryLock() + + return try { + function.apply(acquired) + } finally { + if (acquired) { + unlock() + } + } + } + + override fun tryLock(): Boolean { + return synchronized(this) { + if (locked) { + false + } else { + locked = true + true + } + } + } + + override fun unlock() { + synchronized(this) { + locked = false + } + } +} From 94ed012f9fd43d01dd3501200940ea9ae4025a53 Mon Sep 17 00:00:00 2001 From: Grzegorz Orczykowski Date: Tue, 29 Oct 2024 11:58:02 +0100 Subject: [PATCH 3/8] Revert "Removed redundant BooleanChangeLock" This reverts commit 1bd04b29d870f8758b6aace05d60ec1b8adba56e. --- .../android/external/FormUriActivityTest.kt | 4 +-- .../formentry/FormEntryViewModelTest.java | 4 +-- .../BlankFormListViewModelTest.kt | 4 +-- .../formmanagement/FormsDataServiceTest.kt | 12 +++---- .../InstancesDataServiceTest.kt | 6 ++-- .../android/projects/ProjectDeleterTest.kt | 10 +++--- .../android/projects/ProjectResetterTest.kt | 6 ++-- .../collect/testshared/BooleanChangeLock.kt | 33 +++++++++++++++++++ 8 files changed, 56 insertions(+), 23 deletions(-) create mode 100644 test-shared/src/main/java/org/odk/collect/testshared/BooleanChangeLock.kt diff --git a/collect_app/src/test/java/org/odk/collect/android/external/FormUriActivityTest.kt b/collect_app/src/test/java/org/odk/collect/android/external/FormUriActivityTest.kt index 993a008946b..f1b19cd717f 100644 --- a/collect_app/src/test/java/org/odk/collect/android/external/FormUriActivityTest.kt +++ b/collect_app/src/test/java/org/odk/collect/android/external/FormUriActivityTest.kt @@ -62,8 +62,8 @@ import org.odk.collect.settings.InMemSettingsProvider import org.odk.collect.settings.SettingsProvider import org.odk.collect.settings.keys.ProtectedProjectKeys import org.odk.collect.shared.TempFiles -import org.odk.collect.shared.locks.ThreadSafeBooleanChangeLock import org.odk.collect.shared.strings.UUIDGenerator +import org.odk.collect.testshared.BooleanChangeLock import org.odk.collect.testshared.FakeScheduler import java.io.File import java.text.SimpleDateFormat @@ -85,7 +85,7 @@ class FormUriActivityTest { private val savepointsRepositoryProvider = mock().apply { whenever(create()).thenReturn(savepointsRepository) } - private val changeLock = ThreadSafeBooleanChangeLock() + private val changeLock = BooleanChangeLock() private val changeLockProvider = ChangeLockProvider { changeLock } @get:Rule diff --git a/collect_app/src/test/java/org/odk/collect/android/formentry/FormEntryViewModelTest.java b/collect_app/src/test/java/org/odk/collect/android/formentry/FormEntryViewModelTest.java index 12e681e12ab..b31ea2c95a9 100644 --- a/collect_app/src/test/java/org/odk/collect/android/formentry/FormEntryViewModelTest.java +++ b/collect_app/src/test/java/org/odk/collect/android/formentry/FormEntryViewModelTest.java @@ -36,7 +36,7 @@ import org.odk.collect.androidshared.data.Consumable; import org.odk.collect.forms.FormsRepository; import org.odk.collect.formstest.InMemFormsRepository; -import org.odk.collect.shared.locks.ThreadSafeBooleanChangeLock; +import org.odk.collect.testshared.BooleanChangeLock; import org.odk.collect.testshared.FakeScheduler; import java.io.FileNotFoundException; @@ -54,7 +54,7 @@ public class FormEntryViewModelTest { private FakeScheduler scheduler; private final FormSessionRepository formSessionRepository = new InMemFormSessionRepository(); private final FormsRepository formsRepository = new InMemFormsRepository(); - private final ChangeLocks changeLocks = new ChangeLocks(new ThreadSafeBooleanChangeLock(), new ThreadSafeBooleanChangeLock()); + private final ChangeLocks changeLocks = new ChangeLocks(new BooleanChangeLock(), new BooleanChangeLock()); @Rule public InstantTaskExecutorRule instantTaskExecutorRule = new InstantTaskExecutorRule(); diff --git a/collect_app/src/test/java/org/odk/collect/android/formlists/blankformlist/BlankFormListViewModelTest.kt b/collect_app/src/test/java/org/odk/collect/android/formlists/blankformlist/BlankFormListViewModelTest.kt index fa6483b3ef6..b58ce8638cc 100644 --- a/collect_app/src/test/java/org/odk/collect/android/formlists/blankformlist/BlankFormListViewModelTest.kt +++ b/collect_app/src/test/java/org/odk/collect/android/formlists/blankformlist/BlankFormListViewModelTest.kt @@ -25,8 +25,8 @@ import org.odk.collect.formstest.FormUtils import org.odk.collect.formstest.InMemInstancesRepository import org.odk.collect.settings.enums.FormUpdateMode import org.odk.collect.settings.keys.ProjectKeys -import org.odk.collect.shared.locks.ThreadSafeBooleanChangeLock import org.odk.collect.shared.settings.InMemSettings +import org.odk.collect.testshared.BooleanChangeLock import org.odk.collect.testshared.FakeScheduler import org.odk.collect.testshared.getOrAwaitValue @@ -47,7 +47,7 @@ class BlankFormListViewModelTest { private val changeLockProvider: ChangeLockProvider = mock() private val projectId = "projectId" - private val changeLock = ThreadSafeBooleanChangeLock() + private val changeLock = BooleanChangeLock() private lateinit var viewModel: BlankFormListViewModel @Test diff --git a/collect_app/src/test/java/org/odk/collect/android/formmanagement/FormsDataServiceTest.kt b/collect_app/src/test/java/org/odk/collect/android/formmanagement/FormsDataServiceTest.kt index bd5c2b83a79..78da28b159a 100644 --- a/collect_app/src/test/java/org/odk/collect/android/formmanagement/FormsDataServiceTest.kt +++ b/collect_app/src/test/java/org/odk/collect/android/formmanagement/FormsDataServiceTest.kt @@ -32,8 +32,8 @@ import org.odk.collect.forms.FormSourceException import org.odk.collect.formstest.FormUtils import org.odk.collect.projects.Project import org.odk.collect.settings.keys.ProjectKeys -import org.odk.collect.shared.locks.ThreadSafeBooleanChangeLock import org.odk.collect.shared.strings.Md5.getMd5Hash +import org.odk.collect.testshared.BooleanChangeLock @RunWith(AndroidJUnit4::class) class FormsDataServiceTest { @@ -50,7 +50,7 @@ class FormsDataServiceTest { private val notifier = mock() private val analytics = mock() - private val changeLockProvider = ChangeLockProvider { ThreadSafeBooleanChangeLock() } + private val changeLockProvider = ChangeLockProvider { BooleanChangeLock() } private val formSource = mock { on { fetchFormList() } doReturn emptyList() @@ -113,7 +113,7 @@ class FormsDataServiceTest { fun `downloadUpdates() does nothing when change lock is locked`() { val isSyncing = formsDataService.isSyncing(project.uuid) - val changeLock = changeLockProvider.create(project.uuid).formsLock as ThreadSafeBooleanChangeLock + val changeLock = changeLockProvider.create(project.uuid).formsLock as BooleanChangeLock changeLock.tryLock() isSyncing.recordValues { projectValues -> @@ -130,7 +130,7 @@ class FormsDataServiceTest { fun `matchFormsWithServer() does nothing when change lock is locked`() { val isSyncing = formsDataService.isSyncing(project.uuid) - val changeLock = changeLockProvider.create(project.uuid).formsLock as ThreadSafeBooleanChangeLock + val changeLock = changeLockProvider.create(project.uuid).formsLock as BooleanChangeLock changeLock.tryLock() isSyncing.recordValues { projectValues -> @@ -149,7 +149,7 @@ class FormsDataServiceTest { */ @Test fun `matchFormsWithServer() returns false when change lock is locked`() { - val changeLock = changeLockProvider.create(project.uuid).formsLock as ThreadSafeBooleanChangeLock + val changeLock = changeLockProvider.create(project.uuid).formsLock as BooleanChangeLock changeLock.tryLock() assertThat(formsDataService.matchFormsWithServer(project.uuid), equalTo(false)) @@ -224,7 +224,7 @@ class FormsDataServiceTest { fun `update() does nothing when change lock is locked`() { val isSyncing = formsDataService.isSyncing(project.uuid) - val changeLock = changeLockProvider.create(project.uuid).formsLock as ThreadSafeBooleanChangeLock + val changeLock = changeLockProvider.create(project.uuid).formsLock as BooleanChangeLock changeLock.tryLock() isSyncing.recordValues { projectValues -> diff --git a/collect_app/src/test/java/org/odk/collect/android/instancemanagement/InstancesDataServiceTest.kt b/collect_app/src/test/java/org/odk/collect/android/instancemanagement/InstancesDataServiceTest.kt index 7b3c4e9ba05..b388e8f0efa 100644 --- a/collect_app/src/test/java/org/odk/collect/android/instancemanagement/InstancesDataServiceTest.kt +++ b/collect_app/src/test/java/org/odk/collect/android/instancemanagement/InstancesDataServiceTest.kt @@ -28,8 +28,8 @@ import org.odk.collect.formstest.InMemInstancesRepository import org.odk.collect.formstest.InstanceFixtures import org.odk.collect.projects.ProjectDependencyFactory import org.odk.collect.settings.keys.ProjectKeys -import org.odk.collect.shared.locks.ThreadSafeBooleanChangeLock import org.odk.collect.shared.settings.InMemSettings +import org.odk.collect.testshared.BooleanChangeLock import java.io.File @RunWith(AndroidJUnit4::class) @@ -39,7 +39,7 @@ class InstancesDataServiceTest { it.save(ProjectKeys.KEY_SERVER_URL, "http://example.com") } - private val changeLocks = ChangeLocks(ThreadSafeBooleanChangeLock(), ThreadSafeBooleanChangeLock()) + private val changeLocks = ChangeLocks(BooleanChangeLock(), BooleanChangeLock()) private val formsRepository = InMemFormsRepository() private val instancesRepository = InMemInstancesRepository() @@ -74,7 +74,7 @@ class InstancesDataServiceTest { @Test fun `instances should not be deleted if the instances database is locked`() { - (projectDependencyModule.instancesLock as ThreadSafeBooleanChangeLock).tryLock() + (projectDependencyModule.instancesLock as BooleanChangeLock).tryLock() val result = instancesDataService.deleteInstances("projectId", longArrayOf(1)) assertThat(result, equalTo(false)) } diff --git a/collect_app/src/test/java/org/odk/collect/android/projects/ProjectDeleterTest.kt b/collect_app/src/test/java/org/odk/collect/android/projects/ProjectDeleterTest.kt index 9963b99d674..7183310f7b4 100644 --- a/collect_app/src/test/java/org/odk/collect/android/projects/ProjectDeleterTest.kt +++ b/collect_app/src/test/java/org/odk/collect/android/projects/ProjectDeleterTest.kt @@ -24,7 +24,7 @@ import org.odk.collect.settings.keys.MetaKeys import org.odk.collect.settings.keys.ProjectKeys import org.odk.collect.settings.keys.ProtectedProjectKeys import org.odk.collect.shared.TempFiles -import org.odk.collect.shared.locks.ThreadSafeBooleanChangeLock +import org.odk.collect.testshared.BooleanChangeLock import java.io.File class ProjectDeleterTest { @@ -44,8 +44,8 @@ class ProjectDeleterTest { whenever(getProjectRootDirPath(project1.uuid)).thenReturn("") } private val changeLockProvider = mock { - on { getFormLock(any()) } doReturn ThreadSafeBooleanChangeLock() - on { getInstanceLock(any()) } doReturn ThreadSafeBooleanChangeLock() + on { getFormLock(any()) } doReturn BooleanChangeLock() + on { getInstanceLock(any()) } doReturn BooleanChangeLock() } private val deleter = ProjectDeleter( projectsRepository, @@ -152,7 +152,7 @@ class ProjectDeleterTest { @Test fun `If there are running background jobs that use blank forms the project should not be deleted`() { - val formChangeLock = ThreadSafeBooleanChangeLock().apply { + val formChangeLock = BooleanChangeLock().apply { tryLock() } whenever(changeLockProvider.getFormLock(any())).thenReturn(formChangeLock) @@ -165,7 +165,7 @@ class ProjectDeleterTest { @Test fun `If there are running background jobs that use saved forms the project should not be deleted`() { - val changeLock = ThreadSafeBooleanChangeLock().apply { + val changeLock = BooleanChangeLock().apply { tryLock() } whenever(changeLockProvider.getInstanceLock(any())).thenReturn(changeLock) diff --git a/collect_app/src/test/java/org/odk/collect/android/projects/ProjectResetterTest.kt b/collect_app/src/test/java/org/odk/collect/android/projects/ProjectResetterTest.kt index 32e6b10c76d..527fdba9015 100644 --- a/collect_app/src/test/java/org/odk/collect/android/projects/ProjectResetterTest.kt +++ b/collect_app/src/test/java/org/odk/collect/android/projects/ProjectResetterTest.kt @@ -33,8 +33,8 @@ import org.odk.collect.projects.Project import org.odk.collect.settings.SettingsProvider import org.odk.collect.settings.keys.ProjectKeys import org.odk.collect.settings.keys.ProtectedProjectKeys -import org.odk.collect.shared.locks.ThreadSafeBooleanChangeLock import org.odk.collect.shared.settings.Settings +import org.odk.collect.testshared.BooleanChangeLock import java.io.File @RunWith(AndroidJUnit4::class) @@ -49,7 +49,7 @@ class ProjectResetterTest { private lateinit var anotherProjectId: String private val propertyManager = mock() - private val changeLockProvider = ChangeLockProvider { ThreadSafeBooleanChangeLock() } + private val changeLockProvider = ChangeLockProvider { BooleanChangeLock() } @Before fun setup() { @@ -202,7 +202,7 @@ class ProjectResetterTest { saveTestInstanceFiles(currentProjectId) setupTestInstancesDatabase(currentProjectId) - (changeLockProvider.create(currentProjectId).instancesLock as ThreadSafeBooleanChangeLock).tryLock() + (changeLockProvider.create(currentProjectId).instancesLock as BooleanChangeLock).tryLock() val failedResetActions = projectResetter.reset(listOf(ProjectResetter.ResetAction.RESET_INSTANCES)) assertEquals(1, failedResetActions.size) diff --git a/test-shared/src/main/java/org/odk/collect/testshared/BooleanChangeLock.kt b/test-shared/src/main/java/org/odk/collect/testshared/BooleanChangeLock.kt new file mode 100644 index 00000000000..b6fad2a46c6 --- /dev/null +++ b/test-shared/src/main/java/org/odk/collect/testshared/BooleanChangeLock.kt @@ -0,0 +1,33 @@ +package org.odk.collect.testshared + +import org.odk.collect.shared.locks.ChangeLock +import java.util.function.Function + +class BooleanChangeLock : ChangeLock { + private var locked = false + + override fun withLock(function: Function): T { + val acquired = tryLock() + + return try { + function.apply(acquired) + } finally { + if (acquired) { + unlock() + } + } + } + + override fun tryLock(): Boolean { + if (locked) { + return false + } else { + locked = true + return true + } + } + + override fun unlock() { + locked = false + } +} From f7b5c3eefae0f3d1f968583efdc92d2b81234ef1 Mon Sep 17 00:00:00 2001 From: Grzegorz Orczykowski Date: Tue, 29 Oct 2024 12:08:14 +0100 Subject: [PATCH 4/8] Removed redundant casts --- .../android/formmanagement/FormsDataServiceTest.kt | 8 ++++---- .../instancemanagement/InstancesDataServiceTest.kt | 2 +- .../odk/collect/android/projects/ProjectResetterTest.kt | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/collect_app/src/test/java/org/odk/collect/android/formmanagement/FormsDataServiceTest.kt b/collect_app/src/test/java/org/odk/collect/android/formmanagement/FormsDataServiceTest.kt index 78da28b159a..c8fab5a388e 100644 --- a/collect_app/src/test/java/org/odk/collect/android/formmanagement/FormsDataServiceTest.kt +++ b/collect_app/src/test/java/org/odk/collect/android/formmanagement/FormsDataServiceTest.kt @@ -113,7 +113,7 @@ class FormsDataServiceTest { fun `downloadUpdates() does nothing when change lock is locked`() { val isSyncing = formsDataService.isSyncing(project.uuid) - val changeLock = changeLockProvider.create(project.uuid).formsLock as BooleanChangeLock + val changeLock = changeLockProvider.create(project.uuid).formsLock changeLock.tryLock() isSyncing.recordValues { projectValues -> @@ -130,7 +130,7 @@ class FormsDataServiceTest { fun `matchFormsWithServer() does nothing when change lock is locked`() { val isSyncing = formsDataService.isSyncing(project.uuid) - val changeLock = changeLockProvider.create(project.uuid).formsLock as BooleanChangeLock + val changeLock = changeLockProvider.create(project.uuid).formsLock changeLock.tryLock() isSyncing.recordValues { projectValues -> @@ -149,7 +149,7 @@ class FormsDataServiceTest { */ @Test fun `matchFormsWithServer() returns false when change lock is locked`() { - val changeLock = changeLockProvider.create(project.uuid).formsLock as BooleanChangeLock + val changeLock = changeLockProvider.create(project.uuid).formsLock changeLock.tryLock() assertThat(formsDataService.matchFormsWithServer(project.uuid), equalTo(false)) @@ -224,7 +224,7 @@ class FormsDataServiceTest { fun `update() does nothing when change lock is locked`() { val isSyncing = formsDataService.isSyncing(project.uuid) - val changeLock = changeLockProvider.create(project.uuid).formsLock as BooleanChangeLock + val changeLock = changeLockProvider.create(project.uuid).formsLock changeLock.tryLock() isSyncing.recordValues { projectValues -> diff --git a/collect_app/src/test/java/org/odk/collect/android/instancemanagement/InstancesDataServiceTest.kt b/collect_app/src/test/java/org/odk/collect/android/instancemanagement/InstancesDataServiceTest.kt index b388e8f0efa..7dc5035af4f 100644 --- a/collect_app/src/test/java/org/odk/collect/android/instancemanagement/InstancesDataServiceTest.kt +++ b/collect_app/src/test/java/org/odk/collect/android/instancemanagement/InstancesDataServiceTest.kt @@ -74,7 +74,7 @@ class InstancesDataServiceTest { @Test fun `instances should not be deleted if the instances database is locked`() { - (projectDependencyModule.instancesLock as BooleanChangeLock).tryLock() + projectDependencyModule.instancesLock.tryLock() val result = instancesDataService.deleteInstances("projectId", longArrayOf(1)) assertThat(result, equalTo(false)) } diff --git a/collect_app/src/test/java/org/odk/collect/android/projects/ProjectResetterTest.kt b/collect_app/src/test/java/org/odk/collect/android/projects/ProjectResetterTest.kt index 527fdba9015..567d8b3f86a 100644 --- a/collect_app/src/test/java/org/odk/collect/android/projects/ProjectResetterTest.kt +++ b/collect_app/src/test/java/org/odk/collect/android/projects/ProjectResetterTest.kt @@ -202,7 +202,7 @@ class ProjectResetterTest { saveTestInstanceFiles(currentProjectId) setupTestInstancesDatabase(currentProjectId) - (changeLockProvider.create(currentProjectId).instancesLock as BooleanChangeLock).tryLock() + changeLockProvider.create(currentProjectId).instancesLock.tryLock() val failedResetActions = projectResetter.reset(listOf(ProjectResetter.ResetAction.RESET_INSTANCES)) assertEquals(1, failedResetActions.size) From 00108f9088edc594c8878fbb05a3f18ef71cc3f9 Mon Sep 17 00:00:00 2001 From: Grzegorz Orczykowski Date: Tue, 29 Oct 2024 12:31:39 +0100 Subject: [PATCH 5/8] Add #lock method for easier testing --- .../odk/collect/android/external/FormUriActivityTest.kt | 8 ++++---- .../android/formmanagement/FormsDataServiceTest.kt | 8 ++++---- .../instancemanagement/InstancesDataServiceTest.kt | 2 +- .../odk/collect/android/projects/ProjectDeleterTest.kt | 4 ++-- .../odk/collect/android/projects/ProjectResetterTest.kt | 2 +- .../main/java/org/odk/collect/shared/locks/ChangeLock.kt | 2 ++ .../collect/shared/locks/ThreadSafeBooleanChangeLock.kt | 8 ++++++++ .../java/org/odk/collect/testshared/BooleanChangeLock.kt | 8 ++++++++ 8 files changed, 30 insertions(+), 12 deletions(-) diff --git a/collect_app/src/test/java/org/odk/collect/android/external/FormUriActivityTest.kt b/collect_app/src/test/java/org/odk/collect/android/external/FormUriActivityTest.kt index f1b19cd717f..fe579e73de1 100644 --- a/collect_app/src/test/java/org/odk/collect/android/external/FormUriActivityTest.kt +++ b/collect_app/src/test/java/org/odk/collect/android/external/FormUriActivityTest.kt @@ -1052,7 +1052,7 @@ class FormUriActivityTest { ).build() ) - changeLock.tryLock() + changeLock.lock() launcherRule.launchForResult(getBlankFormIntent(project.uuid, form.dbId)) fakeScheduler.flush() @@ -1074,7 +1074,7 @@ class FormUriActivityTest { ).build() ) - changeLock.tryLock() + changeLock.lock() val scenario = launcherRule.launchForResult(getBlankFormIntent(project.uuid, form.dbId)) fakeScheduler.flush() @@ -1103,7 +1103,7 @@ class FormUriActivityTest { .build() ) - changeLock.tryLock() + changeLock.lock() launcherRule.launchForResult(getSavedIntent(project.uuid, instance.dbId)) fakeScheduler.flush() @@ -1134,7 +1134,7 @@ class FormUriActivityTest { .build() ) - changeLock.tryLock() + changeLock.lock() val scenario = launcherRule.launchForResult(getSavedIntent(project.uuid, instance.dbId)) fakeScheduler.flush() diff --git a/collect_app/src/test/java/org/odk/collect/android/formmanagement/FormsDataServiceTest.kt b/collect_app/src/test/java/org/odk/collect/android/formmanagement/FormsDataServiceTest.kt index c8fab5a388e..a0956e1d8d2 100644 --- a/collect_app/src/test/java/org/odk/collect/android/formmanagement/FormsDataServiceTest.kt +++ b/collect_app/src/test/java/org/odk/collect/android/formmanagement/FormsDataServiceTest.kt @@ -114,7 +114,7 @@ class FormsDataServiceTest { val isSyncing = formsDataService.isSyncing(project.uuid) val changeLock = changeLockProvider.create(project.uuid).formsLock - changeLock.tryLock() + changeLock.lock() isSyncing.recordValues { projectValues -> formsDataService.downloadUpdates(project.uuid) @@ -131,7 +131,7 @@ class FormsDataServiceTest { val isSyncing = formsDataService.isSyncing(project.uuid) val changeLock = changeLockProvider.create(project.uuid).formsLock - changeLock.tryLock() + changeLock.lock() isSyncing.recordValues { projectValues -> formsDataService.matchFormsWithServer(project.uuid) @@ -150,7 +150,7 @@ class FormsDataServiceTest { @Test fun `matchFormsWithServer() returns false when change lock is locked`() { val changeLock = changeLockProvider.create(project.uuid).formsLock - changeLock.tryLock() + changeLock.lock() assertThat(formsDataService.matchFormsWithServer(project.uuid), equalTo(false)) } @@ -225,7 +225,7 @@ class FormsDataServiceTest { val isSyncing = formsDataService.isSyncing(project.uuid) val changeLock = changeLockProvider.create(project.uuid).formsLock - changeLock.tryLock() + changeLock.lock() isSyncing.recordValues { projectValues -> formsDataService.update(project.uuid) diff --git a/collect_app/src/test/java/org/odk/collect/android/instancemanagement/InstancesDataServiceTest.kt b/collect_app/src/test/java/org/odk/collect/android/instancemanagement/InstancesDataServiceTest.kt index 7dc5035af4f..d151d05498b 100644 --- a/collect_app/src/test/java/org/odk/collect/android/instancemanagement/InstancesDataServiceTest.kt +++ b/collect_app/src/test/java/org/odk/collect/android/instancemanagement/InstancesDataServiceTest.kt @@ -74,7 +74,7 @@ class InstancesDataServiceTest { @Test fun `instances should not be deleted if the instances database is locked`() { - projectDependencyModule.instancesLock.tryLock() + projectDependencyModule.instancesLock.lock() val result = instancesDataService.deleteInstances("projectId", longArrayOf(1)) assertThat(result, equalTo(false)) } diff --git a/collect_app/src/test/java/org/odk/collect/android/projects/ProjectDeleterTest.kt b/collect_app/src/test/java/org/odk/collect/android/projects/ProjectDeleterTest.kt index 7183310f7b4..4100a188cf7 100644 --- a/collect_app/src/test/java/org/odk/collect/android/projects/ProjectDeleterTest.kt +++ b/collect_app/src/test/java/org/odk/collect/android/projects/ProjectDeleterTest.kt @@ -153,7 +153,7 @@ class ProjectDeleterTest { @Test fun `If there are running background jobs that use blank forms the project should not be deleted`() { val formChangeLock = BooleanChangeLock().apply { - tryLock() + lock() } whenever(changeLockProvider.getFormLock(any())).thenReturn(formChangeLock) @@ -166,7 +166,7 @@ class ProjectDeleterTest { @Test fun `If there are running background jobs that use saved forms the project should not be deleted`() { val changeLock = BooleanChangeLock().apply { - tryLock() + lock() } whenever(changeLockProvider.getInstanceLock(any())).thenReturn(changeLock) diff --git a/collect_app/src/test/java/org/odk/collect/android/projects/ProjectResetterTest.kt b/collect_app/src/test/java/org/odk/collect/android/projects/ProjectResetterTest.kt index 567d8b3f86a..798aa35cd93 100644 --- a/collect_app/src/test/java/org/odk/collect/android/projects/ProjectResetterTest.kt +++ b/collect_app/src/test/java/org/odk/collect/android/projects/ProjectResetterTest.kt @@ -202,7 +202,7 @@ class ProjectResetterTest { saveTestInstanceFiles(currentProjectId) setupTestInstancesDatabase(currentProjectId) - changeLockProvider.create(currentProjectId).instancesLock.tryLock() + changeLockProvider.create(currentProjectId).instancesLock.lock() val failedResetActions = projectResetter.reset(listOf(ProjectResetter.ResetAction.RESET_INSTANCES)) assertEquals(1, failedResetActions.size) diff --git a/shared/src/main/java/org/odk/collect/shared/locks/ChangeLock.kt b/shared/src/main/java/org/odk/collect/shared/locks/ChangeLock.kt index c2c806f6f76..9d41b231c7a 100644 --- a/shared/src/main/java/org/odk/collect/shared/locks/ChangeLock.kt +++ b/shared/src/main/java/org/odk/collect/shared/locks/ChangeLock.kt @@ -12,5 +12,7 @@ interface ChangeLock { fun tryLock(): Boolean + fun lock() + fun unlock() } diff --git a/shared/src/main/java/org/odk/collect/shared/locks/ThreadSafeBooleanChangeLock.kt b/shared/src/main/java/org/odk/collect/shared/locks/ThreadSafeBooleanChangeLock.kt index 3ba1a628f1b..55aa35f5573 100644 --- a/shared/src/main/java/org/odk/collect/shared/locks/ThreadSafeBooleanChangeLock.kt +++ b/shared/src/main/java/org/odk/collect/shared/locks/ThreadSafeBooleanChangeLock.kt @@ -28,6 +28,14 @@ class ThreadSafeBooleanChangeLock : ChangeLock { } } + override fun lock() { + if (locked) { + throw IllegalStateException() + } else { + locked = true + } + } + override fun unlock() { synchronized(this) { locked = false diff --git a/test-shared/src/main/java/org/odk/collect/testshared/BooleanChangeLock.kt b/test-shared/src/main/java/org/odk/collect/testshared/BooleanChangeLock.kt index b6fad2a46c6..43319d56820 100644 --- a/test-shared/src/main/java/org/odk/collect/testshared/BooleanChangeLock.kt +++ b/test-shared/src/main/java/org/odk/collect/testshared/BooleanChangeLock.kt @@ -27,6 +27,14 @@ class BooleanChangeLock : ChangeLock { } } + override fun lock() { + if (locked) { + throw IllegalStateException() + } else { + locked = true + } + } + override fun unlock() { locked = false } From 86620b98ddee9516c1de50852b19d0ce16762c7c Mon Sep 17 00:00:00 2001 From: Grzegorz Orczykowski Date: Tue, 29 Oct 2024 12:43:08 +0100 Subject: [PATCH 6/8] Improved ThreadSafeBooleanChangeLockTest --- .../locks/ThreadSafeBooleanChangeLockTest.kt | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/shared/src/test/java/org/odk/collect/shared/locks/ThreadSafeBooleanChangeLockTest.kt b/shared/src/test/java/org/odk/collect/shared/locks/ThreadSafeBooleanChangeLockTest.kt index 4547422483c..0f103e406cd 100644 --- a/shared/src/test/java/org/odk/collect/shared/locks/ThreadSafeBooleanChangeLockTest.kt +++ b/shared/src/test/java/org/odk/collect/shared/locks/ThreadSafeBooleanChangeLockTest.kt @@ -8,7 +8,7 @@ class ThreadSafeBooleanChangeLockTest { private val changeLock = ThreadSafeBooleanChangeLock() @Test - fun `tryLock acquires the lock if it is no acquired`() { + fun `tryLock acquires the lock if it is not acquired`() { val acquired = changeLock.tryLock() assertThat(acquired, equalTo(true)) @@ -22,6 +22,20 @@ class ThreadSafeBooleanChangeLockTest { assertThat(acquired, equalTo(false)) } + @Test + fun `lock acquires the lock if it is not acquired`() { + changeLock.lock() + val acquired = changeLock.tryLock() + + assertThat(acquired, equalTo(false)) + } + + @Test(expected = IllegalStateException::class) + fun `lock throws an exception if the lock is already acquired`() { + changeLock.lock() + changeLock.lock() + } + @Test fun `unlock releases the lock`() { changeLock.tryLock() @@ -32,7 +46,7 @@ class ThreadSafeBooleanChangeLockTest { } @Test - fun `withLock acquires the lock if it is no acquired`() { + fun `withLock acquires the lock if it is not acquired`() { changeLock.withLock { acquired -> assertThat(acquired, equalTo(true)) } From d7300a34bc817ce0bbdf602cf59bd14f19b9e736 Mon Sep 17 00:00:00 2001 From: Grzegorz Orczykowski Date: Tue, 29 Oct 2024 14:04:25 +0100 Subject: [PATCH 7/8] Test both implementations of ChangeLock --- .../android/external/FormUriActivityTest.kt | 2 +- .../formentry/FormEntryViewModelTest.java | 2 +- .../BlankFormListViewModelTest.kt | 2 +- .../formmanagement/FormsDataServiceTest.kt | 2 +- .../InstancesDataServiceTest.kt | 2 +- .../android/projects/ProjectDeleterTest.kt | 2 +- .../android/projects/ProjectResetterTest.kt | 2 +- .../shared/locks}/BooleanChangeLock.kt | 3 +- .../shared/locks/BooleanChangeLockTest.kt | 7 ++ .../collect/shared/locks/ChangeLockTest.kt | 99 +++++++++++++++++++ .../locks/ThreadSafeBooleanChangeLockTest.kt | 80 +-------------- 11 files changed, 117 insertions(+), 86 deletions(-) rename {test-shared/src/main/java/org/odk/collect/testshared => shared/src/main/java/org/odk/collect/shared/locks}/BooleanChangeLock.kt (90%) create mode 100644 shared/src/test/java/org/odk/collect/shared/locks/BooleanChangeLockTest.kt create mode 100644 shared/src/test/java/org/odk/collect/shared/locks/ChangeLockTest.kt diff --git a/collect_app/src/test/java/org/odk/collect/android/external/FormUriActivityTest.kt b/collect_app/src/test/java/org/odk/collect/android/external/FormUriActivityTest.kt index fe579e73de1..f86517a6474 100644 --- a/collect_app/src/test/java/org/odk/collect/android/external/FormUriActivityTest.kt +++ b/collect_app/src/test/java/org/odk/collect/android/external/FormUriActivityTest.kt @@ -62,8 +62,8 @@ import org.odk.collect.settings.InMemSettingsProvider import org.odk.collect.settings.SettingsProvider import org.odk.collect.settings.keys.ProtectedProjectKeys import org.odk.collect.shared.TempFiles +import org.odk.collect.shared.locks.BooleanChangeLock import org.odk.collect.shared.strings.UUIDGenerator -import org.odk.collect.testshared.BooleanChangeLock import org.odk.collect.testshared.FakeScheduler import java.io.File import java.text.SimpleDateFormat diff --git a/collect_app/src/test/java/org/odk/collect/android/formentry/FormEntryViewModelTest.java b/collect_app/src/test/java/org/odk/collect/android/formentry/FormEntryViewModelTest.java index b31ea2c95a9..34872a953bf 100644 --- a/collect_app/src/test/java/org/odk/collect/android/formentry/FormEntryViewModelTest.java +++ b/collect_app/src/test/java/org/odk/collect/android/formentry/FormEntryViewModelTest.java @@ -36,7 +36,7 @@ import org.odk.collect.androidshared.data.Consumable; import org.odk.collect.forms.FormsRepository; import org.odk.collect.formstest.InMemFormsRepository; -import org.odk.collect.testshared.BooleanChangeLock; +import org.odk.collect.shared.locks.BooleanChangeLock; import org.odk.collect.testshared.FakeScheduler; import java.io.FileNotFoundException; diff --git a/collect_app/src/test/java/org/odk/collect/android/formlists/blankformlist/BlankFormListViewModelTest.kt b/collect_app/src/test/java/org/odk/collect/android/formlists/blankformlist/BlankFormListViewModelTest.kt index b58ce8638cc..9fca88a6256 100644 --- a/collect_app/src/test/java/org/odk/collect/android/formlists/blankformlist/BlankFormListViewModelTest.kt +++ b/collect_app/src/test/java/org/odk/collect/android/formlists/blankformlist/BlankFormListViewModelTest.kt @@ -25,8 +25,8 @@ import org.odk.collect.formstest.FormUtils import org.odk.collect.formstest.InMemInstancesRepository import org.odk.collect.settings.enums.FormUpdateMode import org.odk.collect.settings.keys.ProjectKeys +import org.odk.collect.shared.locks.BooleanChangeLock import org.odk.collect.shared.settings.InMemSettings -import org.odk.collect.testshared.BooleanChangeLock import org.odk.collect.testshared.FakeScheduler import org.odk.collect.testshared.getOrAwaitValue diff --git a/collect_app/src/test/java/org/odk/collect/android/formmanagement/FormsDataServiceTest.kt b/collect_app/src/test/java/org/odk/collect/android/formmanagement/FormsDataServiceTest.kt index a0956e1d8d2..97c5d503f64 100644 --- a/collect_app/src/test/java/org/odk/collect/android/formmanagement/FormsDataServiceTest.kt +++ b/collect_app/src/test/java/org/odk/collect/android/formmanagement/FormsDataServiceTest.kt @@ -32,8 +32,8 @@ import org.odk.collect.forms.FormSourceException import org.odk.collect.formstest.FormUtils import org.odk.collect.projects.Project import org.odk.collect.settings.keys.ProjectKeys +import org.odk.collect.shared.locks.BooleanChangeLock import org.odk.collect.shared.strings.Md5.getMd5Hash -import org.odk.collect.testshared.BooleanChangeLock @RunWith(AndroidJUnit4::class) class FormsDataServiceTest { diff --git a/collect_app/src/test/java/org/odk/collect/android/instancemanagement/InstancesDataServiceTest.kt b/collect_app/src/test/java/org/odk/collect/android/instancemanagement/InstancesDataServiceTest.kt index d151d05498b..a30eead37ca 100644 --- a/collect_app/src/test/java/org/odk/collect/android/instancemanagement/InstancesDataServiceTest.kt +++ b/collect_app/src/test/java/org/odk/collect/android/instancemanagement/InstancesDataServiceTest.kt @@ -28,8 +28,8 @@ import org.odk.collect.formstest.InMemInstancesRepository import org.odk.collect.formstest.InstanceFixtures import org.odk.collect.projects.ProjectDependencyFactory import org.odk.collect.settings.keys.ProjectKeys +import org.odk.collect.shared.locks.BooleanChangeLock import org.odk.collect.shared.settings.InMemSettings -import org.odk.collect.testshared.BooleanChangeLock import java.io.File @RunWith(AndroidJUnit4::class) diff --git a/collect_app/src/test/java/org/odk/collect/android/projects/ProjectDeleterTest.kt b/collect_app/src/test/java/org/odk/collect/android/projects/ProjectDeleterTest.kt index 4100a188cf7..e2e36796f5a 100644 --- a/collect_app/src/test/java/org/odk/collect/android/projects/ProjectDeleterTest.kt +++ b/collect_app/src/test/java/org/odk/collect/android/projects/ProjectDeleterTest.kt @@ -24,7 +24,7 @@ import org.odk.collect.settings.keys.MetaKeys import org.odk.collect.settings.keys.ProjectKeys import org.odk.collect.settings.keys.ProtectedProjectKeys import org.odk.collect.shared.TempFiles -import org.odk.collect.testshared.BooleanChangeLock +import org.odk.collect.shared.locks.BooleanChangeLock import java.io.File class ProjectDeleterTest { diff --git a/collect_app/src/test/java/org/odk/collect/android/projects/ProjectResetterTest.kt b/collect_app/src/test/java/org/odk/collect/android/projects/ProjectResetterTest.kt index 798aa35cd93..0769cce49cf 100644 --- a/collect_app/src/test/java/org/odk/collect/android/projects/ProjectResetterTest.kt +++ b/collect_app/src/test/java/org/odk/collect/android/projects/ProjectResetterTest.kt @@ -33,8 +33,8 @@ import org.odk.collect.projects.Project import org.odk.collect.settings.SettingsProvider import org.odk.collect.settings.keys.ProjectKeys import org.odk.collect.settings.keys.ProtectedProjectKeys +import org.odk.collect.shared.locks.BooleanChangeLock import org.odk.collect.shared.settings.Settings -import org.odk.collect.testshared.BooleanChangeLock import java.io.File @RunWith(AndroidJUnit4::class) diff --git a/test-shared/src/main/java/org/odk/collect/testshared/BooleanChangeLock.kt b/shared/src/main/java/org/odk/collect/shared/locks/BooleanChangeLock.kt similarity index 90% rename from test-shared/src/main/java/org/odk/collect/testshared/BooleanChangeLock.kt rename to shared/src/main/java/org/odk/collect/shared/locks/BooleanChangeLock.kt index 43319d56820..4005fde3aa8 100644 --- a/test-shared/src/main/java/org/odk/collect/testshared/BooleanChangeLock.kt +++ b/shared/src/main/java/org/odk/collect/shared/locks/BooleanChangeLock.kt @@ -1,6 +1,5 @@ -package org.odk.collect.testshared +package org.odk.collect.shared.locks -import org.odk.collect.shared.locks.ChangeLock import java.util.function.Function class BooleanChangeLock : ChangeLock { diff --git a/shared/src/test/java/org/odk/collect/shared/locks/BooleanChangeLockTest.kt b/shared/src/test/java/org/odk/collect/shared/locks/BooleanChangeLockTest.kt new file mode 100644 index 00000000000..5da7acd3ac1 --- /dev/null +++ b/shared/src/test/java/org/odk/collect/shared/locks/BooleanChangeLockTest.kt @@ -0,0 +1,7 @@ +package org.odk.collect.shared.locks + +class BooleanChangeLockTest : ChangeLockTest() { + override fun buildSubject(): ChangeLock { + return BooleanChangeLock() + } +} diff --git a/shared/src/test/java/org/odk/collect/shared/locks/ChangeLockTest.kt b/shared/src/test/java/org/odk/collect/shared/locks/ChangeLockTest.kt new file mode 100644 index 00000000000..da241c2ed4b --- /dev/null +++ b/shared/src/test/java/org/odk/collect/shared/locks/ChangeLockTest.kt @@ -0,0 +1,99 @@ +package org.odk.collect.shared.locks + +import org.hamcrest.CoreMatchers.equalTo +import org.hamcrest.MatcherAssert.assertThat +import org.junit.Test + +abstract class ChangeLockTest { + abstract fun buildSubject(): ChangeLock + + @Test + fun `tryLock acquires the lock if it is not acquired`() { + val changeLock = buildSubject() + + val acquired = changeLock.tryLock() + + assertThat(acquired, equalTo(true)) + } + + @Test + fun `tryLock does not acquire the lock if it is already acquired`() { + val changeLock = buildSubject() + + changeLock.tryLock() + val acquired = changeLock.tryLock() + + assertThat(acquired, equalTo(false)) + } + + @Test + fun `lock acquires the lock if it is not acquired`() { + val changeLock = buildSubject() + + changeLock.lock() + val acquired = changeLock.tryLock() + + assertThat(acquired, equalTo(false)) + } + + @Test(expected = IllegalStateException::class) + fun `lock throws an exception if the lock is already acquired`() { + val changeLock = buildSubject() + + changeLock.lock() + changeLock.lock() + } + + @Test + fun `unlock releases the lock`() { + val changeLock = buildSubject() + + changeLock.tryLock() + changeLock.unlock() + val acquired = changeLock.tryLock() + + assertThat(acquired, equalTo(true)) + } + + @Test + fun `withLock acquires the lock if it is not acquired`() { + val changeLock = buildSubject() + + changeLock.withLock { acquired -> + assertThat(acquired, equalTo(true)) + } + } + + @Test + fun `withLock does not acquire the lock if it is already acquired`() { + val changeLock = buildSubject() + + changeLock.tryLock() + changeLock.withLock { acquired -> + assertThat(acquired, equalTo(false)) + } + } + + @Test + fun `withLock releases the lock after performing the job`() { + val changeLock = buildSubject() + + changeLock.withLock {} + + val acquired = changeLock.tryLock() + + assertThat(acquired, equalTo(true)) + } + + @Test + fun `withLock does not release the lock it it was not able to acquire it`() { + val changeLock = buildSubject() + + changeLock.tryLock() + changeLock.withLock {} + + val acquired = changeLock.tryLock() + + assertThat(acquired, equalTo(false)) + } +} diff --git a/shared/src/test/java/org/odk/collect/shared/locks/ThreadSafeBooleanChangeLockTest.kt b/shared/src/test/java/org/odk/collect/shared/locks/ThreadSafeBooleanChangeLockTest.kt index 0f103e406cd..98546ded25f 100644 --- a/shared/src/test/java/org/odk/collect/shared/locks/ThreadSafeBooleanChangeLockTest.kt +++ b/shared/src/test/java/org/odk/collect/shared/locks/ThreadSafeBooleanChangeLockTest.kt @@ -1,81 +1,7 @@ package org.odk.collect.shared.locks -import org.hamcrest.CoreMatchers.equalTo -import org.hamcrest.MatcherAssert.assertThat -import org.junit.Test - -class ThreadSafeBooleanChangeLockTest { - private val changeLock = ThreadSafeBooleanChangeLock() - - @Test - fun `tryLock acquires the lock if it is not acquired`() { - val acquired = changeLock.tryLock() - - assertThat(acquired, equalTo(true)) - } - - @Test - fun `tryLock does not acquire the lock if it is already acquired`() { - changeLock.tryLock() - val acquired = changeLock.tryLock() - - assertThat(acquired, equalTo(false)) - } - - @Test - fun `lock acquires the lock if it is not acquired`() { - changeLock.lock() - val acquired = changeLock.tryLock() - - assertThat(acquired, equalTo(false)) - } - - @Test(expected = IllegalStateException::class) - fun `lock throws an exception if the lock is already acquired`() { - changeLock.lock() - changeLock.lock() - } - - @Test - fun `unlock releases the lock`() { - changeLock.tryLock() - changeLock.unlock() - val acquired = changeLock.tryLock() - - assertThat(acquired, equalTo(true)) - } - - @Test - fun `withLock acquires the lock if it is not acquired`() { - changeLock.withLock { acquired -> - assertThat(acquired, equalTo(true)) - } - } - - @Test - fun `withLock does not acquire the lock if it is already acquired`() { - changeLock.tryLock() - changeLock.withLock { acquired -> - assertThat(acquired, equalTo(false)) - } - } - - @Test - fun `withLock releases the lock after performing the job`() { - changeLock.withLock {} - - val acquired = changeLock.tryLock() - - assertThat(acquired, equalTo(true)) - } - - @Test - fun `withLock does not release the lock it it was not able to acquire it`() { - changeLock.tryLock() - changeLock.withLock {} - - val acquired = changeLock.tryLock() - - assertThat(acquired, equalTo(false)) +class ThreadSafeBooleanChangeLockTest : ChangeLockTest() { + override fun buildSubject(): ChangeLock { + return ThreadSafeBooleanChangeLock() } } From 6856223fc861f2356c6391450dcc45f57c276f0a Mon Sep 17 00:00:00 2001 From: Grzegorz Orczykowski Date: Wed, 30 Oct 2024 18:32:03 +0100 Subject: [PATCH 8/8] Use synchronized in #lock --- .../shared/locks/ThreadSafeBooleanChangeLock.kt | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/shared/src/main/java/org/odk/collect/shared/locks/ThreadSafeBooleanChangeLock.kt b/shared/src/main/java/org/odk/collect/shared/locks/ThreadSafeBooleanChangeLock.kt index 55aa35f5573..ba2cc93bafb 100644 --- a/shared/src/main/java/org/odk/collect/shared/locks/ThreadSafeBooleanChangeLock.kt +++ b/shared/src/main/java/org/odk/collect/shared/locks/ThreadSafeBooleanChangeLock.kt @@ -29,10 +29,12 @@ class ThreadSafeBooleanChangeLock : ChangeLock { } override fun lock() { - if (locked) { - throw IllegalStateException() - } else { - locked = true + synchronized(this) { + if (locked) { + throw IllegalStateException() + } else { + locked = true + } } }