Improve logical block spacing in workflows and tests

Signed-off-by: Loren Eteval <loren.eteval@proton.me>
This commit is contained in:
Loren Eteval
2026-09-18 16:53:40 +08:00
parent e416a89c35
commit 330e501eb6
12 changed files with 126 additions and 0 deletions
+5
View File
@@ -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']:
+3
View File
@@ -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()
+1
View File
@@ -472,6 +472,7 @@ class MetricsGraphWidget(QWidget):
transparentFill = QtGui.QColor(fillColor)
transparentFill.setAlpha(0)
gradient = QtGui.QLinearGradient(
chartRect.topLeft(),
chartRect.bottomLeft(),
+3
View File
@@ -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:
+3
View File
@@ -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
)
+5
View File
@@ -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.
+1
View File
@@ -242,6 +242,7 @@ class TextEditorWindow(AppQMainWindow):
icon=bootstrapIcon('eye.svg'),
popupMenu=self.viewMenu,
)
self.closeWindowButton = AppQPushButton(
_('Close Window'),
icon=bootstrapIcon('window-x.svg'),
+21
View File
@@ -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)
+15
View File
@@ -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])
+53
View File
@@ -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))
+5
View File
@@ -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'
+11
View File
@@ -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)