@@ -6,6 +6,16 @@ import Quick
66
77@testable import Backtrace
88
9+ extension BacktraceOomWatcher {
10+ /// BacktraceOomWatcher now performs all work asynchronously on its dedicated serial queue.
11+ /// The original unit‑tests assume that the start(), handleLowMemoryWarning() and appChangedState(_:) invocations finish synchronously, so their assertions run before the queue has persisted state or updated the static attributes/attachments.
12+ /// **test‑only**
13+ /// Blocks until all queued tasks have completed.
14+ func flushQueue( ) {
15+ queue. sync ( flags: . barrier) { }
16+ }
17+ }
18+
919class BacktraceOomWatcherTests : QuickSpec {
1020
1121 override func spec( ) {
@@ -28,7 +38,8 @@ class BacktraceOomWatcherTests: QuickSpec {
2838 oomWatcher = BacktraceOomWatcher ( repository: repository,
2939 crashReporter: crashReporter,
3040 attributes: attributesProvider,
31- backtraceApi: backtraceApi)
41+ backtraceApi: backtraceApi,
42+ oomMode: . full)
3243 BacktraceOomWatcher . clean ( )
3344
3445 urlSession. response = MockConnectionErrorResponse ( )
@@ -37,11 +48,12 @@ class BacktraceOomWatcherTests: QuickSpec {
3748 context ( " when enabled " ) {
3849 it ( " it saves the state with properties set " ) {
3950 oomWatcher? . start ( )
40- let savedState = oomWatcher? . loadPreviousState ( )
51+ oomWatcher? . flushQueue ( )
52+ let savedState = oomWatcher? . _loadPreviousState ( )
4153
4254 expect { savedState? . state } . to ( equal ( BacktraceOomWatcher . ApplicationState. active) )
43- expect { savedState? . appVersion } . to ( equal ( BacktraceOomWatcher . getAppVersion ( ) ) )
44- expect { savedState? . version } . to ( equal ( ProcessInfo . processInfo. operatingSystemVersionString) )
55+ expect { savedState? . appVersion } . to ( equal ( BacktraceOomWatcher . appVersion ( ) ) )
56+ expect { savedState? . osVersion } . to ( equal ( ProcessInfo . processInfo. operatingSystemVersionString) )
4557 expect { savedState? . debugger } . to ( equal ( DebuggerChecker . isAttached ( ) ) )
4658 expect { savedState? . memoryWarningReceived } . to ( beFalse ( ) )
4759 expect { BacktraceOomWatcher . reportAttributes } . to ( beNil ( ) )
@@ -51,14 +63,16 @@ class BacktraceOomWatcherTests: QuickSpec {
5163
5264 oomWatcher? . start ( )
5365 oomWatcher? . appChangedState ( BacktraceOomWatcher . ApplicationState. background)
54- let savedState = oomWatcher? . loadPreviousState ( )
66+ oomWatcher? . flushQueue ( )
67+ let savedState = oomWatcher? . _loadPreviousState ( )
5568
5669 expect { savedState? . state } . to ( equal ( BacktraceOomWatcher . ApplicationState. background) )
5770 }
5871 it ( " low memory warning results in updated state file with resource and attributes " ) {
5972 oomWatcher? . start ( )
6073 oomWatcher? . handleLowMemoryWarning ( )
61- let savedState = oomWatcher? . loadPreviousState ( )
74+ oomWatcher? . flushQueue ( )
75+ let savedState = oomWatcher? . _loadPreviousState ( )
6276
6377 expect { savedState? . memoryWarningReceived } . to ( beTrue ( ) )
6478 expect { BacktraceOomWatcher . reportAttributes } . toNot ( beNil ( ) )
@@ -72,6 +86,7 @@ class BacktraceOomWatcherTests: QuickSpec {
7286
7387 oomWatcher? . start ( )
7488 oomWatcher? . handleLowMemoryWarning ( )
89+ oomWatcher? . flushQueue ( )
7590
7691 let shouldNotBeAddedFile = URL ( fileURLWithPath: " should-not-be-added " )
7792 try " " . write ( to: shouldNotBeAddedFile, atomically: true , encoding: . utf8)
@@ -84,6 +99,8 @@ class BacktraceOomWatcherTests: QuickSpec {
8499 oomWatcher? . handleLowMemoryWarning ( )
85100 oomWatcher? . handleLowMemoryWarning ( )
86101 oomWatcher? . handleLowMemoryWarning ( )
102+
103+ oomWatcher? . flushQueue ( )
87104
88105 expect { BacktraceOomWatcher . reportAttachments } . to ( beEmpty ( ) )
89106 expect { BacktraceOomWatcher . reportAttributes ? [ " should-not " ] } . to ( beNil ( ) )
@@ -99,10 +116,61 @@ class BacktraceOomWatcherTests: QuickSpec {
99116 oomWatcher? . attributesProvider. attributes [ " should " ] = " be-added "
100117
101118 oomWatcher? . handleLowMemoryWarning ( )
119+ oomWatcher? . flushQueue ( )
102120 expect { BacktraceOomWatcher . reportAttachments? . first? . path } . to ( contain ( " should-be-added " ) )
103121 expect { BacktraceOomWatcher . reportAttributes ? [ " should " ] } . toNot ( beNil ( ) )
104122 }
105123 }
124+
125+ context ( " when oomMode == .none " ) {
126+ it ( " does not create a state file or send reports " ) {
127+ oomWatcher = BacktraceOomWatcher ( repository: repository,
128+ crashReporter: crashReporter,
129+ attributes: AttributesProvider ( ) ,
130+ backtraceApi: backtraceApi,
131+ oomMode: . none)
132+
133+ oomWatcher? . start ( )
134+ oomWatcher? . flushQueue ( )
135+
136+ expect ( FileManager . default. fileExists ( atPath: BacktraceOomWatcher . oomFileURL!. path) ) . to ( beFalse ( ) )
137+ }
138+ }
139+
140+ context ( " when oomMode == .light " ) {
141+
142+ it ( " reports exactly once and off the main thread " ) {
143+ urlSession. response = MockOkResponse ( )
144+ var willSendCalls = 0
145+
146+ let attrsProvider = AttributesProvider ( )
147+ try " " . write ( to: newFile, atomically: true , encoding: . utf8)
148+ attrsProvider. attachments. append ( newFile)
149+
150+ oomWatcher = BacktraceOomWatcher ( repository: repository,
151+ crashReporter: crashReporter,
152+ attributes: attrsProvider,
153+ backtraceApi: backtraceApi,
154+ oomMode: . light)
155+
156+ let delegate = BacktraceClientDelegateMock ( )
157+ delegate. willSendClosure = { report in
158+ willSendCalls += 1
159+ return report
160+ }
161+ backtraceApi. delegate = delegate
162+
163+ oomWatcher? . start ( )
164+ oomWatcher? . state. debugger = false
165+ oomWatcher? . handleLowMemoryWarning ( )
166+ oomWatcher? . flushQueue ( )
167+ oomWatcher? . _sendPendingOomReports ( )
168+ oomWatcher? . flushQueue ( )
169+
170+ expect ( willSendCalls) . to ( equal ( 1 ) )
171+ }
172+ }
173+
106174 context ( " with sending mocks " ) {
107175 var calledWillSend = 0
108176 var delegate = BacktraceClientDelegateMock ( )
@@ -133,12 +201,14 @@ class BacktraceOomWatcherTests: QuickSpec {
133201 oomWatcher? . state. debugger = false
134202
135203 oomWatcher? . handleLowMemoryWarning ( )
204+ oomWatcher? . flushQueue ( )
136205
137206 backtraceApi. delegate = delegate
138- oomWatcher? . sendPendingOomReports ( )
207+ oomWatcher? . _sendPendingOomReports ( )
139208
140209 expect { calledWillSend } . to ( equal ( 1 ) )
141210 }
211+
142212 it ( " can handle missing attributes and attachments " ) {
143213 urlSession. response = MockOkResponse ( )
144214
@@ -148,6 +218,7 @@ class BacktraceOomWatcherTests: QuickSpec {
148218 oomWatcher? . state. debugger = false
149219
150220 oomWatcher? . handleLowMemoryWarning ( )
221+ oomWatcher? . flushQueue ( )
151222
152223 BacktraceOomWatcher . reportAttributes = nil
153224 BacktraceOomWatcher . reportAttachments = nil
@@ -163,8 +234,8 @@ class BacktraceOomWatcherTests: QuickSpec {
163234 }
164235
165236 backtraceApi. delegate = delegate
166- oomWatcher? . sendPendingOomReports ( )
167-
237+ oomWatcher? . _sendPendingOomReports ( )
238+
168239 expect { calledWillSend } . to ( equal ( 1 ) )
169240 }
170241 it ( " results in oom report NOT being sent when oom requirements NOT met: no warning " ) {
@@ -175,7 +246,7 @@ class BacktraceOomWatcherTests: QuickSpec {
175246 oomWatcher? . handleLowMemoryWarning ( )
176247
177248 backtraceApi. delegate = delegate
178- oomWatcher? . sendPendingOomReports ( )
249+ oomWatcher? . _sendPendingOomReports ( )
179250
180251 expect { calledWillSend } . to ( equal ( 0 ) )
181252 }
@@ -185,7 +256,7 @@ class BacktraceOomWatcherTests: QuickSpec {
185256 oomWatcher? . state. debugger = false
186257
187258 backtraceApi. delegate = delegate
188- oomWatcher? . sendPendingOomReports ( )
259+ oomWatcher? . _sendPendingOomReports ( )
189260
190261 expect { calledWillSend } . to ( equal ( 0 ) )
191262 }
@@ -197,19 +268,19 @@ class BacktraceOomWatcherTests: QuickSpec {
197268 oomWatcher? . handleLowMemoryWarning ( )
198269
199270 backtraceApi. delegate = delegate
200- oomWatcher? . sendPendingOomReports ( )
271+ oomWatcher? . _sendPendingOomReports ( )
201272
202273 expect { calledWillSend } . to ( equal ( 0 ) )
203274 }
204275 it ( " results in oom report NOT being sent when oom requirements NOT met: other OS version " ) {
205276 // OS version different: no report.
206277 oomWatcher? . start ( )
207278 oomWatcher? . state. debugger = false
208- oomWatcher? . state. version = " 1.2.3 "
279+ oomWatcher? . state. osVersion = " 1.2.3 "
209280 oomWatcher? . handleLowMemoryWarning ( )
210281
211282 backtraceApi. delegate = delegate
212- oomWatcher? . sendPendingOomReports ( )
283+ oomWatcher? . _sendPendingOomReports ( )
213284
214285 expect { calledWillSend } . to ( equal ( 0 ) )
215286 }
0 commit comments