Skip to content

Commit 1cd5e92

Browse files
authored
Fix edit behavior on lan jobs - properly host the edited job by the editing peer (#171)
1 parent b735822 commit 1cd5e92

File tree

5 files changed

+79
-9
lines changed

5 files changed

+79
-9
lines changed

continuousprint/integration_test.py

Lines changed: 55 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
import unittest
22
import datetime
33
import time
4+
import tempfile
45
from unittest.mock import MagicMock, ANY
56
from .driver import Driver, Action as DA, Printer as DP
7+
from pathlib import Path
68
import logging
79
import traceback
810
from .storage.database_test import DBTest
911
from .storage.database import DEFAULT_QUEUE, MODELS, populate_queues
1012
from .storage import queries
13+
from .storage.lan import LANJobView
1114
from .queues.multi import MultiQueue
1215
from .queues.local import LocalQueue
1316
from .queues.lan import LANQueue
@@ -341,18 +344,22 @@ def onupdate():
341344

342345
self.locks = {}
343346
self.peers = []
347+
lqpeers = {}
348+
lqjobs = TestReplDict(lambda a, b: None)
344349
for i, db in enumerate(self.dbs):
345350
with db.bind_ctx(MODELS):
346351
populate_queues()
352+
fsm = MagicMock(host="fsaddr", port=0)
353+
profile = dict(name="profile")
347354
lq = LANQueue(
348355
"LAN",
349356
f"peer{i}:{12345+i}",
350357
logging.getLogger(f"peer{i}:LAN"),
351358
Strategy.IN_ORDER,
352359
onupdate,
353-
MagicMock(),
354-
dict(name="profile"),
355-
lambda path: path,
360+
fsm,
361+
profile,
362+
lambda path, sd: path,
356363
)
357364
mq = MultiQueue(queries, Strategy.IN_ORDER, onupdate)
358365
mq.add(lq.ns, lq)
@@ -368,11 +375,9 @@ def onupdate():
368375
lq.ns, lq.addr, MagicMock(), logging.getLogger("lantestbase")
369376
)
370377
lq.lan.q.locks = LocalLockManager(self.locks, f"peer{i}")
371-
lq.lan.q.jobs = TestReplDict(lambda a, b: None)
372-
lq.lan.q.peers = self.peers
373-
if i > 0:
374-
lq.lan.q.peers = self.peers[0][2].lan.q.peers
375-
lq.lan.q.jobs = self.peers[0][2].lan.q.jobs
378+
lq.lan.q.jobs = lqjobs
379+
lq.lan.q.peers = lqpeers
380+
lq.update_peer_state(lq.addr, "status", "run", profile)
376381
self.peers.append((d, mq, lq, db))
377382

378383
def test_ordered_acquisition(self):
@@ -428,6 +433,48 @@ def test_ordered_acquisition(self):
428433
d2.action(DA.SUCCESS, DP.IDLE) # -> idle
429434
self.assertEqual(d2.state.__name__, d2._state_idle.__name__)
430435

436+
def test_non_local_edit(self):
437+
(d1, _, lq1, db1) = self.peers[0]
438+
(d2, _, lq2, db2) = self.peers[1]
439+
with tempfile.TemporaryDirectory() as tdir:
440+
(Path(tdir) / "test.gcode").touch()
441+
j = LANJobView(
442+
dict(
443+
id="jobhash",
444+
name="job",
445+
created=0,
446+
sets=[
447+
dict(
448+
path="test.gcode",
449+
count=1,
450+
remaining=1,
451+
profiles=["profile"],
452+
),
453+
],
454+
count=1,
455+
remaining=1,
456+
peer_=None,
457+
),
458+
lq1,
459+
)
460+
lq1._path_on_disk = lambda p, sd: str(Path(tdir) / p)
461+
lq1.import_job_from_view(j, j.id)
462+
lq2._fileshare.post.assert_not_called()
463+
464+
# LQ2 edits the job
465+
lq2._fileshare.fetch.return_value = str(Path(tdir) / "unpack/")
466+
(Path(tdir) / "unpack").mkdir()
467+
lq2dest = Path(tdir) / "unpack/test.gcode"
468+
lq2dest.touch()
469+
lq2.edit_job("jobhash", dict(draft=True))
470+
471+
lq2._fileshare.post.assert_called_once()
472+
# Job posts with lan 2 address, from pov of lq1
473+
self.assertEqual(list(lq1.lan.q.jobs.values())[0][0], lq2.addr)
474+
# Uses resolved file path
475+
c = lq2._fileshare.post.call_args[0]
476+
self.assertEqual(c[1], {str(lq2dest): str(lq2dest)})
477+
431478

432479
if __name__ == "__main__":
433480
unittest.main()

continuousprint/queues/lan.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,7 @@ def _gen_uuid(self) -> str:
309309
def edit_job(self, job_id, data) -> bool:
310310
# For lan queues, "editing" a job is basically resubmission of the whole thing.
311311
# This is because the backing .gjob format is a single file containing the full manifest.
312+
312313
j = self.get_job_view(job_id)
313314
for (k, v) in data.items():
314315
if k in ("id", "peer_", "queue"):
@@ -320,6 +321,13 @@ def edit_job(self, job_id, data) -> bool:
320321
else:
321322
setattr(j, k, v)
322323

324+
# We must resolve the set paths so we have them locally, as editing can
325+
# also occur on servers other than the one that submitted the job.
326+
j.remap_set_paths()
327+
328+
# We are also now the source of this job
329+
j.peer = self.addr
330+
323331
# Exchange the old job for the new job (reuse job ID)
324332
jid = self.import_job_from_view(j, j.id)
325333
return self._get_job(jid)

continuousprint/queues/lan_test.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,17 @@ class LANQueueTest(unittest.TestCase, PeerPrintLANTest):
2020
def setUp(self):
2121
PeerPrintLANTest.setUp(self) # Generate peerprint LANQueue as self.q
2222
self.q.q.syncPeer(
23-
dict(profile=dict(name="profile")), addr=self.q.q.addr
23+
dict(
24+
profile=dict(name="profile"),
25+
fs_addr="mock_fs_addr",
26+
),
27+
addr=self.q.q.addr,
2428
) # Helps pass validation
2529
ppq = self.q # Rename to make way for CPQ LANQueue
2630

2731
self.ucb = MagicMock()
2832
self.fs = MagicMock()
33+
self.fs.fetch.return_value = "asdf.gcode"
2934
self.q = LANQueue(
3035
"ns",
3136
"localhost:1234",

continuousprint/storage/lan.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,11 @@ def __init__(self, manifest, lq):
3030
def get_base_dir(self):
3131
return self.queue.lq.get_gjob_dirpath(self.peer, self.hash)
3232

33+
def remap_set_paths(self):
34+
# Replace all relative/local set paths with fully resolved paths
35+
for s in self.sets:
36+
s.path = s.resolve()
37+
3338
def updateSets(self, sets_list):
3439
self.sets = [LANSetView(s, self, i) for i, s in enumerate(sets_list)]
3540

continuousprint/storage/lan_test.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@ def test_resolve_file(self):
2525
self.lq.get_gjob_dirpath.return_value = "/path/to/"
2626
self.assertEqual(self.s.resolve(), "/path/to/a.gcode")
2727

28+
def test_remap_set_paths(self):
29+
self.lq.get_gjob_dirpath.return_value = "/path/to/"
30+
self.j.remap_set_paths()
31+
self.assertEqual(self.s.path, "/path/to/a.gcode")
32+
2833
def test_resolve_http_error(self):
2934
self.lq.get_gjob_dirpath.side_effect = HTTPError
3035
with self.assertRaises(ResolveError):

0 commit comments

Comments
 (0)