mirror of
https://github.com/LorenEteval/Furious.git
synced 2026-10-14 10:09:03 +03:00
Improve workflow and test readability
Signed-off-by: Loren Eteval <loren.eteval@proton.me>
This commit is contained in:
@@ -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:
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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()),
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -71,6 +71,7 @@ class RuntimeEventRouter(QtCore.QObject):
|
||||
self._attemptMethod = ''
|
||||
self._committedCallback = None
|
||||
self._terminalDelivered = False
|
||||
|
||||
self._publishedConnection = connectWeakly(
|
||||
self._published,
|
||||
self,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 = []
|
||||
|
||||
@@ -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()):
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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], {})
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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 = []
|
||||
|
||||
Reference in New Issue
Block a user