Improve workflow and test readability

Signed-off-by: Loren Eteval <loren.eteval@proton.me>
This commit is contained in:
Loren Eteval
2026-09-08 15:52:25 +08:00
parent c8099462a7
commit c4fb12be50
22 changed files with 113 additions and 0 deletions
@@ -1034,6 +1034,7 @@ class DesktopApplication(ApplicationRunner, SingletonApplication):
self.addCustomFont()
# self.configureApplicationFont()
self.configureLogging()
self._logRuntimeInformation()
@@ -192,6 +192,7 @@ class ConnectionController(QtCore.QObject):
"""Restore disconnected state after all runtime resources stop."""
self._startOperation = None
self._pendingHttpProxy = ''
self.progressFinished.emit(True)
self._setActiveProfile(None)
@@ -275,6 +276,7 @@ class ConnectionController(QtCore.QObject):
self._lastError = None
self._setActiveProfile(configuration)
self._pendingHttpProxy = httpProxy
self._startConnecting()
logManager = AppLogManager()
@@ -405,6 +407,7 @@ class ConnectionController(QtCore.QObject):
interval *= 2
self._actionTimer.start(interval)
self._runPostConnectTasksOnce()
return True
@@ -459,6 +462,7 @@ class ConnectionController(QtCore.QObject):
self._startOperation = None
self._emitRuntimesChanged()
self._reset()
def startDisconnection(self, notification: str = '') -> bool:
+15
View File
@@ -249,6 +249,7 @@ class _RuntimeReadinessProbe(QtCore.QObject):
self._terminal = True
self._timer.stop()
self._socket.abort()
self.ready.emit()
def _finishFailed(self, message):
@@ -259,6 +260,7 @@ class _RuntimeReadinessProbe(QtCore.QObject):
self._terminal = True
self._timer.stop()
self._socket.abort()
self.failed.emit(str(message))
def cancel(self):
@@ -330,6 +332,7 @@ class _ConditionProbe(QtCore.QObject):
self._terminal = True
self._timer.stop()
self.finished.emit(bool(success))
def cancel(self):
@@ -377,6 +380,7 @@ class ConnectionStartOperation(QtCore.QObject):
self.proxyModeOnly = proxyModeOnly
self.log = log
self.options = dict(options or {})
self.attempt = _ConnectionStartAttempt(
manager, manager._runtimeConfiguration(config, deepcopy)
)
@@ -558,6 +562,7 @@ class ConnectionStartOperation(QtCore.QObject):
self._readinessProbe = None
self._conditionContinuation = ''
self._fail('Failed to start core', message)
def _afterPrimaryReady(self):
@@ -605,6 +610,7 @@ class ConnectionStartOperation(QtCore.QObject):
f'\'DefaultPrimaryGatewayIP\': {userGateway}. '
f'\'PrimaryAdapterInterfaceIP\': {userInterfaceIP}'
)
self._gateway, self._interface = userGateway, userInterfaceIP
else:
logger.info(
@@ -612,6 +618,7 @@ class ConnectionStartOperation(QtCore.QObject):
'\'DefaultPrimaryGatewayIP\' and '
'\'PrimaryAdapterInterfaceIP\''
)
defaultGateway = SystemRoutingTable.getDefaultGateway()
if PLATFORM == 'Darwin':
@@ -944,6 +951,7 @@ class ConnectionStartOperation(QtCore.QObject):
for sourceIP, destinationIP in SystemRoutingTable.managedRoutes
if iproute.find(route(sourceIP, destinationIP)) == -1
)
tempdir = os.environ.get('TMPDIR') if SystemRuntime.flatpakID() else None
with tempfile.NamedTemporaryFile(
@@ -1013,8 +1021,10 @@ class ConnectionStartOperation(QtCore.QObject):
self.attempt.commit(self.exitCallback)
self._terminal = True
self._setStage(ConnectionStartStage.Succeeded)
self.succeeded.emit(self)
self.manager._finishStartOperation(self)
self.deleteLater()
@@ -1048,8 +1058,10 @@ class ConnectionStartOperation(QtCore.QObject):
self.manager._lastStartError = concise
self.attempt.rollback(f'connection startup failed: {details or concise}')
self._setStage(ConnectionStartStage.Failed)
self.failed.emit(self, concise, str(details or ''))
self.manager._finishStartOperation(self)
self.deleteLater()
@@ -1060,9 +1072,12 @@ class ConnectionStartOperation(QtCore.QObject):
self._terminal = True
self._cancelObservers()
self.attempt.rollback('connection startup cancelled')
self._setStage(ConnectionStartStage.Cancelled)
self.cancelled.emit(self)
self.manager._finishStartOperation(self)
self.deleteLater()
+2
View File
@@ -70,6 +70,7 @@ class DnsResolutionOperation(QtCore.QObject):
logger.error(f'failed to start DNS resolution for {self._domain!r}: {ex}')
self._resultMap['error'] = True
self._finish()
return
@@ -114,6 +115,7 @@ class DnsResolutionOperation(QtCore.QObject):
self._terminal = True
self._timer.stop()
self.finished.emit(
bool(self._resultMap['error']),
list(self._resultMap['result'].keys()),
+2
View File
@@ -331,6 +331,7 @@ class LogManager(QtCore.QObject):
self._retainedEntryCount = 0
self._retainedCharacters = 0
self._generationSequence = 0
# Three fixed active streams preserve exact global ordering with an O(n)
# three-way merge and make oldest-live selection constant time. Runtime
# categories are isolated so disconnect/runtime clear is one reference
@@ -341,6 +342,7 @@ class LogManager(QtCore.QObject):
self._otherGeneration = self._newGenerationLocked('other')
self._runtimeCategoryIds = frozenset()
self._nonApplicationCategoryIds = frozenset()
# Retired batches remain strongly owned until bounded cleanup removes
# their entries. Merely dropping a large OrderedDict here would make the
# clear caller synchronously execute thousands of CPython decrefs.
+14
View File
@@ -523,6 +523,7 @@ class _LatencyScheduler(QtCore.QObject):
worker = self.pingWorkerFactory(job, self)
self.activeJobs[id(job)] = (job, worker)
self.threadPool.start(worker)
@QtCore.Slot(object, object)
@@ -534,6 +535,7 @@ class _LatencyScheduler(QtCore.QObject):
return
self.completeJob(job, result)
self.scheduleDrain()
def reconcileProfiles(self):
@@ -551,12 +553,14 @@ class _LatencyScheduler(QtCore.QObject):
for job, worker in list(self.activeJobs.values()):
if self._resolveTarget(job.target) is None:
job.state = ProfileTestJobState.Cancelled
cancel = getattr(worker, 'cancel', None)
if callable(cancel):
cancel()
self.discardTcpingJobs(lambda job: self._resolveTarget(job.target) is None)
self.scheduleDrain()
def invalidateSubscriptions(self, subscriptionIds):
@@ -575,6 +579,7 @@ class _LatencyScheduler(QtCore.QObject):
for job, worker in list(self.activeJobs.values()):
if job.target.subscriptionSource in subscriptionIds:
job.state = ProfileTestJobState.Cancelled
cancel = getattr(worker, 'cancel', None)
if callable(cancel):
@@ -624,6 +629,7 @@ class _LatencyScheduler(QtCore.QObject):
for job, worker in list(self.activeJobs.values()):
job.state = ProfileTestJobState.Cancelled
cancel = getattr(worker, 'cancel', None)
if callable(cancel):
@@ -815,6 +821,7 @@ class _DownloadSpeedWorker(HttpGetManager):
return
self.cancelled = True
self.coreStartupTimer.stop()
self.timeoutTimer.stop()
@@ -985,6 +992,7 @@ class _DownloadSpeedWorker(HttpGetManager):
self.setResult('Core start failed', publish=False)
self._releaseRuntime()
self.publishProgress()
def hasDataCallback(self, networkReply, **_kwargs):
@@ -1033,6 +1041,7 @@ class _DownloadSpeedWorker(HttpGetManager):
self.setResult(value, publish=False)
self._releaseRuntime()
self.publishProgress()
@@ -1081,6 +1090,7 @@ class _DownloadSpeedScheduler(QtCore.QObject):
_DownloadSpeedTestJob(ProfileTestTarget.capture(profile), options)
for profile in profiles
)
self.scheduleDrain()
def cancelAll(self):
@@ -1208,6 +1218,7 @@ class _DownloadSpeedScheduler(QtCore.QObject):
self.activePorts.discard(port)
worker.deleteLater()
self.scheduleDrain()
def reconcileProfiles(self):
@@ -1285,6 +1296,7 @@ class ProfileTestManager(QtCore.QObject):
self._profilesProvider = profilesProvider or Storage.UserServers
self._targets = _currentTargets(self._profilesProvider())
self._latencyScheduler = _LatencyScheduler(
self.resolveTarget,
self.applyResult,
@@ -1376,6 +1388,7 @@ class ProfileTestManager(QtCore.QObject):
if concurrent
else self._serialDownloadScheduler
)
scheduler.enqueue(profiles, options)
def clearResults(self, profiles):
@@ -1411,6 +1424,7 @@ class ProfileTestManager(QtCore.QObject):
for profile in self._profilesProvider()
if profile.metadata.subscriptionSource in subscriptionIds
]
self.clearResults(profiles)
self.reconcileProfiles()
+1
View File
@@ -71,6 +71,7 @@ class RuntimeEventRouter(QtCore.QObject):
self._attemptMethod = ''
self._committedCallback = None
self._terminalDelivered = False
self._publishedConnection = connectWeakly(
self._published,
self,
+5
View File
@@ -660,6 +660,7 @@ class SubscriptionManager(HttpGetManager):
logger.exception(
f'failed to commit subscription {context.get("unique", "")!r}'
)
self._failOperation(context, error)
return
@@ -667,8 +668,10 @@ class SubscriptionManager(HttpGetManager):
committed = {**context, 'syncResult': result}
self.subscriptionCommitted.emit(context['unique'])
self._recordGroupSuccess(committed, result)
self.subscriptionStateChanged.emit((context['unique'],))
self._finishOperation(committed, successful=committed, structural=True)
logger.info(
@@ -815,7 +818,9 @@ class SubscriptionManager(HttpGetManager):
controller = AppConnectionController()
wasConnected = controller is not None and controller.isConnected()
result = self.synchronizer.commit(servers, plan)
newActivatedIndex = next(
(
index
+2
View File
@@ -140,6 +140,7 @@ class SubscriptionSynchronizer:
profiles[index].metadata.profileId: profiles[index]
for index in managedIndexes
}
synchronized = []
for prepared in plan.profiles:
@@ -246,6 +247,7 @@ class SubscriptionSynchronizer:
): profiles[index]
for index in managedIndexes
}
synchronized = []
incomingMetadata = []
existingUpdates = []
+4
View File
@@ -128,6 +128,7 @@ class TcpingProbe(QtCore.QObject):
"""Start one non-blocking TCP connection attempt."""
self.elapsedTimer.start()
self.timeoutTimer.start(self.request.timeoutMilliseconds)
self.socket.connectToHost(self.request.address, self.request.port)
@QtCore.Slot()
@@ -153,6 +154,7 @@ class TcpingProbe(QtCore.QObject):
return
self.completionHasRun = True
self.timeoutTimer.stop()
if self.socket.state() != QAbstractSocket.SocketState.UnconnectedState:
@@ -215,6 +217,7 @@ class TcpingEngine(QtCore.QObject):
return
self.pendingRequests.extend(requests)
self.drain()
def drain(self):
@@ -320,6 +323,7 @@ class TcpingEngine(QtCore.QObject):
return
self.stopping = True
self.pendingRequests.clear()
for probe in list(self.activeProbes.values()):
+4
View File
@@ -332,6 +332,7 @@ class TrafficStatsManager(
self._sampleTimer.stop()
self._generation += 1
self._cancelCurrentQuery()
self._monitor = monitor
self._resetSamples()
self._beginConnectionUsage()
@@ -375,6 +376,7 @@ class TrafficStatsManager(
monitor = getPluginRegistry().trafficStatsMonitorForRuntimes(
self._activeRuntimes()
)
self._activateMonitor(monitor)
@QtCore.Slot()
@@ -488,6 +490,7 @@ class TrafficStatsManager(
if counters is None:
self._previousCounters = None
self._previousSampleTime = None
self.statisticsUnavailable.emit()
return
@@ -510,6 +513,7 @@ class TrafficStatsManager(
monitor = getPluginRegistry().trafficStatsMonitorForRuntimes(
self._activeRuntimes()
)
self._activateMonitor(monitor)
def disconnectedCallback(self):
+3
View File
@@ -268,6 +268,7 @@ class DeleteServersProgressDialog(AppQTransientDialog):
Storage.UserServers().pop(deleteIndex)
self.table.sourceModel.endRemoveRows()
self.table.reconcileProfileTestJobs()
if not self.deletedActivated and deleteIndex < Storage.UserActivatedItemIndex():
@@ -276,6 +277,7 @@ class DeleteServersProgressDialog(AppQTransientDialog):
)
self.deletedCount += 1
self.updateStatus()
singleShotWeakly(0, self, 'deleteNext')
@@ -1716,6 +1718,7 @@ class ServerTableView(
showTrayMessage=showTrayMessage,
parent=self.window(),
)
dialog.open()
return 0
+5
View File
@@ -197,6 +197,7 @@ class LogPage(Mixins.QTranslatable, QMainWindow):
self.pageTitleLabel.setObjectName('LogPageTitle')
self.filterLabel = AppQLabel(_('Log Type'))
# Category names can be either translated built-ins or literal plugin
# metadata, so LogPage rebuilds this application-styled selector with
# the correct per-category translation policy.
@@ -403,6 +404,7 @@ class LogPage(Mixins.QTranslatable, QMainWindow):
self.autoScrollSwitch.toggled.connect(self._autoScrollChanged)
self.autoClearSwitch.toggled.connect(self._autoClearChanged)
self.manager.categoryRegistered.connect(self._categoryRegistered)
# Do not drive the document directly from entryAdded: cross-thread Qt
# delivery can occur after that entry was evicted or its generation was
# cleared, and one queued signal per line defeats batching under a burst.
@@ -665,6 +667,7 @@ class LogPage(Mixins.QTranslatable, QMainWindow):
self._documentMutation = False
self.textBrowser.viewport().update()
self._renderedCategoryId = categoryId
self._representationInvalid = False
@@ -715,6 +718,7 @@ class LogPage(Mixins.QTranslatable, QMainWindow):
)
self._entryCursor = None
self._requestRefresh(invalidate=True, immediate=True)
return
@@ -748,6 +752,7 @@ class LogPage(Mixins.QTranslatable, QMainWindow):
document = self.textBrowser.document()
start = self._highlightNextBlock
maximumEnd = min(document.blockCount(), start + self.HighlightBatchSize)
elapsed = QtCore.QElapsedTimer()
elapsed.start()
end = start
+4
View File
@@ -360,6 +360,7 @@ class QRCodeWindow(AppQMainWindow):
self.cancelExport()
self._clearTabs()
self._exportProcessedCount = 0
self._exportGeneratedCount = 0
@@ -372,15 +373,18 @@ class QRCodeWindow(AppQMainWindow):
if self.appendExportItem(items[0]):
self._exportProcessedCount = 1
self._exportGeneratedCount = 1
self.show()
else:
self._exportProcessedCount = 1
self.deleteLater()
return self
self._exportItems = items
self._exporting = True
self.show()
self._exportTimer.start(0)
+5
View File
@@ -222,14 +222,19 @@ class ConnectionStartupAsyncTest(TestCase):
readiness=CoreRuntimeStartup(endpoint=endpoint, timeout=1500),
)
manager = self._manager()
operation = self._operation(manager, launch)
succeeded = []
timerEvents = []
operation.succeeded.connect(succeeded.append)
QtCore.QTimer.singleShot(0, lambda: timerEvents.append(True))
self.assertEqual(operation.stage, ConnectionStartStage.Pending)
self.assertTrue(waitFor(lambda: bool(succeeded), timeout=0.5))
self.assertEqual(timerEvents, [True])
self.assertEqual(manager.runtimes, [runtime])
self.assertEqual(runtime.startOptions[0], {})
+12
View File
@@ -738,9 +738,11 @@ class EndpointInfoServiceTest(unittest.TestCase):
)
self.assertFalse(hasattr(widget.countryRow, 'flagLabel'))
self.assertFalse(hasattr(widget, 'statusLabel'))
self.assertEqual(widget.bodyLayout.stretch(0), 1)
self.assertEqual(widget.bodyLayout.stretch(1), 2)
self.assertGreaterEqual(widget.minimumHeight(), 360)
self.assertIsInstance(widget.mapWidget.webView, QWebEngineView)
self.assertEqual(widget.mapWidget.webProfile.httpUserAgent(), 'Mozilla/5.0')
self.assertNotIn('Furious', widget.mapWidget.webProfile.httpUserAgent())
@@ -753,6 +755,7 @@ class EndpointInfoServiceTest(unittest.TestCase):
widget.mapWidget._lastWebState['fontPointSize'],
QtGui.QFontInfo(widget.mapWidget.font()).pointSizeF(),
)
themePalette = AppStyleSheet.paletteForTheme(widget.mapWidget._theme)
self.assertEqual(
widget.mapWidget._lastWebState['surfaceColor'],
@@ -770,11 +773,13 @@ class EndpointInfoServiceTest(unittest.TestCase):
widget.mapWidget._lastWebState['mutedTextColor'],
themePalette['muted'],
)
self.assertAlmostEqual(widget.mapWidget._lastWebState['markerLatitude'], 34.05)
self.assertAlmostEqual(
widget.mapWidget._lastWebState['markerLongitude'], -118.24
)
self.assertTrue(scripts)
self.assertEqual(
widget.ipv4Row.valueContainer.objectName(),
'EndpointFieldValueContainer',
@@ -796,6 +801,7 @@ class EndpointInfoServiceTest(unittest.TestCase):
QtCore.Qt.ScrollPhase.ScrollUpdate,
False,
)
QtCore.QCoreApplication.sendEvent(widget.mapWidget.webView, wheelEvent)
self.assertTrue(wheelEvent.isAccepted())
@@ -810,12 +816,14 @@ class EndpointInfoServiceTest(unittest.TestCase):
self.assertIn("document.documentElement.dataset.theme", mapScript)
self.assertIn('--endpoint-attribution-background', html)
self.assertIn('--endpoint-text-muted', html)
self.assertIn('endpoint-loading-overlay', html)
self.assertIn('endpoint-loading-spinner', html)
self.assertIn('width: 16px', html)
self.assertIn('height: 16px', html)
self.assertIn('0.8s linear infinite', html)
self.assertIn('border-right-color: transparent', html)
self.assertIn('--endpoint-font-family', html)
self.assertIn("JSON.stringify(state.fontFamily", mapScript)
self.assertIn('applyLoadingState()', mapScript)
@@ -823,11 +831,13 @@ class EndpointInfoServiceTest(unittest.TestCase):
self.assertIn('.maplibregl-canvas:focus', html)
self.assertIn('outline: none', html)
self.assertNotIn('color-mix(', html)
self.assertIn('const MAP_PALETTES = {', mapScript)
self.assertIn('const createPalette = (themeState)', mapScript)
self.assertIn('const createStyle = (themeState)', mapScript)
self.assertIn('style: createStyle(state)', mapScript)
self.assertIn('const styleKey = ()', mapScript)
self.assertIn("url: 'https://tiles.openfreemap.org/planet'", mapScript)
self.assertIn("glyphs: 'https://tiles.openfreemap.org/fonts/", mapScript)
self.assertIn("'source-layer': 'water'", mapScript)
@@ -843,6 +853,7 @@ class EndpointInfoServiceTest(unittest.TestCase):
self.assertNotIn('tile.openstreetmap.org', html)
self.assertNotIn('opacity: 0.60', html)
self.assertNotIn('opacity: 0.60', mapScript)
self.assertTrue(mapScriptPath.is_file())
self.assertTrue((widget.mapWidget.HtmlPath.parent / 'maplibre-gl.js').is_file())
self.assertTrue(
@@ -897,6 +908,7 @@ class EndpointInfoServiceTest(unittest.TestCase):
)
previousRevision = widget.mapWidget._viewRevision
service.completeRefresh()
processQtEvents()
+9
View File
@@ -643,11 +643,14 @@ class GenerationLogManagerContractTest(unittest.TestCase):
globalCursor = globalBatch.cursor
secondCursor = manager.entriesSince(None, 'other.second').cursor
manager.clear('other.extra')
manager.append('second new', 'other.second')
self.assertTrue(manager.entriesSince(globalCursor).resetRequired)
secondBatch = manager.entriesSince(secondCursor, 'other.second')
self.assertTrue(secondBatch.resetRequired)
self.assertEqual(
tuple(entry.message for entry in secondBatch.entries),
@@ -666,10 +669,12 @@ class GenerationLogManagerContractTest(unittest.TestCase):
batched = self.makeManager(**options)
repeated = self.makeManager(**options)
messages = tuple(f'core-{index}-payload' for index in range(11))
added = []
cleared = []
changed = []
observedSnapshots = []
batched.entryAdded.connect(added.append)
batched.entryAdded.connect(
lambda _entry: observedSnapshots.append(batched.entries())
@@ -698,16 +703,20 @@ class GenerationLogManagerContractTest(unittest.TestCase):
self.assertEqual(batchEntries, repeatedEntries)
self.assertEqual(batched.entries(), repeated.entries())
self.assertEqual(batched.retainedCharacters, repeated.retainedCharacters)
self.assertEqual(added, list(batchEntries))
self.assertTrue(observedSnapshots)
self.assertTrue(
all(snapshot == batched.entries() for snapshot in observedSnapshots)
)
self.assertEqual(len(cleared), 3)
processQtEvents()
self.assertEqual(changed, [batchEntries[-1].sequence])
self.assertLessEqual(batched.entryCount(), batched.maximumEntries)
self.assertLessEqual(batched.retainedCharacters, batched.maximumCharacters)
_assertManagerInvariants(self, batched)
_assertManagerInvariants(self, repeated)
+8
View File
@@ -395,16 +395,20 @@ class ProfileTestServiceTest(unittest.TestCase):
processQtEvents()
first = _ControlledDownloadWorker.instances[0]
active.deleted = True
queued.deleted = True
self._setProfiles((valid,))
manager.reconcileProfiles()
self.assertEqual(first.cancelCount, 1)
self.assertEqual(len(scheduler.queue), 1)
first.publish('stale result')
self.assertEqual(valid.metadata.speed, '')
processQtEvents()
self.assertFalse(isValid(first))
@@ -518,11 +522,13 @@ class ProfileTestServiceTest(unittest.TestCase):
manager.testPing((running, queued, valid))
processQtEvents()
first = pool.started[0]
running.deleted = True
queued.deleted = True
self._setProfiles((valid,))
manager.reconcileProfiles()
self.assertIs(first.job.state, ProfileTestJobState.Cancelled)
@@ -801,6 +807,7 @@ class ProfileTestServiceTest(unittest.TestCase):
)
self._setProfiles((retained, replacement, other, manual))
manager.invalidateSubscriptions({'group-a'}, clearResults=True)
self.assertIs(activeLatency.job.state, ProfileTestJobState.Cancelled)
@@ -824,6 +831,7 @@ class ProfileTestServiceTest(unittest.TestCase):
self.assertEqual(retained.metadata.speed, '')
self.assertEqual(replacement.metadata.latency, '')
self.assertEqual(replacement.metadata.speed, '')
self.assertEqual(other.metadata.latency, 'other latency')
self.assertEqual(other.metadata.speed, 'other speed')
self.assertEqual(manual.metadata.latency, 'manual latency')
+3
View File
@@ -258,6 +258,7 @@ class ServerTableQtInteractionTest(unittest.TestCase):
"""Assert one semantic color invalidation and resulting paint."""
connectionController.state = state
isAdmin.return_value = admin
sourceSpy = QSignalSpy(table.sourceModel.dataChanged)
proxySpy = QSignalSpy(table.proxyModel.dataChanged)
paintCounter.count = 0
@@ -300,12 +301,14 @@ class ServerTableQtInteractionTest(unittest.TestCase):
tuple(int(role) for role in sourceArguments[2]),
expectedRoles,
)
self.assertEqual(proxyArguments[0].row(), proxyIndex.row())
self.assertEqual(proxyArguments[1].row(), proxyIndex.row())
self.assertEqual(
tuple(int(role) for role in proxyArguments[2]),
expectedRoles,
)
self.assertEqual(
table.sourceModel.data(
sourceIndex,
+5
View File
@@ -476,16 +476,19 @@ class SubscriptionManagerTest(TestCase):
manager._synchronizeProfiles = mock.Mock(
side_effect=(RuntimeError('injected failure'), committed)
)
completed = []
committedSubscriptions = []
stateChanges = []
structuralChanges = []
manager.updateCompleted.connect(completed.append)
manager.subscriptionCommitted.connect(committedSubscriptions.append)
manager.subscriptionStateChanged.connect(
lambda uniques: stateChanges.append(tuple(uniques))
)
manager.subscriptionsChanged.connect(lambda: structuralChanges.append(True))
failed = {'unique': 'group-a', 'profiles': ()}
successful = {'unique': 'group-b', 'profiles': ()}
@@ -1058,6 +1061,7 @@ class SubscriptionManagerTest(TestCase):
groupATimer = manager._autoUpdateTimers['group-a']
groupBTimer = manager._autoUpdateTimers['group-b']
groupBTimerId = groupBTimer.timerId()
groupAReply = _AbortableReply()
groupBReply = _AbortableReply()
destroyed = []
@@ -1068,6 +1072,7 @@ class SubscriptionManagerTest(TestCase):
manager._replySubscriptions.update(
{groupAReply: 'group-a', groupBReply: 'group-b'}
)
subscriptions.pop('group-a')
with mock.patch(
+3
View File
@@ -93,15 +93,18 @@ class SubscriptionSynchronizerTest(unittest.TestCase):
self.assertIs(profiles[0], manual)
self.assertIs(profiles[1], retained)
self.assertIs(profiles[-1], other)
self.assertEqual(retained.metadata.profileId, originalId)
self.assertEqual(retained.itemRemark, 'Remote label')
self.assertTrue(retained.metadata.favorite)
self.assertEqual(retained.connection['address'], 'new.example')
self.assertTrue(removed.deleted)
self.assertEqual(
tuple(item.index for item in profiles),
tuple(range(len(profiles))),
)
self.assertEqual(manual.itemSubscription, '')
self.assertFalse(manual.itemSubscriptionManaged)
self.assertEqual(other.connection['address'], 'other.example')
+2
View File
@@ -892,6 +892,7 @@ class QRCodeWindowBehaviorTest(unittest.TestCase):
'',
'socks://three.example:1080#Three',
)
window.show()
processQtEvents()
@@ -901,6 +902,7 @@ class QRCodeWindowBehaviorTest(unittest.TestCase):
self.assertEqual(window.tabWidget.tabToolTip(0), '1 - Profile 1')
self.assertEqual(window.tabWidget.tabToolTip(1), '3 - Profile 3')
firstPage = window.tabWidget.widget(0)
firstPageReference = weakref.ref(firstPage)
firstPageDestroyed = []