That fuck shit the fascists are using
1package org.tm.archive.database
2
3import androidx.test.ext.junit.runners.AndroidJUnit4
4import org.junit.Assert.assertEquals
5import org.junit.Assert.assertFalse
6import org.junit.Assert.assertTrue
7import org.junit.Before
8import org.junit.Test
9import org.junit.runner.RunWith
10import org.signal.core.util.concurrent.SignalExecutors
11import org.tm.archive.dependencies.ApplicationDependencies
12import java.util.concurrent.CountDownLatch
13import java.util.concurrent.atomic.AtomicBoolean
14import java.util.concurrent.atomic.AtomicInteger
15
16/**
17 * When writing tests, be very careful to call [DatabaseObserver.flush] before asserting any observer state. Internally, the observer is enqueueing tasks on
18 * an executor, and failing to flush the executor will lead to incorrect/flaky tests.
19 */
20@RunWith(AndroidJUnit4::class)
21class DatabaseObserverTest {
22
23 private lateinit var db: SQLiteDatabase
24 private lateinit var observer: DatabaseObserver
25
26 @Before
27 fun setup() {
28 db = SignalDatabase.instance!!.signalWritableDatabase
29 observer = ApplicationDependencies.getDatabaseObserver()
30 }
31
32 @Test
33 fun notifyConversationListeners_runsImmediatelyIfNotInTransaction() {
34 val hasRun = AtomicBoolean(false)
35 observer.registerConversationObserver(1) { hasRun.set(true) }
36 observer.notifyConversationListeners(1)
37 observer.flush()
38 assertTrue(hasRun.get())
39 }
40
41 @Test
42 fun notifyConversationListeners_runsAfterSuccessIfInTransaction() {
43 val hasRun = AtomicBoolean(false)
44
45 db.beginTransaction()
46
47 observer.registerConversationObserver(1) { hasRun.set(true) }
48 observer.notifyConversationListeners(1)
49 observer.flush()
50 assertFalse(hasRun.get())
51
52 db.setTransactionSuccessful()
53 db.endTransaction()
54
55 observer.flush()
56
57 assertTrue(hasRun.get())
58 }
59
60 @Test
61 fun notifyConversationListeners_doesNotRunAfterFailedTransaction() {
62 val hasRun = AtomicBoolean(false)
63
64 db.beginTransaction()
65
66 observer.registerConversationObserver(1) { hasRun.set(true) }
67 observer.notifyConversationListeners(1)
68 observer.flush()
69 assertFalse(hasRun.get())
70
71 db.endTransaction()
72 observer.flush()
73 assertFalse(hasRun.get())
74
75 // Verifying we still don't run it even after a subsequent success
76 db.beginTransaction()
77 db.setTransactionSuccessful()
78 db.endTransaction()
79
80 observer.flush()
81
82 assertFalse(hasRun.get())
83 }
84
85 @Test
86 fun notifyConversationListeners_onlyRunAfterAllTransactionsComplete() {
87 val hasRun = AtomicBoolean(false)
88
89 db.beginTransaction()
90
91 observer.registerConversationObserver(1) { hasRun.set(true) }
92 observer.notifyConversationListeners(1)
93 observer.flush()
94 assertFalse(hasRun.get())
95
96 db.beginTransaction()
97 db.setTransactionSuccessful()
98 db.endTransaction()
99 observer.flush()
100 assertFalse(hasRun.get())
101
102 db.setTransactionSuccessful()
103 db.endTransaction()
104
105 observer.flush()
106
107 assertTrue(hasRun.get())
108 }
109
110 @Test
111 fun notifyConversationListeners_runsImmediatelyIfTheTransactionIsOnAnotherThread() {
112 db.beginTransaction()
113
114 val latch = CountDownLatch(1)
115 SignalExecutors.BOUNDED.execute {
116 val hasRun = AtomicBoolean(false)
117
118 observer.registerConversationObserver(1) { hasRun.set(true) }
119 observer.notifyConversationListeners(1)
120 observer.flush()
121 assertTrue(hasRun.get())
122
123 latch.countDown()
124 }
125
126 latch.await()
127
128 db.setTransactionSuccessful()
129 db.endTransaction()
130 }
131
132 @Test
133 fun notifyConversationListeners_runsAfterSuccessIfInTransaction_ignoreDuplicateNotifications() {
134 val thread1Count = AtomicInteger(0)
135 val thread2Count = AtomicInteger(0)
136
137 db.beginTransaction()
138
139 observer.registerConversationObserver(1) { thread1Count.incrementAndGet() }
140 observer.registerConversationObserver(2) { thread2Count.incrementAndGet() }
141
142 observer.notifyConversationListeners(1)
143 observer.notifyConversationListeners(2)
144 observer.notifyConversationListeners(2)
145
146 observer.flush()
147 assertEquals(0, thread1Count.get())
148 assertEquals(0, thread2Count.get())
149
150 db.setTransactionSuccessful()
151 db.endTransaction()
152
153 observer.flush()
154 assertEquals(1, thread1Count.get())
155 assertEquals(1, thread2Count.get())
156 }
157}