Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 22 additions & 1 deletion src/sorunlib/seq.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import datetime as dt

import sorunlib as run

from sorunlib.commands import _timestamp_to_utc_datetime
from sorunlib._internal import check_response, check_started, monitor_process


OP_TIMEOUT = 60


def scan(description, stop_time, width, az_drift=0, tag=None, subtype=None):
def scan(description, stop_time, width, az_drift=0, tag=None, subtype=None,
min_duration=None):
"""Run a constant elevation scan, collecting detector data.

Args:
Expand All @@ -19,8 +24,24 @@ def scan(description, stop_time, width, az_drift=0, tag=None, subtype=None):
tag (str, optional): Tag or comma-separated listed of tags to attach to
the operation. Passed through to the smurf stream command.
subtype (str, optional): Operation subtype used to tag the stream.
min_duration (float, optional): Minimum duration required to scan,
specified in seconds. If not enough time exists between now and the
``stop_time`` the scan is not executed. Defaults to None.

"""
now = dt.datetime.now(dt.timezone.utc)
scan_stop = _timestamp_to_utc_datetime(stop_time)

# Check stop time has not already passed
if now > scan_stop:
return

# Check there is enough time to perform scan
if min_duration is not None:
start_by_time = scan_stop - dt.timedelta(seconds=min_duration)
if now > start_by_time:
return

acu = run.CLIENTS['acu']

# Enable SMuRF streams
Expand Down
20 changes: 18 additions & 2 deletions tests/test_seq.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,30 @@ def test_scan(patch_clients):
seq.scan(description='test', stop_time=target.isoformat(), width=20.)


@patch('sorunlib._internal.time.sleep', MagicMock())
def test_scan_passed_stop_time(patch_clients):
# This affects test runtime duration keep it short
target = dt.datetime.now(dt.timezone.utc) - dt.timedelta(seconds=10)
seq.scan(description='test', stop_time=target.isoformat(), width=20.)
seq.run.CLIENTS['acu'].generate_scan.start.assert_not_called()


@patch('sorunlib._internal.time.sleep', MagicMock())
def test_scan_passed_min_duration(patch_clients):
# This affects test runtime duration keep it short
target = dt.datetime.now(dt.timezone.utc) + dt.timedelta(seconds=10)
seq.scan(description='test', stop_time=target.isoformat(), width=20., min_duration=60)
seq.run.CLIENTS['acu'].generate_scan.start.assert_not_called()


@patch('sorunlib.commands.time.sleep', MagicMock())
def test_scan_no_session(patch_clients):
# Setup mock OCSReply without session object
mock_reply = MagicMock()
mock_reply.session = None
sorunlib.CLIENTS['acu'].generate_scan.start = MagicMock(return_value=mock_reply)

target = dt.datetime.now() + dt.timedelta(seconds=1)
target = dt.datetime.now(dt.timezone.utc) + dt.timedelta(seconds=1)
with pytest.raises(Exception):
seq.scan(description='test', stop_time=target.isoformat(), width=20.)

Expand Down Expand Up @@ -60,6 +76,6 @@ def test_scan_failed_to_start(patch_clients):
# other keys in .session: op_code, data
print(mock_reply)

target = dt.datetime.now() + dt.timedelta(seconds=1)
target = dt.datetime.now(dt.timezone.utc) + dt.timedelta(seconds=10)
with pytest.raises(RuntimeError):
seq.scan(description='test', stop_time=target.isoformat(), width=20.)