mirror of
https://github.com/LorenEteval/Furious.git
synced 2026-09-27 09:27:55 +03:00
Improve logical block spacing in workflows and tests
Signed-off-by: Loren Eteval <loren.eteval@proton.me>
This commit is contained in:
@@ -204,6 +204,7 @@ class DnsResolver(HttpGetManager):
|
||||
f'DNS resolution for \'{domain}\' returned an invalid '
|
||||
f'answer record'
|
||||
)
|
||||
|
||||
resultMap['error'] = True
|
||||
|
||||
continue
|
||||
@@ -224,6 +225,7 @@ class DnsResolver(HttpGetManager):
|
||||
f'DNS resolution for \'{domain}\' returned an unsupported '
|
||||
f'non-address answer record'
|
||||
)
|
||||
|
||||
resultMap['error'] = True
|
||||
|
||||
continue
|
||||
@@ -241,6 +243,7 @@ class DnsResolver(HttpGetManager):
|
||||
f'DNS resolution for \'{domain}\' returned a cyclic '
|
||||
f'reference to \'{reference}\''
|
||||
)
|
||||
|
||||
resultMap['error'] = True
|
||||
|
||||
continue
|
||||
@@ -250,6 +253,7 @@ class DnsResolver(HttpGetManager):
|
||||
f'DNS resolution for \'{domain}\' exceeded the maximum '
|
||||
f'reference depth {self.MAX_REFERENCE_DEPTH}'
|
||||
)
|
||||
|
||||
resultMap['error'] = True
|
||||
|
||||
continue
|
||||
@@ -370,6 +374,7 @@ class DnsResolver(HttpGetManager):
|
||||
logger.error(
|
||||
f'DNS resolution for \'{domain}\' reached timeout {timeout // 1000}s'
|
||||
)
|
||||
|
||||
resultMap['error'] = True
|
||||
|
||||
for networkReply in resultMap['reference']:
|
||||
|
||||
@@ -305,6 +305,7 @@ class _LatencyScheduler(QtCore.QObject):
|
||||
self._publishResult = publishResult
|
||||
self.maxConcurrency = max(int(pingConcurrency), 1)
|
||||
self.tcpingMaxConcurrency = max(int(tcpingConcurrency), 1)
|
||||
|
||||
self.threadPool = threadPool
|
||||
self._ownsThreadPool = self.threadPool is None
|
||||
|
||||
@@ -716,6 +717,7 @@ class _DownloadSpeedWorker(HttpGetManager):
|
||||
self._startInProgress = False
|
||||
self._completionInProgress = False
|
||||
self._pendingCompletionKwargs = None
|
||||
|
||||
self._runtimeLease = None
|
||||
self.networkReply = None
|
||||
|
||||
@@ -1092,6 +1094,7 @@ class _DownloadSpeedScheduler(QtCore.QObject):
|
||||
self.maxConcurrency = max(int(maxConcurrency), 1)
|
||||
self.portRange = portRange
|
||||
self.workerFactory = workerFactory
|
||||
|
||||
self.queue = collections.deque()
|
||||
self.activeJobs = {}
|
||||
self.activePorts = set()
|
||||
|
||||
@@ -472,6 +472,7 @@ class MetricsGraphWidget(QWidget):
|
||||
|
||||
transparentFill = QtGui.QColor(fillColor)
|
||||
transparentFill.setAlpha(0)
|
||||
|
||||
gradient = QtGui.QLinearGradient(
|
||||
chartRect.topLeft(),
|
||||
chartRect.bottomLeft(),
|
||||
|
||||
@@ -684,6 +684,7 @@ class SubscriptionTableView(Mixins.QTranslatable, AppQTableView):
|
||||
def _restoreGroupSelection(self, selectedUniques, currentUnique):
|
||||
"""Restore logical selection, current item, and keyboard focus by ID."""
|
||||
rows = {unique: row for row, unique in enumerate(Storage.UserSubs())}
|
||||
|
||||
selection = self.selectionModel()
|
||||
selection.clearSelection()
|
||||
flags = (
|
||||
@@ -749,6 +750,7 @@ class SubscriptionTableView(Mixins.QTranslatable, AppQTableView):
|
||||
value['sortOrder'] = order
|
||||
|
||||
self.flushAll()
|
||||
|
||||
self.groupsChanged.emit()
|
||||
else:
|
||||
# Do not delete
|
||||
@@ -789,6 +791,7 @@ class SubscriptionTableView(Mixins.QTranslatable, AppQTableView):
|
||||
changed = Storage.moveSubscriptionGroups(selectedUniques, position)
|
||||
|
||||
self.sourceModel.layoutChanged.emit()
|
||||
|
||||
self._restoreGroupSelection(selectedUniques, currentUnique)
|
||||
|
||||
if changed:
|
||||
|
||||
@@ -729,6 +729,7 @@ class HomePage(Mixins.QTranslatable, QMainWindow):
|
||||
self.connectionStatus = ConnectionStatusWidget(parent=self)
|
||||
self.networkState = self.connectionStatus.networkState
|
||||
self.trafficStats = self.connectionStatus.trafficStats
|
||||
|
||||
self.trafficStatsManager = TrafficStatsManager(parent=self)
|
||||
self.trafficStatsManager.speedChanged.connect(self.trafficStats.setSpeeds)
|
||||
self.trafficStatsManager.usageChanged.connect(self.trafficStats.setUsage)
|
||||
@@ -740,6 +741,7 @@ class HomePage(Mixins.QTranslatable, QMainWindow):
|
||||
|
||||
self._widget = QWidget()
|
||||
self._widget.setObjectName('HomePageContent')
|
||||
|
||||
self._layout = QVBoxLayout(self._widget)
|
||||
self._layout.setContentsMargins(20, 18, 20, 20)
|
||||
self._layout.setSpacing(12)
|
||||
@@ -861,6 +863,7 @@ class HomePage(Mixins.QTranslatable, QMainWindow):
|
||||
self.subscriptionFilterComboBox.currentIndexChanged.connect(
|
||||
self.handleSubscriptionFilterChanged
|
||||
)
|
||||
|
||||
self.systemProxyComboBox.currentIndexChanged.connect(
|
||||
self.handleSystemProxyModeChanged
|
||||
)
|
||||
|
||||
@@ -78,6 +78,7 @@ class MainWindow(AppQMainWindow):
|
||||
self.homePage.userServersQTableWidget,
|
||||
parent=self.navigationView,
|
||||
)
|
||||
|
||||
self.metricsHistory = MetricsHistory(parent=self)
|
||||
self.homePage.trafficStatsManager.sampleChanged.connect(
|
||||
self.metricsHistory.recordTrafficSample
|
||||
@@ -89,6 +90,7 @@ class MainWindow(AppQMainWindow):
|
||||
self.metricsHistory,
|
||||
parent=self.navigationView,
|
||||
)
|
||||
|
||||
self.logPage = AppLogPage()
|
||||
self.settingsPage = SettingsPage(
|
||||
tunSettingsDialogFactory=self.homePage.getGuiTUNSettings,
|
||||
@@ -132,8 +134,10 @@ class MainWindow(AppQMainWindow):
|
||||
'Subscription',
|
||||
'star.svg',
|
||||
)
|
||||
|
||||
self.pluginNavigationManager = PluginNavigationManager()
|
||||
self.pluginNavigationManager.registerPages(self.navigationView)
|
||||
|
||||
self.navigationView.addPage(
|
||||
'metrics',
|
||||
self.metricsPage,
|
||||
@@ -147,6 +151,7 @@ class MainWindow(AppQMainWindow):
|
||||
'gear-wide-connected.svg',
|
||||
placement='bottom',
|
||||
)
|
||||
|
||||
self.setCentralWidget(self.navigationView)
|
||||
|
||||
# Preserve the established application-facing server-management API.
|
||||
|
||||
@@ -242,6 +242,7 @@ class TextEditorWindow(AppQMainWindow):
|
||||
icon=bootstrapIcon('eye.svg'),
|
||||
popupMenu=self.viewMenu,
|
||||
)
|
||||
|
||||
self.closeWindowButton = AppQPushButton(
|
||||
_('Close Window'),
|
||||
icon=bootstrapIcon('window-x.svg'),
|
||||
|
||||
@@ -244,8 +244,10 @@ class ConnectionStartupAsyncTest(TestCase):
|
||||
server = self._server()
|
||||
port = server.serverPort()
|
||||
server.close()
|
||||
|
||||
runtime = _Runtime()
|
||||
manager = self._manager()
|
||||
|
||||
operation = self._operation(
|
||||
manager,
|
||||
PreparedRuntime(
|
||||
@@ -257,10 +259,12 @@ class ConnectionStartupAsyncTest(TestCase):
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
failures = []
|
||||
operation.failed.connect(lambda *_args: failures.append(_args))
|
||||
|
||||
self.assertTrue(waitFor(lambda: bool(failures)))
|
||||
|
||||
self.assertEqual(failures[0][1], 'Failed to start core')
|
||||
self.assertEqual(failures[0][2], 'core readiness check timed out')
|
||||
self.assertEqual(manager.lastStartError, 'Failed to start core')
|
||||
@@ -272,6 +276,7 @@ class ConnectionStartupAsyncTest(TestCase):
|
||||
"""Let the runtime's typed exit remain the sole terminal authority."""
|
||||
runtime = _Runtime()
|
||||
manager = self._manager()
|
||||
|
||||
operation = self._operation(
|
||||
manager,
|
||||
PreparedRuntime(
|
||||
@@ -283,6 +288,7 @@ class ConnectionStartupAsyncTest(TestCase):
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
failures = []
|
||||
operation.failed.connect(lambda *_args: failures.append(_args))
|
||||
|
||||
@@ -291,6 +297,7 @@ class ConnectionStartupAsyncTest(TestCase):
|
||||
|
||||
self.assertTrue(waitFor(lambda: bool(failures)))
|
||||
processQtEvents(5)
|
||||
|
||||
self.assertEqual(len(failures), 1)
|
||||
self.assertIs(failures[0][0], operation)
|
||||
self.assertEqual(failures[0][1], 'Invalid server configuration')
|
||||
@@ -307,6 +314,7 @@ class ConnectionStartupAsyncTest(TestCase):
|
||||
"""Preserve code 23 when timeout delivery races a queued runtime event."""
|
||||
runtime = _Runtime()
|
||||
manager = self._manager()
|
||||
|
||||
operation = self._operation(
|
||||
manager,
|
||||
PreparedRuntime(
|
||||
@@ -318,6 +326,7 @@ class ConnectionStartupAsyncTest(TestCase):
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
failures = []
|
||||
operation.failed.connect(lambda *_args: failures.append(_args))
|
||||
|
||||
@@ -327,6 +336,7 @@ class ConnectionStartupAsyncTest(TestCase):
|
||||
|
||||
self.assertTrue(waitFor(lambda: bool(failures)))
|
||||
processQtEvents(5)
|
||||
|
||||
self.assertEqual(len(failures), 1)
|
||||
self.assertEqual(failures[0][1], 'Invalid server configuration')
|
||||
self.assertEqual(
|
||||
@@ -342,6 +352,7 @@ class ConnectionStartupAsyncTest(TestCase):
|
||||
"""Let process termination own the terminal result before timeout."""
|
||||
runtime = _Runtime()
|
||||
manager = self._manager()
|
||||
|
||||
operation = self._operation(
|
||||
manager,
|
||||
PreparedRuntime(
|
||||
@@ -352,6 +363,7 @@ class ConnectionStartupAsyncTest(TestCase):
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
failures = []
|
||||
operation.failed.connect(lambda *_args: failures.append(_args))
|
||||
|
||||
@@ -360,6 +372,7 @@ class ConnectionStartupAsyncTest(TestCase):
|
||||
|
||||
self.assertTrue(waitFor(lambda: bool(failures)))
|
||||
processQtEvents(5)
|
||||
|
||||
self.assertEqual(len(failures), 1)
|
||||
self.assertEqual(failures[0][1], 'Core terminated unexpectedly')
|
||||
self.assertEqual(
|
||||
@@ -404,8 +417,10 @@ class ConnectionStartupAsyncTest(TestCase):
|
||||
'Global',
|
||||
deepcopy=False,
|
||||
)
|
||||
|
||||
cancelled = []
|
||||
firstOperation.cancelled.connect(cancelled.append)
|
||||
|
||||
processQtEvents()
|
||||
|
||||
secondOperation = manager.startAsync(
|
||||
@@ -413,6 +428,7 @@ class ConnectionStartupAsyncTest(TestCase):
|
||||
'Global',
|
||||
deepcopy=False,
|
||||
)
|
||||
|
||||
succeeded = []
|
||||
secondOperation.succeeded.connect(succeeded.append)
|
||||
|
||||
@@ -488,13 +504,16 @@ class ConnectionStartupAsyncTest(TestCase):
|
||||
'example.test',
|
||||
timeout=200,
|
||||
)
|
||||
|
||||
results = []
|
||||
operation.finished.connect(
|
||||
lambda error, addresses: results.append((error, addresses))
|
||||
)
|
||||
|
||||
operation.start()
|
||||
|
||||
self.assertTrue(waitFor(lambda: bool(results)))
|
||||
|
||||
self.assertEqual(results, [(False, ['192.0.2.10'])])
|
||||
|
||||
cancelled = DnsResolutionOperation(
|
||||
@@ -502,10 +521,12 @@ class ConnectionStartupAsyncTest(TestCase):
|
||||
'cancelled.test',
|
||||
timeout=200,
|
||||
)
|
||||
|
||||
staleResults = []
|
||||
cancelled.finished.connect(
|
||||
lambda error, addresses: staleResults.append((error, addresses))
|
||||
)
|
||||
|
||||
cancelled.start()
|
||||
cancelled.cancel()
|
||||
processQtEvents(5)
|
||||
|
||||
@@ -185,6 +185,7 @@ class ConnectionControllerTest(unittest.TestCase):
|
||||
coreManager=core,
|
||||
updatesManager=FixtureUpdatesManager(),
|
||||
)
|
||||
|
||||
states = []
|
||||
interactions = []
|
||||
controller.stateChanged.connect(states.append)
|
||||
@@ -200,6 +201,7 @@ class ConnectionControllerTest(unittest.TestCase):
|
||||
mock.patch.object(controller, '_runPostConnectTasksOnce'),
|
||||
):
|
||||
self.assertTrue(controller.startConnection(self.profile))
|
||||
|
||||
self.assertEqual(controller.state, ConnectionState.Connected)
|
||||
self.assertIs(controller.activeProfile, self.profile)
|
||||
self.assertEqual(
|
||||
@@ -216,6 +218,7 @@ class ConnectionControllerTest(unittest.TestCase):
|
||||
self.assertEqual(controller.state, ConnectionState.Disconnected)
|
||||
self.assertIsNone(controller.activeProfile)
|
||||
self.assertEqual(core.stopCalls, 1)
|
||||
|
||||
self.assertEqual(
|
||||
states,
|
||||
[
|
||||
@@ -240,6 +243,7 @@ class ConnectionControllerTest(unittest.TestCase):
|
||||
coreManager=core,
|
||||
updatesManager=FixtureUpdatesManager(),
|
||||
)
|
||||
|
||||
errors = []
|
||||
notifications = []
|
||||
controller.errorOccurred.connect(errors.append)
|
||||
@@ -258,6 +262,7 @@ class ConnectionControllerTest(unittest.TestCase):
|
||||
AppSettings.get('Connect'),
|
||||
AppBinarySettings.OFF,
|
||||
)
|
||||
|
||||
self.assertEqual(len(errors), 1)
|
||||
self.assertIn('fixture launch failure', errors[0].message)
|
||||
self.assertEqual(notifications, [])
|
||||
@@ -272,9 +277,11 @@ class ConnectionControllerTest(unittest.TestCase):
|
||||
coreManager=core,
|
||||
updatesManager=FixtureUpdatesManager(),
|
||||
)
|
||||
|
||||
events = []
|
||||
controller.stateChanged.connect(lambda state: events.append(state.value))
|
||||
controller.errorOccurred.connect(lambda error: events.append(error.message))
|
||||
|
||||
process = mock.Mock()
|
||||
process.name.return_value = 'Fixture Core'
|
||||
|
||||
@@ -384,6 +391,7 @@ class ConnectionControllerTest(unittest.TestCase):
|
||||
mock.patch.object(controller, '_runPostConnectTasksOnce'),
|
||||
):
|
||||
self.assertTrue(controller.startConnection(self.profile))
|
||||
|
||||
self.assertTrue(controller.isConnecting())
|
||||
proxySet.assert_not_called()
|
||||
|
||||
@@ -393,6 +401,7 @@ class ConnectionControllerTest(unittest.TestCase):
|
||||
|
||||
self.assertTrue(controller.isConnected())
|
||||
proxySet.assert_called_once()
|
||||
|
||||
self.assertTrue(controller.startDisconnection())
|
||||
|
||||
controller.deleteLater()
|
||||
@@ -405,6 +414,7 @@ class ConnectionControllerTest(unittest.TestCase):
|
||||
coreManager=core,
|
||||
updatesManager=FixtureUpdatesManager(),
|
||||
)
|
||||
|
||||
errors = []
|
||||
controller.errorOccurred.connect(errors.append)
|
||||
|
||||
@@ -416,6 +426,7 @@ class ConnectionControllerTest(unittest.TestCase):
|
||||
),
|
||||
):
|
||||
self.assertTrue(controller.startConnection(self.profile))
|
||||
|
||||
operation = core.operations[0][0]
|
||||
operation.fail(
|
||||
'Invalid server configuration',
|
||||
@@ -482,17 +493,21 @@ class ConnectionControllerTest(unittest.TestCase):
|
||||
):
|
||||
self.assertTrue(controller.startConnection(self.profile))
|
||||
first = core.operations[0][0]
|
||||
|
||||
self.assertTrue(controller.startReconnection())
|
||||
second = core.operations[1][0]
|
||||
|
||||
first.succeed()
|
||||
|
||||
self.assertTrue(controller.isConnecting())
|
||||
proxySet.assert_not_called()
|
||||
|
||||
core.runtimes.append(object())
|
||||
second.succeed()
|
||||
|
||||
self.assertTrue(controller.isConnected())
|
||||
proxySet.assert_called_once()
|
||||
|
||||
controller.startDisconnection()
|
||||
|
||||
self.assertEqual(core.cancelCalls, [first])
|
||||
|
||||
@@ -456,17 +456,20 @@ class GenerationLogManagerContractTest(unittest.TestCase):
|
||||
maximumCharacters=size * 30 + 100,
|
||||
autoClearMaximumEntries=size,
|
||||
)
|
||||
|
||||
for index in range(size):
|
||||
manager.append(f'core {index}', CORE_LOG_CATEGORY)
|
||||
manager.append(f'other {index}', 'other.extra')
|
||||
|
||||
observed = []
|
||||
|
||||
for generation in manager._activeGenerationsLocked():
|
||||
index = _ObservedEntries(generation.entries)
|
||||
generation.entries = index
|
||||
observed.append(index)
|
||||
|
||||
manager.append('trigger', CORE_LOG_CATEGORY)
|
||||
|
||||
self.assertEqual(sum(item.iterations for item in observed), 0)
|
||||
self.assertEqual(sum(item.deletions for item in observed), 0)
|
||||
self.assertEqual(sum(item.oldestRemovals for item in observed), 0)
|
||||
@@ -475,20 +478,26 @@ class GenerationLogManagerContractTest(unittest.TestCase):
|
||||
|
||||
for index in range(size):
|
||||
manager.append(f'runtime {index}', 'runtime.extra')
|
||||
|
||||
runtime = manager._runtimeGeneration
|
||||
watchedRuntime = _ObservedEntries(runtime.entries)
|
||||
runtime.entries = watchedRuntime
|
||||
|
||||
manager.clear(runtimeOnly=True)
|
||||
|
||||
self.assertEqual(watchedRuntime.iterations, 0)
|
||||
self.assertEqual(watchedRuntime.oldestRemovals, 0)
|
||||
|
||||
manager.append('application', APPLICATION_LOG_CATEGORY)
|
||||
watched = []
|
||||
|
||||
for generation in manager._activeGenerationsLocked():
|
||||
index = _ObservedEntries(generation.entries)
|
||||
generation.entries = index
|
||||
watched.append(index)
|
||||
|
||||
manager.clear()
|
||||
|
||||
self.assertEqual(sum(item.iterations for item in watched), 0)
|
||||
self.assertEqual(sum(item.oldestRemovals for item in watched), 0)
|
||||
_assertManagerInvariants(self, manager)
|
||||
@@ -955,18 +964,23 @@ class GenerationLogManagerContractTest(unittest.TestCase):
|
||||
with self.subTest(backlog=backlog, budget=budget):
|
||||
manager = self.makeManager(maximumEntries=200)
|
||||
manager.RetiredCleanupBudget = budget
|
||||
|
||||
for index in range(backlog):
|
||||
manager.append(str(index), CORE_LOG_CATEGORY)
|
||||
if index in (1, 4):
|
||||
manager.clear(runtimeOnly=True)
|
||||
|
||||
manager.clear(runtimeOnly=True)
|
||||
|
||||
before = manager.retiredEntryCount
|
||||
identifiers = tuple(
|
||||
getattr(batch, 'identifier', None)
|
||||
for batch in manager._retiredBatches
|
||||
)
|
||||
|
||||
with manager._lock:
|
||||
released = manager._cleanupRetiredLocked()
|
||||
|
||||
self.assertEqual(released, min(budget, before))
|
||||
self.assertEqual(manager.retiredEntryCount, before - released)
|
||||
if manager._retiredBatches and identifiers:
|
||||
@@ -974,13 +988,16 @@ class GenerationLogManagerContractTest(unittest.TestCase):
|
||||
getattr(manager._retiredBatches[0], 'identifier', None),
|
||||
identifiers,
|
||||
)
|
||||
|
||||
_assertManagerInvariants(self, manager)
|
||||
|
||||
manager = self.makeManager()
|
||||
manager.append('retired', CORE_LOG_CATEGORY)
|
||||
manager.clear(runtimeOnly=True)
|
||||
|
||||
with manager._lock:
|
||||
self.assertEqual(manager._cleanupRetiredLocked(0), 0)
|
||||
|
||||
manager.RetiredCleanupBudget = 0
|
||||
with manager._lock:
|
||||
self.assertEqual(manager._cleanupRetiredLocked(), 1)
|
||||
@@ -989,25 +1006,32 @@ class GenerationLogManagerContractTest(unittest.TestCase):
|
||||
"""Finish each older clear-all stream before touching the next one."""
|
||||
manager = self.makeManager(autoClearEnabled=False)
|
||||
manager.RetiredCleanupBudget = 1
|
||||
|
||||
manager.append('application 1', APPLICATION_LOG_CATEGORY)
|
||||
manager.append('application 2', APPLICATION_LOG_CATEGORY)
|
||||
manager.append('runtime 1', CORE_LOG_CATEGORY)
|
||||
manager.append('runtime 2', CORE_LOG_CATEGORY)
|
||||
manager.append('other 1', 'other.extra')
|
||||
manager.append('other 2', 'other.extra')
|
||||
|
||||
expectedIdentifiers = tuple(
|
||||
generation.identifier for generation in manager._activeGenerationsLocked()
|
||||
)
|
||||
|
||||
manager.clear()
|
||||
|
||||
self.assertEqual(
|
||||
tuple(batch.identifier for batch in manager._retiredBatches),
|
||||
expectedIdentifiers,
|
||||
)
|
||||
|
||||
observedHeads = []
|
||||
|
||||
while manager.retiredEntryCount:
|
||||
observedHeads.append(manager._retiredBatches[0].identifier)
|
||||
with manager._lock:
|
||||
self.assertEqual(manager._cleanupRetiredLocked(), 1)
|
||||
|
||||
self.assertEqual(
|
||||
observedHeads,
|
||||
[
|
||||
@@ -1108,6 +1132,7 @@ class GenerationLogManagerContractTest(unittest.TestCase):
|
||||
autoClearEnabled=False,
|
||||
)
|
||||
categoryIds = []
|
||||
|
||||
for index in range(100):
|
||||
category = manager.registerCategory(
|
||||
LogCategory(
|
||||
@@ -1118,17 +1143,23 @@ class GenerationLogManagerContractTest(unittest.TestCase):
|
||||
)
|
||||
)
|
||||
categoryIds.append(category.id)
|
||||
|
||||
for index in range(2_000):
|
||||
manager.append(str(index), categoryIds[index % len(categoryIds)])
|
||||
|
||||
for categoryId in (categoryIds[0], categoryIds[-1], categoryIds[51]):
|
||||
expected = tuple(
|
||||
entry for entry in manager.entries() if entry.categoryId != categoryId
|
||||
)
|
||||
|
||||
manager.clear(categoryId)
|
||||
|
||||
self.assertEqual(manager.entries(), expected)
|
||||
_assertManagerInvariants(self, manager)
|
||||
|
||||
duplicate = manager.category(categoryIds[1])
|
||||
self.assertIs(manager.registerCategory(duplicate), duplicate)
|
||||
|
||||
with self.assertRaises(ValueError):
|
||||
manager.registerCategory(LogCategory(categoryIds[1], 'Different'))
|
||||
|
||||
@@ -1136,8 +1167,10 @@ class GenerationLogManagerContractTest(unittest.TestCase):
|
||||
"""Account normalized storage and preserve state after bad input."""
|
||||
manager = self.makeManager(maximumEntryCharacters=32)
|
||||
messages = ('', 'x', 'line\r\n', '😀é', 'a\0b', 'n\n' * 20, 'z' * 33)
|
||||
|
||||
for message in messages:
|
||||
entry = manager.append(message)
|
||||
|
||||
self.assertLessEqual(len(entry.message), 32)
|
||||
_assertManagerInvariants(self, manager)
|
||||
|
||||
@@ -1146,16 +1179,22 @@ class GenerationLogManagerContractTest(unittest.TestCase):
|
||||
raise RuntimeError('conversion failed')
|
||||
|
||||
before = manager.entries()
|
||||
|
||||
with self.assertRaises(RuntimeError):
|
||||
manager.append(RaisingString())
|
||||
|
||||
with self.assertRaises(RuntimeError):
|
||||
manager.appendMany(('must not commit', RaisingString(), 'unreached'))
|
||||
|
||||
with self.assertRaises(TypeError):
|
||||
manager.append('bad timestamp', timestamp='not a datetime')
|
||||
|
||||
with self.assertRaises(KeyError):
|
||||
manager.append('unknown', 'missing')
|
||||
|
||||
with self.assertRaises(ValueError):
|
||||
manager.clear(CORE_LOG_CATEGORY, runtimeOnly=True)
|
||||
|
||||
self.assertEqual(manager.entries(), before)
|
||||
_assertManagerInvariants(self, manager)
|
||||
|
||||
@@ -1259,6 +1298,7 @@ class GenerationLogManagerContractTest(unittest.TestCase):
|
||||
errors = []
|
||||
returnedSequences = []
|
||||
sequenceLock = threading.Lock()
|
||||
|
||||
# Producers plus the reader and mutator are the complete
|
||||
# participant set. Keeping the exact cardinality here makes a
|
||||
# failed synchronization a real deadlock signal rather than a
|
||||
@@ -1267,8 +1307,10 @@ class GenerationLogManagerContractTest(unittest.TestCase):
|
||||
|
||||
def producer(workerIndex):
|
||||
randomizer = random.Random(10_000 + workerIndex)
|
||||
|
||||
try:
|
||||
start.wait(5)
|
||||
|
||||
for index in range(300):
|
||||
categoryId = randomizer.choice(
|
||||
(
|
||||
@@ -1280,6 +1322,7 @@ class GenerationLogManagerContractTest(unittest.TestCase):
|
||||
)
|
||||
)
|
||||
entry = manager.append(f'{workerIndex}:{index}', categoryId)
|
||||
|
||||
with sequenceLock:
|
||||
returnedSequences.append(entry.sequence)
|
||||
except Exception as error:
|
||||
@@ -1289,13 +1332,17 @@ class GenerationLogManagerContractTest(unittest.TestCase):
|
||||
try:
|
||||
start.wait(5)
|
||||
cursor = None
|
||||
|
||||
for _index in range(500):
|
||||
entries = manager.entries()
|
||||
|
||||
self.assertEqual(
|
||||
tuple(item.sequence for item in entries),
|
||||
tuple(sorted(item.sequence for item in entries)),
|
||||
)
|
||||
|
||||
batch = manager.entriesSince(cursor, CORE_LOG_CATEGORY)
|
||||
|
||||
self.assertEqual(
|
||||
tuple(item.sequence for item in batch.entries),
|
||||
tuple(sorted(item.sequence for item in batch.entries)),
|
||||
@@ -1316,10 +1363,13 @@ class GenerationLogManagerContractTest(unittest.TestCase):
|
||||
|
||||
def mutator():
|
||||
randomizer = random.Random(77)
|
||||
|
||||
try:
|
||||
start.wait(5)
|
||||
|
||||
for index in range(180):
|
||||
choice = randomizer.randrange(4)
|
||||
|
||||
if choice == 0:
|
||||
manager.clear(runtimeOnly=True)
|
||||
elif choice == 1:
|
||||
@@ -1338,11 +1388,14 @@ class GenerationLogManagerContractTest(unittest.TestCase):
|
||||
threads.extend(
|
||||
(threading.Thread(target=reader), threading.Thread(target=mutator))
|
||||
)
|
||||
|
||||
for thread in threads:
|
||||
thread.start()
|
||||
|
||||
for thread in threads:
|
||||
thread.join(20)
|
||||
self.assertFalse(thread.is_alive(), 'possible LogManager deadlock')
|
||||
|
||||
self.assertEqual(errors, [])
|
||||
self.assertEqual(len(returnedSequences), producerCount * 300)
|
||||
self.assertEqual(len(set(returnedSequences)), len(returnedSequences))
|
||||
|
||||
@@ -430,6 +430,7 @@ class ProfileTestServiceTest(unittest.TestCase):
|
||||
profiles = [
|
||||
self._profile(f'profile-{index}', f'{index}.example') for index in range(4)
|
||||
]
|
||||
|
||||
manager = self._manager(profiles, controlledDownloads=False)
|
||||
scheduler = manager._concurrentDownloadScheduler
|
||||
scheduler.maxConcurrency = len(profiles)
|
||||
@@ -444,6 +445,7 @@ class ProfileTestServiceTest(unittest.TestCase):
|
||||
return worker
|
||||
|
||||
scheduler.workerFactory = workerFactory
|
||||
|
||||
registry = mock.Mock()
|
||||
registry.prepareDownloadTest.side_effect = lambda profile, _port: profile
|
||||
registry.createCoreRuntime.side_effect = (
|
||||
@@ -485,6 +487,7 @@ class ProfileTestServiceTest(unittest.TestCase):
|
||||
active = self._profile('active', 'active.example')
|
||||
queued = self._profile('queued', 'queued.example')
|
||||
valid = self._profile('valid', 'valid.example')
|
||||
|
||||
manager = self._manager((active, queued, valid))
|
||||
scheduler = manager._serialDownloadScheduler
|
||||
|
||||
@@ -512,6 +515,7 @@ class ProfileTestServiceTest(unittest.TestCase):
|
||||
processQtEvents()
|
||||
|
||||
self.assertFalse(isValid(first))
|
||||
|
||||
second = _ControlledDownloadWorker.instances[1]
|
||||
self.assertEqual(
|
||||
second.profile.metadata.profileId,
|
||||
@@ -913,6 +917,7 @@ class ProfileTestServiceTest(unittest.TestCase):
|
||||
self.assertIs(activeLatency.job.state, ProfileTestJobState.Cancelled)
|
||||
self.assertEqual(serialWorker.cancelCount, 1)
|
||||
self.assertEqual(concurrentWorker.cancelCount, 1)
|
||||
|
||||
self.assertTrue(
|
||||
all(
|
||||
job.target.subscriptionSource == 'group-b'
|
||||
|
||||
@@ -504,6 +504,7 @@ class SubscriptionManagerTest(TestCase):
|
||||
self.assertEqual(completed[0].successful[0]['unique'], 'group-b')
|
||||
self.assertEqual(completed[0].failed[0]['unique'], 'group-a')
|
||||
self.assertIn('injected failure', completed[0].failed[0]['error'])
|
||||
|
||||
self.assertEqual(committedSubscriptions, ['group-b'])
|
||||
self.assertEqual(stateChanges, [('group-b', 'group-a')])
|
||||
self.assertEqual(structuralChanges, [True])
|
||||
@@ -704,39 +705,47 @@ class SubscriptionManagerTest(TestCase):
|
||||
) as lifecycleLog,
|
||||
):
|
||||
manager.configureAutoUpdate('group-a')
|
||||
|
||||
lifecycleLog.assert_not_called()
|
||||
|
||||
subscriptions['group-a']['autoupdate'] = 'Every 5 mins'
|
||||
manager.configureAutoUpdate('group-a')
|
||||
|
||||
self.assertTrue(timer.isActive())
|
||||
self.assertEqual(timer.interval(), 5 * 60 * 1000)
|
||||
self.assertIn('start auto update job', lifecycleLog.call_args.args[0])
|
||||
|
||||
activeTimerId = timer.timerId()
|
||||
manager.configureAutoUpdate('group-a')
|
||||
|
||||
self.assertEqual(timer.timerId(), activeTimerId)
|
||||
self.assertEqual(lifecycleLog.call_count, 1)
|
||||
|
||||
subscriptions['group-a']['autoupdate'] = 'Every 10 mins'
|
||||
manager.configureAutoUpdate('group-a')
|
||||
|
||||
self.assertIs(manager._autoUpdateTimers['group-a'], timer)
|
||||
self.assertEqual(timer.interval(), 10 * 60 * 1000)
|
||||
self.assertIn('reschedule auto update job', lifecycleLog.call_args.args[0])
|
||||
|
||||
subscriptions['group-a']['enabled'] = False
|
||||
manager.configureAutoUpdate('group-a')
|
||||
|
||||
self.assertFalse(timer.isActive())
|
||||
self.assertIn('stop auto update job', lifecycleLog.call_args.args[0])
|
||||
|
||||
manager.configureAutoUpdate('group-a')
|
||||
|
||||
self.assertEqual(lifecycleLog.call_count, 3)
|
||||
|
||||
subscriptions['group-a']['enabled'] = True
|
||||
manager.configureAutoUpdate('group-a')
|
||||
|
||||
self.assertTrue(timer.isActive())
|
||||
self.assertIn('start auto update job', lifecycleLog.call_args.args[0])
|
||||
|
||||
self.assertEqual(lifecycleLog.call_count, 4)
|
||||
|
||||
manager.deleteLater()
|
||||
|
||||
def testUnrelatedSubscriptionEditDoesNotRestartItsTimer(self):
|
||||
@@ -1064,6 +1073,7 @@ class SubscriptionManagerTest(TestCase):
|
||||
groupBReply = _AbortableReply()
|
||||
destroyed = []
|
||||
groupATimer.destroyed.connect(lambda *_args: destroyed.append(True))
|
||||
|
||||
manager._activeReplies.update(
|
||||
{groupAReply: groupAReply, groupBReply: groupBReply}
|
||||
)
|
||||
@@ -1334,6 +1344,7 @@ class SubscriptionManagerTest(TestCase):
|
||||
[],
|
||||
[],
|
||||
)
|
||||
|
||||
completed = []
|
||||
structural = []
|
||||
manager.updateCompleted.connect(completed.append)
|
||||
|
||||
Reference in New Issue
Block a user