cyclo-manager 1.1.0.dev4__tar.gz → 1.1.0.dev5__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {cyclo_manager-1.1.0.dev4 → cyclo_manager-1.1.0.dev5}/PKG-INFO +2 -2
- {cyclo_manager-1.1.0.dev4 → cyclo_manager-1.1.0.dev5}/README.md +1 -0
- {cyclo_manager-1.1.0.dev4 → cyclo_manager-1.1.0.dev5}/cyclo_host_agent/routers/repos.py +41 -20
- {cyclo_manager-1.1.0.dev4 → cyclo_manager-1.1.0.dev5}/cyclo_manager.egg-info/PKG-INFO +2 -2
- {cyclo_manager-1.1.0.dev4 → cyclo_manager-1.1.0.dev5}/cyclo_manager.egg-info/SOURCES.txt +1 -2
- {cyclo_manager-1.1.0.dev4 → cyclo_manager-1.1.0.dev5}/cyclo_manager.egg-info/requires.txt +0 -1
- {cyclo_manager-1.1.0.dev4 → cyclo_manager-1.1.0.dev5}/pyproject.toml +1 -2
- cyclo_manager-1.1.0.dev4/tests/test_cpu_usage.py +0 -169
- {cyclo_manager-1.1.0.dev4 → cyclo_manager-1.1.0.dev5}/cyclo_host_agent/__init__.py +0 -0
- {cyclo_manager-1.1.0.dev4 → cyclo_manager-1.1.0.dev5}/cyclo_host_agent/cpu_usage.py +0 -0
- {cyclo_manager-1.1.0.dev4 → cyclo_manager-1.1.0.dev5}/cyclo_host_agent/main.py +0 -0
- {cyclo_manager-1.1.0.dev4 → cyclo_manager-1.1.0.dev5}/cyclo_host_agent/models.py +0 -0
- {cyclo_manager-1.1.0.dev4 → cyclo_manager-1.1.0.dev5}/cyclo_host_agent/routers/__init__.py +0 -0
- {cyclo_manager-1.1.0.dev4 → cyclo_manager-1.1.0.dev5}/cyclo_host_agent/routers/files.py +0 -0
- {cyclo_manager-1.1.0.dev4 → cyclo_manager-1.1.0.dev5}/cyclo_host_agent/routers/system_stats.py +0 -0
- {cyclo_manager-1.1.0.dev4 → cyclo_manager-1.1.0.dev5}/cyclo_host_agent/routers/update.py +0 -0
- {cyclo_manager-1.1.0.dev4 → cyclo_manager-1.1.0.dev5}/cyclo_manager.egg-info/dependency_links.txt +0 -0
- {cyclo_manager-1.1.0.dev4 → cyclo_manager-1.1.0.dev5}/cyclo_manager.egg-info/entry_points.txt +0 -0
- {cyclo_manager-1.1.0.dev4 → cyclo_manager-1.1.0.dev5}/cyclo_manager.egg-info/top_level.txt +0 -0
- {cyclo_manager-1.1.0.dev4 → cyclo_manager-1.1.0.dev5}/cyclo_manager_cli/__init__.py +0 -0
- {cyclo_manager-1.1.0.dev4 → cyclo_manager-1.1.0.dev5}/cyclo_manager_cli/cli.py +0 -0
- {cyclo_manager-1.1.0.dev4 → cyclo_manager-1.1.0.dev5}/cyclo_manager_cli/config/config.yml +0 -0
- {cyclo_manager-1.1.0.dev4 → cyclo_manager-1.1.0.dev5}/cyclo_manager_cli/docker/docker-compose.yml +0 -0
- {cyclo_manager-1.1.0.dev4 → cyclo_manager-1.1.0.dev5}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cyclo-manager
|
|
3
|
-
Version: 1.1.0.
|
|
3
|
+
Version: 1.1.0.dev5
|
|
4
4
|
Summary: cyclo_manager CLI: pip-installable launcher for cyclo_manager server and UI containers. Run 'cyclo_manager up' to start Docker stack.
|
|
5
5
|
License-Expression: Apache-2.0
|
|
6
6
|
Requires-Python: >=3.10
|
|
@@ -9,7 +9,6 @@ Requires-Dist: fastapi>=0.100.0
|
|
|
9
9
|
Requires-Dist: uvicorn[standard]>=0.23.0
|
|
10
10
|
Requires-Dist: psutil>=5.9.0
|
|
11
11
|
Provides-Extra: dev
|
|
12
|
-
Requires-Dist: pytest; extra == "dev"
|
|
13
12
|
Requires-Dist: ruff; extra == "dev"
|
|
14
13
|
|
|
15
14
|
# cyclo_manager CLI
|
|
@@ -134,6 +133,7 @@ The API container reaches it at `/agents/host/host_agent.sock` (see bundled `con
|
|
|
134
133
|
- Check update availability from remote tags and local `package.xml` versions.
|
|
135
134
|
- Update repos on allowed branches (`main`, `jazzy`) using stash or reset workflows.
|
|
136
135
|
- Stop/start a repo's `docker/container.sh` helper during an update when requested by the UI.
|
|
136
|
+
- Run container starts as background jobs with a 10-minute timeout covering the helper and its output streams; timeout or cancellation terminates the helper's process group and ends the job.
|
|
137
137
|
- Run Cyclo Manager package updates from the UI by delegating to `cyclo_manager update`.
|
|
138
138
|
- Provide host CPU/memory/disk statistics and process information. CPU summaries
|
|
139
139
|
share a background sampler's average of the latest three one-second samples.
|
|
@@ -120,6 +120,7 @@ The API container reaches it at `/agents/host/host_agent.sock` (see bundled `con
|
|
|
120
120
|
- Check update availability from remote tags and local `package.xml` versions.
|
|
121
121
|
- Update repos on allowed branches (`main`, `jazzy`) using stash or reset workflows.
|
|
122
122
|
- Stop/start a repo's `docker/container.sh` helper during an update when requested by the UI.
|
|
123
|
+
- Run container starts as background jobs with a 10-minute timeout covering the helper and its output streams; timeout or cancellation terminates the helper's process group and ends the job.
|
|
123
124
|
- Run Cyclo Manager package updates from the UI by delegating to `cyclo_manager update`.
|
|
124
125
|
- Provide host CPU/memory/disk statistics and process information. CPU summaries
|
|
125
126
|
share a background sampler's average of the latest three one-second samples.
|
|
@@ -22,6 +22,7 @@ import asyncio
|
|
|
22
22
|
import os
|
|
23
23
|
from pathlib import Path
|
|
24
24
|
import re
|
|
25
|
+
import signal
|
|
25
26
|
import time
|
|
26
27
|
from typing import Optional
|
|
27
28
|
|
|
@@ -45,6 +46,7 @@ router = APIRouter(prefix='/repos', tags=['repos'])
|
|
|
45
46
|
GIT_TIMEOUT = 120.0
|
|
46
47
|
GIT_REMOTE_TIMEOUT = 5.0
|
|
47
48
|
CONTAINER_SCRIPT_TIMEOUT = 600.0
|
|
49
|
+
CONTAINER_TERMINATE_TIMEOUT = 2.0
|
|
48
50
|
CONTAINER_JOB_RETENTION_SECONDS = 3600.0
|
|
49
51
|
CONTAINER_JOB_OUTPUT_LIMIT = 40000
|
|
50
52
|
|
|
@@ -429,13 +431,28 @@ async def _stop_container_start_process(
|
|
|
429
431
|
proc: asyncio.subprocess.Process | None,
|
|
430
432
|
readers: list[asyncio.Task],
|
|
431
433
|
) -> None:
|
|
432
|
-
"""Stop
|
|
433
|
-
if proc is not None
|
|
434
|
+
"""Stop the isolated process group, with bounded pipe and process cleanup."""
|
|
435
|
+
if proc is not None:
|
|
436
|
+
def signal_group(sig):
|
|
437
|
+
try:
|
|
438
|
+
os.killpg(proc.pid, sig)
|
|
439
|
+
except ProcessLookupError:
|
|
440
|
+
pass
|
|
441
|
+
|
|
442
|
+
signal_group(signal.SIGTERM)
|
|
434
443
|
try:
|
|
435
|
-
proc.
|
|
436
|
-
except
|
|
444
|
+
await asyncio.wait_for(proc.wait(), CONTAINER_TERMINATE_TIMEOUT)
|
|
445
|
+
except asyncio.TimeoutError:
|
|
437
446
|
pass
|
|
438
|
-
|
|
447
|
+
# Children may still exist even after their shell has exited.
|
|
448
|
+
signal_group(signal.SIGKILL)
|
|
449
|
+
try:
|
|
450
|
+
await asyncio.wait_for(proc.wait(), CONTAINER_TERMINATE_TIMEOUT)
|
|
451
|
+
except asyncio.TimeoutError:
|
|
452
|
+
pass
|
|
453
|
+
for reader in readers:
|
|
454
|
+
if not reader.done():
|
|
455
|
+
reader.cancel()
|
|
439
456
|
await asyncio.gather(*readers, return_exceptions=True)
|
|
440
457
|
|
|
441
458
|
|
|
@@ -477,6 +494,7 @@ async def _run_container_start(repo_path: Path, name: str) -> None:
|
|
|
477
494
|
'bash', str(script), 'start',
|
|
478
495
|
cwd=str(repo_path / 'docker'),
|
|
479
496
|
env=env,
|
|
497
|
+
start_new_session=True,
|
|
480
498
|
stdin=asyncio.subprocess.PIPE,
|
|
481
499
|
stdout=asyncio.subprocess.PIPE,
|
|
482
500
|
stderr=asyncio.subprocess.PIPE,
|
|
@@ -490,28 +508,31 @@ async def _run_container_start(repo_path: Path, name: str) -> None:
|
|
|
490
508
|
asyncio.create_task(_read_container_job_stream(proc.stdout, job)),
|
|
491
509
|
asyncio.create_task(_read_container_job_stream(proc.stderr, job)),
|
|
492
510
|
]
|
|
493
|
-
await asyncio.wait_for(
|
|
494
|
-
|
|
511
|
+
await asyncio.wait_for(
|
|
512
|
+
asyncio.gather(proc.wait(), *readers), timeout=CONTAINER_SCRIPT_TIMEOUT)
|
|
495
513
|
except asyncio.TimeoutError:
|
|
496
514
|
error = 'Timeout waiting for container.sh'
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
515
|
+
try:
|
|
516
|
+
await _stop_container_start_process(proc, readers)
|
|
517
|
+
finally:
|
|
518
|
+
_append_container_job_output(job, error)
|
|
519
|
+
_set_container_job_status(job, running=False, success=False, error=error)
|
|
500
520
|
return
|
|
501
521
|
except asyncio.CancelledError:
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
)
|
|
522
|
+
try:
|
|
523
|
+
await _stop_container_start_process(proc, readers)
|
|
524
|
+
finally:
|
|
525
|
+
_set_container_job_status(
|
|
526
|
+
job, running=False, success=False,
|
|
527
|
+
error='Container start operation was cancelled')
|
|
509
528
|
raise
|
|
510
529
|
except Exception as exc:
|
|
511
|
-
await _stop_container_start_process(proc, readers)
|
|
512
530
|
error = str(exc) or type(exc).__name__
|
|
513
|
-
|
|
514
|
-
|
|
531
|
+
try:
|
|
532
|
+
await _stop_container_start_process(proc, readers)
|
|
533
|
+
finally:
|
|
534
|
+
_append_container_job_output(job, error)
|
|
535
|
+
_set_container_job_status(job, running=False, success=False, error=error)
|
|
515
536
|
return
|
|
516
537
|
|
|
517
538
|
assert proc is not None
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cyclo-manager
|
|
3
|
-
Version: 1.1.0.
|
|
3
|
+
Version: 1.1.0.dev5
|
|
4
4
|
Summary: cyclo_manager CLI: pip-installable launcher for cyclo_manager server and UI containers. Run 'cyclo_manager up' to start Docker stack.
|
|
5
5
|
License-Expression: Apache-2.0
|
|
6
6
|
Requires-Python: >=3.10
|
|
@@ -9,7 +9,6 @@ Requires-Dist: fastapi>=0.100.0
|
|
|
9
9
|
Requires-Dist: uvicorn[standard]>=0.23.0
|
|
10
10
|
Requires-Dist: psutil>=5.9.0
|
|
11
11
|
Provides-Extra: dev
|
|
12
|
-
Requires-Dist: pytest; extra == "dev"
|
|
13
12
|
Requires-Dist: ruff; extra == "dev"
|
|
14
13
|
|
|
15
14
|
# cyclo_manager CLI
|
|
@@ -134,6 +133,7 @@ The API container reaches it at `/agents/host/host_agent.sock` (see bundled `con
|
|
|
134
133
|
- Check update availability from remote tags and local `package.xml` versions.
|
|
135
134
|
- Update repos on allowed branches (`main`, `jazzy`) using stash or reset workflows.
|
|
136
135
|
- Stop/start a repo's `docker/container.sh` helper during an update when requested by the UI.
|
|
136
|
+
- Run container starts as background jobs with a 10-minute timeout covering the helper and its output streams; timeout or cancellation terminates the helper's process group and ends the job.
|
|
137
137
|
- Run Cyclo Manager package updates from the UI by delegating to `cyclo_manager update`.
|
|
138
138
|
- Provide host CPU/memory/disk statistics and process information. CPU summaries
|
|
139
139
|
share a background sampler's average of the latest three one-second samples.
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "cyclo-manager"
|
|
7
|
-
version = "1.1.0.
|
|
7
|
+
version = "1.1.0.dev5"
|
|
8
8
|
description = "cyclo_manager CLI: pip-installable launcher for cyclo_manager server and UI containers. Run 'cyclo_manager up' to start Docker stack."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "Apache-2.0"
|
|
@@ -17,7 +17,6 @@ dependencies = [
|
|
|
17
17
|
|
|
18
18
|
[project.optional-dependencies]
|
|
19
19
|
dev = [
|
|
20
|
-
"pytest",
|
|
21
20
|
"ruff",
|
|
22
21
|
]
|
|
23
22
|
|
|
@@ -1,169 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
#
|
|
3
|
-
# Copyright 2026 ROBOTIS CO., LTD.
|
|
4
|
-
#
|
|
5
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
-
# you may not use this file except in compliance with the License.
|
|
7
|
-
# You may obtain a copy of the License at
|
|
8
|
-
#
|
|
9
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
-
#
|
|
11
|
-
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
-
# See the License for the specific language governing permissions and
|
|
15
|
-
# limitations under the License.
|
|
16
|
-
#
|
|
17
|
-
# Author: Hyungyu Kim
|
|
18
|
-
|
|
19
|
-
"""Regression tests for continuous CPU sampling and shared API summaries."""
|
|
20
|
-
|
|
21
|
-
from types import SimpleNamespace
|
|
22
|
-
import threading
|
|
23
|
-
import time
|
|
24
|
-
import unittest
|
|
25
|
-
from unittest.mock import Mock, call, patch
|
|
26
|
-
|
|
27
|
-
from cyclo_host_agent.cpu_usage import CpuUsageSampler
|
|
28
|
-
from cyclo_host_agent.main import app, lifespan
|
|
29
|
-
from cyclo_host_agent.routers import system_stats
|
|
30
|
-
from fastapi import HTTPException
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
class CpuUsageTests(unittest.TestCase):
|
|
34
|
-
"""Check measurement windows, startup behavior, and sampling ownership."""
|
|
35
|
-
|
|
36
|
-
def test_rolling_window_discards_prime_and_oldest_sample(self):
|
|
37
|
-
"""Average available samples at startup and only the last three afterward."""
|
|
38
|
-
sampler = CpuUsageSampler()
|
|
39
|
-
observed = []
|
|
40
|
-
|
|
41
|
-
def next_interval(interval):
|
|
42
|
-
self.assertEqual(interval, 1.0)
|
|
43
|
-
observed.append(sampler.average())
|
|
44
|
-
if len(observed) == 5:
|
|
45
|
-
sampler._stop.set()
|
|
46
|
-
return True
|
|
47
|
-
return False
|
|
48
|
-
|
|
49
|
-
with patch('cyclo_host_agent.cpu_usage.psutil.cpu_percent',
|
|
50
|
-
side_effect=[99.0, 10.0, 20.0, 60.0, 90.0]) as cpu:
|
|
51
|
-
with patch.object(sampler._stop, 'wait', side_effect=next_interval):
|
|
52
|
-
sampler._run()
|
|
53
|
-
self.assertEqual(observed, [None, 10.0, 15.0, 30.0, 56.7])
|
|
54
|
-
self.assertEqual(cpu.call_args_list, [call(interval=None)] * 5)
|
|
55
|
-
|
|
56
|
-
def test_background_sampling_is_independent_of_readers(self):
|
|
57
|
-
"""Prime and sample on one thread, even without API requests."""
|
|
58
|
-
sampler = CpuUsageSampler(interval=0.01)
|
|
59
|
-
thread_ids = []
|
|
60
|
-
|
|
61
|
-
def cpu_percent(interval):
|
|
62
|
-
thread_ids.append(threading.get_ident())
|
|
63
|
-
return 30.0
|
|
64
|
-
|
|
65
|
-
with patch('cyclo_host_agent.cpu_usage.psutil.cpu_percent',
|
|
66
|
-
side_effect=cpu_percent):
|
|
67
|
-
sampler.start()
|
|
68
|
-
worker = sampler._thread
|
|
69
|
-
try:
|
|
70
|
-
sampler.start()
|
|
71
|
-
self.assertIs(sampler._thread, worker)
|
|
72
|
-
deadline = time.monotonic() + 2
|
|
73
|
-
while sampler.average() is None and time.monotonic() < deadline:
|
|
74
|
-
time.sleep(0.005)
|
|
75
|
-
self.assertEqual(sampler.average(), 30.0)
|
|
76
|
-
finally:
|
|
77
|
-
sampler.stop()
|
|
78
|
-
self.assertFalse(worker.is_alive())
|
|
79
|
-
count = len(thread_ids)
|
|
80
|
-
for _ in range(50):
|
|
81
|
-
self.assertEqual(sampler.average(), 30.0)
|
|
82
|
-
self.assertEqual(len(thread_ids), count)
|
|
83
|
-
self.assertGreaterEqual(count, 2)
|
|
84
|
-
self.assertEqual(len(set(thread_ids)), 1)
|
|
85
|
-
self.assertNotEqual(thread_ids[0], threading.get_ident())
|
|
86
|
-
sampler._interval = 1.0
|
|
87
|
-
sampler.start()
|
|
88
|
-
try:
|
|
89
|
-
self.assertIsNone(sampler.average())
|
|
90
|
-
finally:
|
|
91
|
-
sampler.stop()
|
|
92
|
-
|
|
93
|
-
def test_warmup_does_not_report_a_fake_zero(self):
|
|
94
|
-
"""Return a retryable response before a complete sample exists."""
|
|
95
|
-
with patch.object(system_stats, 'cpu_sampler', CpuUsageSampler()):
|
|
96
|
-
with self.assertRaises(HTTPException) as result:
|
|
97
|
-
system_stats.get_system_stats()
|
|
98
|
-
self.assertEqual(result.exception.status_code, 503)
|
|
99
|
-
|
|
100
|
-
def test_sampling_failure_clears_history_and_primes_again(self):
|
|
101
|
-
"""Do not keep old CPU values when a measurement fails."""
|
|
102
|
-
sampler = CpuUsageSampler()
|
|
103
|
-
observed = []
|
|
104
|
-
|
|
105
|
-
def next_interval(interval):
|
|
106
|
-
observed.append(sampler.average())
|
|
107
|
-
if len(observed) == 5:
|
|
108
|
-
sampler._stop.set()
|
|
109
|
-
return True
|
|
110
|
-
return False
|
|
111
|
-
|
|
112
|
-
with patch('cyclo_host_agent.cpu_usage.psutil.cpu_percent',
|
|
113
|
-
side_effect=[99.0, 10.0, OSError('CPU read failed'), 99.0, 60.0]), \
|
|
114
|
-
patch('cyclo_host_agent.cpu_usage.logger.exception') as log, \
|
|
115
|
-
patch.object(sampler._stop, 'wait', side_effect=next_interval):
|
|
116
|
-
sampler._run()
|
|
117
|
-
self.assertEqual(observed, [None, 10.0, None, None, 60.0])
|
|
118
|
-
log.assert_called_once()
|
|
119
|
-
|
|
120
|
-
def test_status_and_process_summary_read_the_same_average(self):
|
|
121
|
-
"""Total CPU is shared while process rows retain their own measurements."""
|
|
122
|
-
process = Mock()
|
|
123
|
-
process.as_dict.return_value = {
|
|
124
|
-
'pid': 42, 'username': 'robot', 'cpu_percent': 80.0,
|
|
125
|
-
'memory_percent': 1.0, 'memory_info': SimpleNamespace(rss=1024),
|
|
126
|
-
'cmdline': ['robot-node'], 'name': 'robot-node',
|
|
127
|
-
}
|
|
128
|
-
with patch.object(system_stats.cpu_sampler, 'average', return_value=12.3), \
|
|
129
|
-
patch.object(system_stats.psutil, 'cpu_percent',
|
|
130
|
-
side_effect=AssertionError('API must not resample total CPU')), \
|
|
131
|
-
patch.object(system_stats.psutil, 'virtual_memory',
|
|
132
|
-
return_value=SimpleNamespace(used=1024**3, total=8*1024**3)), \
|
|
133
|
-
patch.object(system_stats.psutil, 'disk_usage',
|
|
134
|
-
return_value=SimpleNamespace(used=10*1024**3, total=100*1024**3)), \
|
|
135
|
-
patch.object(system_stats, '_extra_storage_disk_usage', return_value=(None, None)), \
|
|
136
|
-
patch.object(system_stats, '_temperature', return_value=None), \
|
|
137
|
-
patch.object(system_stats.psutil, 'process_iter', return_value=[process]), \
|
|
138
|
-
patch.object(system_stats.psutil, 'cpu_count', return_value=4), \
|
|
139
|
-
patch.object(system_stats.time, 'sleep') as sleep:
|
|
140
|
-
status = system_stats.get_system_stats()
|
|
141
|
-
processes = system_stats._sample_processes()
|
|
142
|
-
self.assertEqual(status.cpu_percent, 12.3)
|
|
143
|
-
self.assertEqual(processes.cpu_percent, status.cpu_percent)
|
|
144
|
-
self.assertEqual(processes.processes[0].cpu_percent, 20.0)
|
|
145
|
-
process.cpu_percent.assert_called_once_with(None)
|
|
146
|
-
sleep.assert_called_once_with(0.2)
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
class CpuLifespanTests(unittest.IsolatedAsyncioTestCase):
|
|
150
|
-
"""Check sampler cleanup when the API exits."""
|
|
151
|
-
|
|
152
|
-
async def test_lifespan_stops_sampler_even_on_failure(self):
|
|
153
|
-
"""Stop the background worker on both normal and exceptional shutdown."""
|
|
154
|
-
sampler = Mock()
|
|
155
|
-
with patch.object(system_stats, 'cpu_sampler', sampler):
|
|
156
|
-
async with lifespan(app):
|
|
157
|
-
sampler.start.assert_called_once_with()
|
|
158
|
-
sampler.stop.assert_not_called()
|
|
159
|
-
sampler.stop.assert_called_once_with()
|
|
160
|
-
sampler.reset_mock()
|
|
161
|
-
with self.assertRaises(RuntimeError):
|
|
162
|
-
async with lifespan(app):
|
|
163
|
-
raise RuntimeError('shutdown')
|
|
164
|
-
sampler.start.assert_called_once_with()
|
|
165
|
-
sampler.stop.assert_called_once_with()
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
if __name__ == '__main__':
|
|
169
|
-
unittest.main()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{cyclo_manager-1.1.0.dev4 → cyclo_manager-1.1.0.dev5}/cyclo_host_agent/routers/system_stats.py
RENAMED
|
File without changes
|
|
File without changes
|
{cyclo_manager-1.1.0.dev4 → cyclo_manager-1.1.0.dev5}/cyclo_manager.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
{cyclo_manager-1.1.0.dev4 → cyclo_manager-1.1.0.dev5}/cyclo_manager.egg-info/entry_points.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{cyclo_manager-1.1.0.dev4 → cyclo_manager-1.1.0.dev5}/cyclo_manager_cli/docker/docker-compose.yml
RENAMED
|
File without changes
|
|
File without changes
|