Skip to content

Commit 1add445

Browse files
authored
Merge pull request #889 from simvue-io/wk9874/885-offline-fixes
Fix offline mode bugs
2 parents e8767d1 + dc4f560 commit 1add445

File tree

6 files changed

+104
-23
lines changed

6 files changed

+104
-23
lines changed

simvue/api/objects/artifact/file.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,9 @@ def new(
8080
else:
8181
file_path = pathlib.Path(file_path)
8282
if snapshot:
83-
_user_config = SimvueConfiguration.fetch()
83+
_user_config = SimvueConfiguration.fetch(
84+
mode="offline" if offline else "online"
85+
)
8486

8587
_local_staging_dir: pathlib.Path = _user_config.offline.cache.joinpath(
8688
"artifacts"

simvue/api/objects/run.py

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -696,19 +696,9 @@ def on_reconnect(self, id_mapping: dict[str, str]) -> None:
696696
id_mapping: dict[str, str]
697697
A mapping from offline identifier to online identifier.
698698
"""
699-
online_alert_ids: list[str] = []
700-
for id in self._staging.get("alerts", []):
701-
try:
702-
online_alert_ids.append(id_mapping[id])
703-
except KeyError:
704-
raise KeyError(
705-
"Could not find alert ID in offline to online ID mapping."
706-
)
707-
# If run is offline, no alerts have been added yet, so add all alerts:
708-
if self._identifier is not None and self._identifier.startswith("offline"):
709-
self._staging["alerts"] = online_alert_ids
710-
# Otherwise, only add alerts which have not yet been added
711-
else:
712-
self._staging["alerts"] = [
713-
id for id in online_alert_ids if id not in list(self.alerts)
714-
]
699+
online_alert_ids: list[str] = list(
700+
set(id_mapping.get(_id) for _id in self._staging.get("alerts", []))
701+
)
702+
if not all(online_alert_ids):
703+
raise KeyError("Could not find alert ID in offline to online ID mapping.")
704+
self._staging["alerts"] = online_alert_ids

simvue/config/user.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,9 +151,9 @@ def check_valid_server(cls, values: "SimvueConfiguration") -> "SimvueConfigurati
151151
@sv_util.prettify_pydantic
152152
def fetch(
153153
cls,
154+
mode: typing.Literal["offline", "online", "disabled"],
154155
server_url: str | None = None,
155156
server_token: str | None = None,
156-
mode: typing.Literal["offline", "online", "disabled"] | None = None,
157157
) -> "SimvueConfiguration":
158158
"""Retrieve the Simvue configuration from this project
159159

simvue/sender.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@ def sender(
217217
id_mapping
218218
mapping of local ID to server ID
219219
"""
220-
_user_config: SimvueConfiguration = SimvueConfiguration.fetch()
220+
_user_config: SimvueConfiguration = SimvueConfiguration.fetch(mode="online")
221221
cache_dir = cache_dir or _user_config.offline.cache
222222

223223
cache_dir.joinpath("server_ids").mkdir(parents=True, exist_ok=True)

tests/functional/test_config.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -101,15 +101,16 @@ def _mocked_find(file_names: list[str], *_, ppt_file=_ppt_file, conf_file=_confi
101101

102102
if not use_file and not use_env and not use_args:
103103
with pytest.raises(RuntimeError):
104-
simvue.config.user.SimvueConfiguration.fetch()
104+
simvue.config.user.SimvueConfiguration.fetch(mode="online")
105105
return
106106
elif use_args:
107107
_config = simvue.config.user.SimvueConfiguration.fetch(
108108
server_url=_arg_url,
109-
server_token=_arg_token
109+
server_token=_arg_token,
110+
mode="online"
110111
)
111112
else:
112-
_config = simvue.config.user.SimvueConfiguration.fetch()
113+
_config = simvue.config.user.SimvueConfiguration.fetch(mode="online")
113114

114115
if use_file and use_file != "pyproject.toml":
115116
assert _config.config_file() == _config_file

tests/functional/test_run_class.py

Lines changed: 89 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1153,6 +1153,94 @@ def test_add_alerts() -> None:
11531153
)
11541154
for _id in _expected_alerts:
11551155
client.delete_alert(_id)
1156+
1157+
@pytest.mark.run
1158+
@pytest.mark.offline
1159+
def test_add_alerts_offline(monkeypatch) -> None:
1160+
_uuid = f"{uuid.uuid4()}".split("-")[0]
1161+
1162+
temp_d = tempfile.TemporaryDirectory()
1163+
monkeypatch.setenv("SIMVUE_OFFLINE_DIRECTORY", temp_d.name)
1164+
1165+
run = sv_run.Run(mode="offline")
1166+
run.init(
1167+
name="test_add_alerts_offline",
1168+
folder=f"/simvue_unit_testing/{_uuid}",
1169+
retention_period=os.environ.get("SIMVUE_TESTING_RETENTION_PERIOD", "2 mins"),
1170+
tags=[platform.system(), "test_add_alerts"],
1171+
visibility="tenant" if os.environ.get("CI") else None,
1172+
)
1173+
1174+
_expected_alerts = []
1175+
1176+
# Create alerts, have them attach to run automatically
1177+
_id = run.create_event_alert(
1178+
name=f"event_alert_{_uuid}",
1179+
pattern="test",
1180+
)
1181+
_expected_alerts.append(_id)
1182+
1183+
# Create another alert and attach to run
1184+
_id = run.create_metric_range_alert(
1185+
name=f"metric_range_alert_{_uuid}",
1186+
metric="test",
1187+
range_low=10,
1188+
range_high=100,
1189+
rule="is inside range",
1190+
)
1191+
_expected_alerts.append(_id)
1192+
1193+
# Create another alert, do not attach to run
1194+
_id = run.create_metric_threshold_alert(
1195+
name=f"metric_threshold_alert_{_uuid}",
1196+
metric="test",
1197+
threshold=10,
1198+
rule="is above",
1199+
attach_to_run=False,
1200+
)
1201+
1202+
# Try redefining existing alert again
1203+
_id = run.create_metric_range_alert(
1204+
name=f"metric_range_alert_{_uuid}",
1205+
metric="test",
1206+
range_low=10,
1207+
range_high=100,
1208+
rule="is inside range",
1209+
)
1210+
1211+
_id_mapping = sv_send.sender(os.environ["SIMVUE_OFFLINE_DIRECTORY"], 2, 10, throw_exceptions=True)
1212+
_online_run = RunObject(identifier=_id_mapping.get(run.id))
1213+
1214+
# Check that there is no duplication
1215+
assert sorted(_online_run.alerts) == sorted([_id_mapping.get(_id) for _id in _expected_alerts])
1216+
1217+
# Create another run without adding to run
1218+
_id = run.create_user_alert(name=f"user_alert_{_uuid}", attach_to_run=False)
1219+
_id_mapping = sv_send.sender(os.environ["SIMVUE_OFFLINE_DIRECTORY"], 2, 10, throw_exceptions=True)
1220+
1221+
# Check alert is not added
1222+
_online_run.refresh()
1223+
assert sorted(_online_run.alerts) == sorted([_id_mapping.get(_id) for _id in _expected_alerts])
1224+
1225+
# Try adding alerts with IDs, check there is no duplication
1226+
_expected_alerts.append(_id)
1227+
run.add_alerts(ids=_expected_alerts)
1228+
_id_mapping = sv_send.sender(os.environ["SIMVUE_OFFLINE_DIRECTORY"], 2, 10, throw_exceptions=True)
1229+
1230+
_online_run.refresh()
1231+
assert sorted(_online_run.alerts) == sorted([_id_mapping.get(_id) for _id in _expected_alerts])
1232+
1233+
run.close()
1234+
1235+
client = sv_cl.Client()
1236+
with contextlib.suppress(ObjectNotFoundError):
1237+
client.delete_folder(
1238+
f"/simvue_unit_testing/{_uuid}",
1239+
remove_runs=True,
1240+
recursive=True
1241+
)
1242+
for _id in [_id_mapping.get(_id) for _id in _expected_alerts]:
1243+
client.delete_alert(_id)
11561244

11571245

11581246
@pytest.mark.run
@@ -1439,7 +1527,7 @@ def test_run_environment_metadata(environment: str, mocker: pytest_mock.MockerFi
14391527
_target_dir = _data_dir
14401528
if "python" in environment:
14411529
_target_dir = _data_dir.joinpath(environment)
1442-
_config = SimvueConfiguration.fetch()
1530+
_config = SimvueConfiguration.fetch(mode="online")
14431531

14441532
with sv_run.Run(server_token=_config.server.token, server_url=_config.server.url) as run:
14451533
_uuid = f"{uuid.uuid4()}".split("-")[0]

0 commit comments

Comments
 (0)