def test_caput_status_pv_message(self, catools): p = self.create_part( dict( name="mname", description="desc", pv="pv", status_pv="spv", good_status="All Good", message_pv="mpv", ) ) catools.caget.return_value = [caint(4)] c = StatefulController("mri") c.add_part(p) proc = Process("proc") proc.add_controller(c) proc.start() self.addCleanup(proc.stop) b = proc.block_view("mri") self.make_camonitor_return(catools, "No Good") catools.caget.return_value = "Bad things happened" with self.assertRaises(AssertionError) as cm: b.mname() assert ( str(cm.exception) == "Status No Good: Bad things happened: " "while performing 'caput pv 1'" )
def setUp(self): self.process = Process("proc") self.o = RawMotorSinkPortsPart("PV:PRE") c = StatefulController("mri") c.add_part(self.o) self.process.add_controller(c) self.b = self.process.block_view("mri") self.addCleanup(self.process.stop)
def setUp(self, catools): self.catools = catools catools.caget.side_effect = [[castr("BRICK1CS1")]] self.process = Process("proc") self.o = CSSourcePortsPart("cs", "PV:PRE:Port") c = StatefulController("mri") c.add_part(self.o) self.process.add_controller(c) self.b = self.process.block_view("mri") self.process.start() self.addCleanup(self.process.stop)
def setUp(self, catools): self.catools = catools catools.caget.side_effect = [[castr("@asyn(BRICK1CS1,2)")]] self.process = Process("proc") self.o = CompoundMotorCSPart("cs", "PV:PRE.OUT") c = StatefulController("mri") c.add_part(self.o) self.process.add_controller(c) self.b = self.process.block_view("mri") self.process.start() self.addCleanup(self.process.stop)
def _make_child_controller(self, parts, mri): # Add some extra parts to determine the dataset name and type for # any CAPTURE field part new_parts = [] for existing_part in parts: new_parts.append(existing_part) if hasattr(existing_part, "field_name") and \ existing_part.field_name.endswith(".CAPTURE"): # Add capture dataset name and type part_name = existing_part.field_name.replace( ".CAPTURE", ".DATASET_NAME") attr_name = snake_to_camel(part_name.replace(".", "_")) new_parts.append( StringPart( name=attr_name, description="Name of the captured dataset in HDF file", writeable=True)) # Make a choice part to hold the type of the dataset part_name = existing_part.field_name.replace( ".CAPTURE", ".DATASET_TYPE") attr_name = snake_to_camel(part_name.replace(".", "_")) if "INENC" in mri: initial = "position" else: initial = "monitor" new_parts.append( ChoicePart( name=attr_name, description="Type of the captured dataset in HDF file", writeable=True, choices=list(AttributeDatasetType), value=initial)) if mri.endswith("PCAP"): cs, ps = adbase_parts(prefix=self.prefix) controller = StatefulController(mri=mri) for p in new_parts + ps: controller.add_part(p) for c in cs: self.process.add_controller(c) else: controller = super(PandABlocksRunnableController, self).\ _make_child_controller(new_parts, mri) return controller
class TestStatefulController(unittest.TestCase): def setUp(self): self.process = Process("proc") self.part = MyPart("testpart") self.part2 = MyPart("testpart2") self.o = StatefulController("MyMRI") self.o.add_part(self.part) self.o.add_part(self.part2) self.process.add_controller(self.o) self.b = self.process.block_view("MyMRI") def start_process(self): self.process.start() self.addCleanup(self.stop_process) def stop_process(self): if self.process.state: self.process.stop(timeout=1) def test_process_init(self, ): assert not self.part.started self.start_process() assert self.part.started def test_process_stop(self): self.start_process() assert not self.part.halted self.process.stop(timeout=1) assert self.part.halted def test_init(self): assert self.b.state.value == "Disabled" self.start_process() assert list(self.b) == ['meta', 'health', 'state', 'disable', 'reset'] assert self.b.state.value == "Ready" assert self.b.disable.writeable is True assert self.b.reset.writeable is False def test_reset_fails_from_ready(self): self.start_process() with self.assertRaises(TypeError): self.o.reset() assert not self.part.reset_done def test_disable(self): self.start_process() assert not self.part.disable_done self.b.disable() assert self.part.disable_done assert self.b.state.value == "Disabled" with self.assertRaises(NotWriteableError) as cm: self.b.disable() assert str(cm.exception) == \ "Method ['MyMRI', 'disable'] is not writeable in state Disabled" assert not self.part.reset_done self.b.reset() assert self.part.reset_done assert self.b.state.value == "Ready" def test_run_hook(self): self.start_process() part_contexts = self.o.create_part_contexts() result = self.o.run_hooks( SaveHook(p, c) for p, c in part_contexts.items()) assert list(result) == ["testpart", "testpart2"] assert result["testpart"] == dict(foo="bartestpart") assert result["testpart2"] == dict(foo="bartestpart2") # The part.context is a weakref, so compare on one of its strong # methods instead assert self.part.context.sleep == part_contexts[self.part].sleep del part_contexts gc.collect() with self.assertRaises(ReferenceError): self.part.context.sleep(0) def test_run_hook_raises(self): self.start_process() class MyException(Exception): pass self.part.exception = MyException() with self.assertRaises(Exception) as cm: self.o.run_hooks( SaveHook(p, c) for p, c in self.o.create_part_contexts().items()) self.assertIs(self.part.context, None) self.assertIs(cm.exception, self.part.exception)
def child_block(): controllers, parts = adbase_parts(prefix="prefix") controller = StatefulController("WINDOWS:DETECTOR") for part in parts: controller.add_part(part) return controllers + [controller]
class TestManagerController(unittest.TestCase): maxDiff = None def setUp(self): self.p = Process('process1') # create a child to client self.c_child = StatefulController("childBlock") self.c_part = MyPart("cp1") self.c_child.add_part(self.c_part) self.p.add_controller(self.c_child) # create a root block for the ManagerController block to reside in if os.path.isdir("/tmp/mainBlock"): shutil.rmtree("/tmp/mainBlock") self.c = ManagerController('mainBlock', config_dir="/tmp") self.c.add_part(MyPart("part1")) self.c.add_part( ChildPart("part2", mri="childBlock", initial_visibility=True)) self.p.add_controller(self.c) self.b = self.p.block_view("mainBlock") # check that do_initial_reset works asynchronously assert self.c.state.value == "Disabled" self.p.start() assert self.c.state.value == "Ready" def tearDown(self): self.p.stop(timeout=1) def test_init(self): assert self.c.layout.value.name == ["part2"] assert self.c.layout.value.mri == ["childBlock"] assert self.c.layout.value.x == [0.0] assert self.c.layout.value.y == [0.0] assert self.c.layout.value.visible == [True] assert self.c.layout.meta.elements["name"].writeable is False assert self.c.layout.meta.elements["mri"].writeable is False assert self.c.layout.meta.elements["x"].writeable is True assert self.c.layout.meta.elements["y"].writeable is True assert self.c.layout.meta.elements["visible"].writeable is True assert self.c.design.value == "" assert self.c.exports.value.source == [] assert self.c.exports.meta.elements["source"].choices == \ ['part2.health', 'part2.state', 'part2.disable', 'part2.reset', 'part2.attr'] assert self.c.exports.value.export == [] assert self.c.modified.value is False assert self.c.modified.alarm.message == "" assert self.b.mri.value == "mainBlock" assert self.b.mri.meta.tags == ["sourcePort:block:mainBlock"] def check_expected_save(self, x=0.0, y=0.0, visible="true", attr="defaultv"): expected = [ x.strip() for x in ("""{ "attributes": { "layout": { "part2": { "x": %s, "y": %s, "visible": %s } }, "exports": {}, "attr": "defaultv" }, "children": { "part2": { "attr": "%s" } } }""" % (x, y, visible, attr)).splitlines() ] with open("/tmp/mainBlock/testSaveLayout.json") as f: actual = [x.strip() for x in f.readlines()] assert actual == expected def test_save(self): self.c._run_git_cmd = MagicMock() assert self.c.design.value == "" assert self.c.design.meta.choices == [""] c = Context(self.p) l = [] c.subscribe(["mainBlock", "design", "meta"], l.append) # Wait for long enough for the other process to get a look in c.sleep(0.1) assert len(l) == 1 assert l.pop()["choices"] == [""] b = c.block_view("mainBlock") b.save(design="testSaveLayout") assert len(l) == 3 assert l[0]["writeable"] == False assert l[1]["choices"] == ["", "testSaveLayout"] assert l[2]["writeable"] == True assert self.c.design.meta.choices == ["", "testSaveLayout"] self.check_expected_save() assert self.c.state.value == "Ready" assert self.c.design.value == 'testSaveLayout' assert self.c.modified.value is False os.remove("/tmp/mainBlock/testSaveLayout.json") self.c_part.attr.set_value("newv") assert self.c.modified.value is True assert self.c.modified.alarm.message == \ "part2.attr.value = 'newv' not 'defaultv'" self.c.save(design="") self.check_expected_save(attr="newv") assert self.c.design.value == 'testSaveLayout' assert self.c._run_git_cmd.call_args_list == [ call('add', '/tmp/mainBlock/testSaveLayout.json'), call('commit', '--allow-empty', '-m', 'Saved mainBlock testSaveLayout', '/tmp/mainBlock/testSaveLayout.json'), call('add', '/tmp/mainBlock/testSaveLayout.json'), call('commit', '--allow-empty', '-m', 'Saved mainBlock testSaveLayout', '/tmp/mainBlock/testSaveLayout.json') ] def move_child_block(self): new_layout = dict(name=["part2"], mri=["anything"], x=[10], y=[20], visible=[True]) self.b.layout.put_value(new_layout) def test_move_child_block_dict(self): assert self.b.layout.value.x == [0] self.move_child_block() assert self.b.layout.value.x == [10] def test_set_and_load_layout(self): new_layout = LayoutTable(name=["part2"], mri=["anything"], x=[10], y=[20], visible=[False]) self.c.set_layout(new_layout) assert self.c.parts['part2'].x == 10 assert self.c.parts['part2'].y == 20 assert self.c.parts['part2'].visible == False assert self.c.modified.value == True assert self.c.modified.alarm.message == "layout changed" # save the layout, modify and restore it self.b.save(design='testSaveLayout') assert self.c.modified.value is False self.check_expected_save(10.0, 20.0, "false") self.c.parts['part2'].x = 30 self.c.set_design('testSaveLayout') assert self.c.parts['part2'].x == 10 def test_set_export_parts(self): context = Context(self.p) b = context.block_view("mainBlock") assert list(b) == [ 'meta', 'health', 'state', 'disable', 'reset', 'mri', 'layout', 'design', 'exports', 'modified', 'save', 'attr' ] assert b.attr.meta.tags == ["widget:textinput"] new_exports = ExportTable.from_rows([('part2.attr', 'childAttr'), ('part2.reset', 'childReset')]) self.c.set_exports(new_exports) assert self.c.modified.value == True assert self.c.modified.alarm.message == "exports changed" self.c.save(design='testSaveLayout') assert self.c.modified.value == False # block has changed, get a new view b = context.block_view("mainBlock") assert list(b) == [ 'meta', 'health', 'state', 'disable', 'reset', 'mri', 'layout', 'design', 'exports', 'modified', 'save', 'attr', 'childAttr', 'childReset' ] assert self.c.state.value == "Ready" assert b.childAttr.value == "defaultv" assert self.c.modified.value == False m = MagicMock() f = b.childAttr.subscribe_value(m) # allow a subscription to come through context.sleep(0.1) m.assert_called_once_with("defaultv") m.reset_mock() self.c_part.attr.set_value("newv") assert b.childAttr.value == "newv" assert self.c_part.attr.value == "newv" assert self.c.modified.value == True assert self.c.modified.alarm.message == \ "part2.attr.value = 'newv' not 'defaultv'" # allow a subscription to come through context.sleep(0.1) m.assert_called_once_with("newv") b.childAttr.put_value("again") assert b.childAttr.value == "again" assert self.c_part.attr.value == "again" assert self.c.modified.value == True assert self.c.modified.alarm.message == \ "part2.attr.value = 'again' not 'defaultv'" # remove the field new_exports = ExportTable([], []) self.c.set_exports(new_exports) assert self.c.modified.value == True self.c.save() assert self.c.modified.value == False # block has changed, get a new view b = context.block_view("mainBlock") assert "childAttr" not in b
def create_block(self, p): c = StatefulController("mri") c.add_part(p) self.process.add_controller(c) b = self.process.block_view("mri") return b
class TestManagerController(unittest.TestCase): maxDiff = None def setUp(self): self.p = Process("process1") # create a child to client self.c_child = StatefulController("childBlock") self.c_part = MyPart("cp1") self.c_child.add_part(self.c_part) self.p.add_controller(self.c_child) # Create temporary config directory for ProcessController self.config_dir = tmp_dir("config_dir") self.main_block_name = "mainBlock" self.c = ManagerController("mainBlock", config_dir=self.config_dir.value) self.c.add_part(MyPart("part1")) self.c.add_part( ChildPart("part2", mri="childBlock", initial_visibility=True)) self.p.add_controller(self.c) self.b = self.p.block_view("mainBlock") # check that do_initial_reset works asynchronously assert self.c.state.value == "Disabled" self.p.start() assert self.c.state.value == "Ready" def tearDown(self): self.p.stop(timeout=1) shutil.rmtree(self.config_dir.value) def test_init(self): assert self.c.layout.value.name == ["part2"] assert self.c.layout.value.mri == ["childBlock"] assert self.c.layout.value.x == [0.0] assert self.c.layout.value.y == [0.0] assert self.c.layout.value.visible == [True] assert self.c.layout.meta.elements["name"].writeable is False assert self.c.layout.meta.elements["mri"].writeable is False assert self.c.layout.meta.elements["x"].writeable is True assert self.c.layout.meta.elements["y"].writeable is True assert self.c.layout.meta.elements["visible"].writeable is True assert self.c.design.value == "" assert self.c.exports.value.source == [] assert self.c.exports.meta.elements["source"].choices == [ "part2.health", "part2.state", "part2.disable", "part2.reset", "part2.attr", ] assert self.c.exports.value.export == [] assert self.c.modified.value is False assert self.c.modified.alarm.message == "" assert self.b.mri.value == "mainBlock" assert self.b.mri.meta.tags == ["sourcePort:block:mainBlock"] def _get_design_filename(self, block_name, design_name): return f"{self.config_dir.value}/{block_name}/{design_name}.json" def check_expected_save(self, design_name, x=0.0, y=0.0, visible="true", attr="defaultv"): expected = [ x.strip() for x in ("""{ "attributes": { "layout": { "part2": { "x": %s, "y": %s, "visible": %s } }, "exports": {}, "attr": "defaultv" }, "children": { "part2": { "attr": "%s" } } }""" % (x, y, visible, attr)).splitlines() ] with open(self._get_design_filename(self.main_block_name, design_name)) as f: actual = [x.strip() for x in f.readlines()] assert actual == expected def test_save(self): self.c._run_git_cmd = MagicMock() assert self.c.design.value == "" assert self.c.design.meta.choices == [""] c = Context(self.p) li = [] c.subscribe(["mainBlock", "design", "meta"], li.append) # Wait for long enough for the other process to get a look in c.sleep(0.1) assert len(li) == 1 assert li.pop()["choices"] == [""] b = c.block_view("mainBlock") design_name = "testSaveLayout" b.save(designName=design_name) assert len(li) == 3 assert li[0]["writeable"] is False assert li[1]["choices"] == ["", design_name] assert li[2]["writeable"] is True assert self.c.design.meta.choices == ["", design_name] self.check_expected_save(design_name) assert self.c.state.value == "Ready" assert self.c.design.value == design_name assert self.c.modified.value is False os.remove(self._get_design_filename(self.main_block_name, design_name)) self.c_part.attr.set_value("newv") assert self.c.modified.value is True assert (self.c.modified.alarm.message == "part2.attr.value = 'newv' not 'defaultv'") self.c.save(designName="") self.check_expected_save(design_name, attr="newv") design_filename = self._get_design_filename(self.main_block_name, design_name) assert self.c.design.value == "testSaveLayout" assert self.c._run_git_cmd.call_args_list == [ call("add", design_filename), call( "commit", "--allow-empty", "-m", "Saved mainBlock testSaveLayout", design_filename, ), call("add", design_filename), call( "commit", "--allow-empty", "-m", "Saved mainBlock testSaveLayout", design_filename, ), ] def move_child_block(self): new_layout = dict(name=["part2"], mri=["anything"], x=[10], y=[20], visible=[True]) self.b.layout.put_value(new_layout) def test_move_child_block_dict(self): assert self.b.layout.value.x == [0] self.move_child_block() assert self.b.layout.value.x == [10] def test_set_and_load_layout(self): new_layout = LayoutTable(name=["part2"], mri=["anything"], x=[10], y=[20], visible=[False]) self.c.set_layout(new_layout) assert self.c.parts["part2"].x == 10 assert self.c.parts["part2"].y == 20 assert self.c.parts["part2"].visible is False assert self.c.modified.value is True assert self.c.modified.alarm.message == "layout changed" # save the layout, modify and restore it design_name = "testSaveLayout" self.b.save(designName=design_name) assert self.c.modified.value is False self.check_expected_save(design_name, 10.0, 20.0, "false") self.c.parts["part2"].x = 30 self.c.set_design(design_name) assert self.c.parts["part2"].x == 10 def test_set_export_parts(self): context = Context(self.p) b = context.block_view("mainBlock") assert list(b) == [ "meta", "health", "state", "disable", "reset", "mri", "layout", "design", "exports", "modified", "save", "attr", ] assert b.attr.meta.tags == ["widget:textinput"] new_exports = ExportTable.from_rows([("part2.attr", "childAttr"), ("part2.reset", "childReset")]) self.c.set_exports(new_exports) assert self.c.modified.value is True assert self.c.modified.alarm.message == "exports changed" self.c.save(designName="testSaveLayout") assert self.c.modified.value is False # block has changed, get a new view b = context.block_view("mainBlock") assert list(b) == [ "meta", "health", "state", "disable", "reset", "mri", "layout", "design", "exports", "modified", "save", "attr", "childAttr", "childReset", ] assert self.c.state.value == "Ready" assert b.childAttr.value == "defaultv" assert self.c.modified.value is False m = MagicMock() b.childAttr.subscribe_value(m) # allow a subscription to come through context.sleep(0.1) m.assert_called_once_with("defaultv") m.reset_mock() self.c_part.attr.set_value("newv") assert b.childAttr.value == "newv" assert self.c_part.attr.value == "newv" assert self.c.modified.value is True assert (self.c.modified.alarm.message == "part2.attr.value = 'newv' not 'defaultv'") # allow a subscription to come through context.sleep(0.1) m.assert_called_once_with("newv") b.childAttr.put_value("again") assert b.childAttr.value == "again" assert self.c_part.attr.value == "again" assert self.c.modified.value is True assert (self.c.modified.alarm.message == "part2.attr.value = 'again' not 'defaultv'") # remove the field new_exports = ExportTable([], []) self.c.set_exports(new_exports) assert self.c.modified.value is True self.c.save() assert self.c.modified.value is False # block has changed, get a new view b = context.block_view("mainBlock") assert "childAttr" not in b