|
11 | 11 | from alchemiscale.storage.statestore import Neo4jStore |
12 | 12 | from alchemiscale.storage.objectstore import S3ObjectStore |
13 | 13 | from alchemiscale.compute.client import AlchemiscaleComputeClientError |
14 | | -from alchemiscale.compute.service import SynchronousComputeService |
15 | | -from alchemiscale.compute.settings import ComputeServiceSettings |
| 14 | +from alchemiscale.compute.service import AsynchronousComputeService, SynchronousComputeService |
| 15 | +from alchemiscale.compute.settings import AsynchronousComputeServiceSettings, ComputeServiceSettings |
16 | 16 |
|
17 | 17 |
|
18 | 18 | class TestSynchronousComputeService: |
@@ -255,3 +255,81 @@ def test_missing_compute_manager(self, n4js_preloaded, service): |
255 | 255 | match="Could not find ComputeManagerRegistration", |
256 | 256 | ): |
257 | 257 | service._register() |
| 258 | + |
| 259 | +class TestAsynchronousComputeService: |
| 260 | + |
| 261 | + @pytest.fixture |
| 262 | + def service(self, n4js_preloaded, compute_client, tmpdir): |
| 263 | + with tmpdir.as_cwd(): |
| 264 | + return AsynchronousComputeService( |
| 265 | + AsynchronousComputeServiceSettings( |
| 266 | + gpu_monitor_enabled=False, |
| 267 | + api_url=compute_client.api_url, |
| 268 | + identifier=compute_client.identifier, |
| 269 | + key=compute_client.key, |
| 270 | + name="test_compute_service", |
| 271 | + shared_basedir=Path("shared").absolute(), |
| 272 | + scratch_basedir=Path("scratch").absolute(), |
| 273 | + heartbeat_interval=1, |
| 274 | + sleep_interval=1, |
| 275 | + deep_sleep_interval=1, |
| 276 | + ) |
| 277 | + ) |
| 278 | + |
| 279 | + def test_heartbeat(self, n4js_preloaded, service): |
| 280 | + n4js: Neo4jStore = n4js_preloaded |
| 281 | + |
| 282 | + # register service; normally happens on service start, but needed |
| 283 | + # for heartbeats |
| 284 | + service._register() |
| 285 | + |
| 286 | + # start up heartbeat thread |
| 287 | + heartbeat_thread = threading.Thread(target=service.heartbeat, daemon=True) |
| 288 | + heartbeat_thread.start() |
| 289 | + |
| 290 | + # give time for a heartbeat |
| 291 | + time.sleep(2) |
| 292 | + |
| 293 | + q = f""" |
| 294 | + match (csreg:ComputeServiceRegistration {{identifier: '{service.compute_service_id}'}}) |
| 295 | + return csreg |
| 296 | + """ |
| 297 | + csreg = n4js.execute_query(q).records[0]["csreg"] |
| 298 | + |
| 299 | + assert csreg["registered"] < csreg["heartbeat"] |
| 300 | + |
| 301 | + # stop the service; should trigger heartbeat to stop |
| 302 | + service.stop() |
| 303 | + time.sleep(2) |
| 304 | + assert not heartbeat_thread.is_alive() |
| 305 | + |
| 306 | + def test_cycle(self, n4js_preloaded, s3os_server_fresh, service): |
| 307 | + service._register() |
| 308 | + |
| 309 | + q = """ |
| 310 | + match (pdr:ProtocolDAGResultRef) |
| 311 | + return pdr |
| 312 | + """ |
| 313 | + |
| 314 | + # preconditions |
| 315 | + protocoldagresultref = n4js_preloaded.execute_query(q) |
| 316 | + assert not protocoldagresultref.records |
| 317 | + |
| 318 | + # note that non-None max_time will fail due to _start_time |
| 319 | + # never being set |
| 320 | + while service.cycle(max_tasks=1, max_time=None): |
| 321 | + pass |
| 322 | + |
| 323 | + # postconditions |
| 324 | + protocoldagresultref = n4js_preloaded.execute_query(q) |
| 325 | + assert protocoldagresultref.records |
| 326 | + assert protocoldagresultref.records[0]["pdr"]["ok"] is True |
| 327 | + |
| 328 | + q = """ |
| 329 | + match (t:Task {status: 'complete'}) |
| 330 | + return t |
| 331 | + """ |
| 332 | + |
| 333 | + results = n4js_preloaded.execute_query(q) |
| 334 | + |
| 335 | + assert results.records |
0 commit comments