def setUp(self):
        self.maxDiff = 5000

        self.p = Process('process1', SyncFactory('threading'))

        # Make a ticker block to act as our child
        params = Ticker.MethodMeta.prepare_input_map(mri="childBlock")
        self.b_child = Ticker(self.p, params)[-1]

        # Make an empty part for our parent
        params = Part.MethodMeta.prepare_input_map(name='part1')
        part1 = Part(self.p, params)

        # Make a RunnableChildPart to control the ticker
        params = RunnableChildPart.MethodMeta.prepare_input_map(
            mri='childBlock', name='part2')
        part2 = RunnableChildPart(self.p, params)

        # create a root block for the RunnableController block to reside in
        params = RunnableController.MethodMeta.prepare_input_map(
            mri='mainBlock')
        self.c = RunnableController(self.p, [part1, part2], params)
        self.b = self.c.block
        self.sm = self.c.stateMachine

        # start the process off
        self.p.start()

        # wait until block is Ready
        task = Task("block_ready_task", self.p)
        task.when_matches(self.b["state"], self.sm.IDLE, timeout=1)

        self.checkState(self.sm.IDLE)
 def setUp(self):
     sf = SyncFactory("sync")
     self.process = Process("proc", sf)
     Hello(self.process, dict(mri="hello"))
     Counter(self.process, dict(mri="counter"))
     self.process.add_comms(
         WebsocketServerComms(self.process, dict(port=self.socket)))
     self.process.start()
     # If we don't wait long enough, sometimes the websocket_connect()
     # in process2 will hang...
     time.sleep(0.1)
     self.process2 = Process("proc2", sf)
     self.process2.add_comms(
         WebsocketClientComms(self.process2,
                          dict(hostname="localhost", port=self.socket)))
     self.process2.start()
    def setUp(self):
        self.p = Process("process1", SyncFactory("threading"))

        # create a child ManagerController block
        params = ManagerController.MethodMeta.prepare_input_map(mri="childBlock")
        self.c_child = ManagerController(self.p, [], params)
        self.b_child = self.c_child.block

        self.sm = self.c_child.stateMachine

        params = Part.MethodMeta.prepare_input_map(name="part1")
        part1 = Part(self.p, params)
        params = {"name": "part2", "mri": "childBlock"}
        params = ChildPart.MethodMeta.prepare_input_map(**params)
        part2 = ChildPart(self.p, params)

        # create a root block for the ManagerController block to reside in
        parts = [part1, part2]
        params = {"mri": "mainBlock"}
        params = ManagerController.MethodMeta.prepare_input_map(**params)
        self.c = ManagerController(self.p, parts, params)
        self.b = self.c.block

        # check that do_initial_reset works asynchronously
        self.p.start()

        # wait until block is Ready
        task = Task("block_ready_task", self.p)
        task.when_matches(self.b["state"], self.sm.READY, timeout=1)

        self.checkState(self.sm.READY)
Example #4
0
    def setUp(self):
        self.p = Process('process1', SyncFactory('threading'))

        self.p1, self.c1 = self.makeChildBlock('child1')
        self.p2, self.c2 = self.makeChildBlock('child2')
        self.p3, self.c3 = self.makeChildBlock('child3')

        # create a root block for the child blocks to reside in
        parts = [self.p1, self.p2, self.p3]
        params = RunnableController.MethodMeta.prepare_input_map(
            mri='mainBlock')
        self.c = RunnableController(self.p, parts, params)
        self.b = self.c.block

        params = ChildPart.MethodMeta.prepare_input_map(
            mri='mainBlock', name='mainPart')
        self.part = ChildPart(self.p, params)

        # Get the parent block into idle state
        self.p.start()

        # wait until block is Ready
        task = Task("block_ready_task", self.p)
        task.when_matches(self.c.block["state"], sm.IDLE, timeout=1)

        self.checkState(sm.IDLE)
Example #5
0
class TestSystemWSCommsServerAndClient(unittest.TestCase):
    socket = 8883

    def setUp(self):
        self.process = Process("proc")
        self.hello = call_with_params(hello_block, self.process, mri="hello")
        self.counter = call_with_params(
            counter_block, self.process, mri="counter")
        self.server = call_with_params(
            web_server_block, self.process, mri="server", port=self.socket)
        self.process.start()
        self.process2 = Process("proc2")
        self.client = call_with_params(
            websocket_client_block, self.process2, mri="client",
            port=self.socket)
        self.process2.start()

    def tearDown(self):
        self.socket += 1
        self.process.stop(timeout=1)
        self.process2.stop(timeout=1)

    def test_server_hello_with_malcolm_client(self):
        call_with_params(
            proxy_block, self.process2, mri="hello", comms="client")
        block2 = self.process2.block_view("hello")
        ret = block2.greet("me2")
        assert ret == dict(greeting="Hello me2")
        with self.assertRaises(ResponseError):
            block2.error()

    def test_server_counter_with_malcolm_client(self):
        call_with_params(
            proxy_block, self.process2, mri="counter", comms="client")
        block2 = self.process2.block_view("counter")
        assert block2.counter.value == 0
        block2.increment()
        assert block2.counter.value == 1
        block2.zero()
        assert block2.counter.value == 0
        assert self.client.remote_blocks.value == (
            "hello", "counter", "server")
Example #6
0
class TestSystemWSCommsServerOnly(unittest.TestCase):
    socket = 8881

    def setUp(self):
        self.process = Process("proc")
        self.hello = call_with_params(hello_block, self.process, mri="hello")
        self.server = call_with_params(
            web_server_block, self.process, mri="server", port=self.socket)
        self.result = Queue()
        self.process.start()

    def tearDown(self):
        self.process.stop(timeout=1)

    @gen.coroutine
    def send_message(self):
        conn = yield websocket_connect("ws://localhost:%s/ws" % self.socket)
        req = dict(
            typeid="malcolm:core/Post:1.0",
            id=0,
            path=["hello", "greet"],
            parameters=dict(
                name="me"
            )
        )
        conn.write_message(json.dumps(req))
        resp = yield conn.read_message()
        resp = json.loads(resp)
        self.result.put(resp)
        conn.close()

    def test_server_and_simple_client(self):
        self.server._loop.add_callback(self.send_message)
        resp = self.result.get(timeout=2)
        assert resp == dict(
            typeid="malcolm:core/Return:1.0",
            id=0,
            value=dict(
                typeid='malcolm:core/Map:1.0',
                greeting="Hello me",
            )
        )
    def setUp(self):
        self.p = Process('process1')
        self.context = Context(self.p)

        # Make a fast child, this will load the wait of 0.01 from saved file
        c1 = RunnableController(mri="fast",
                                config_dir=DESIGN_PATH,
                                use_git=False,
                                initial_design="fast")
        c1.add_part(WaitingPart("wait"))
        self.p.add_controller(c1)

        # And a slow one, this has the same saved files as fast, but doesn't
        # load at startup
        c2 = RunnableController(mri="slow",
                                config_dir=DESIGN_PATH,
                                use_git=False)
        c2.add_part(WaitingPart("wait", 0.123))
        self.p.add_controller(c2)

        # And a top level one, this loads slow and fast designs for the
        # children on every configure (or load), but not at init
        c3 = RunnableController(mri="top",
                                config_dir=DESIGN_PATH,
                                use_git=False,
                                initial_design="default")
        c3.add_part(
            RunnableChildPart(name="FAST", mri="fast",
                              initial_visibility=True))
        c3.add_part(
            RunnableChildPart(name="SLOW", mri="slow",
                              initial_visibility=True))
        self.p.add_controller(c3)

        # Some blocks to interface to them
        self.b = self.context.block_view("top")
        self.bf = self.context.block_view("fast")
        self.bs = self.context.block_view("slow")

        # start the process off
        self.p.start()
class TestXspress3DetectorDriverPart(ChildTestCase):

    def setUp(self):
        self.process = Process("Process")
        self.context = Context(self.process)
        self.child = self.create_child_block(
            xspress3_detector_driver_block, self.process,
            mri="mri", prefix="prefix")
        choices = ["Single", "Multiple", "Continuous"]
        self.child.parts["imageMode"].attr.meta.set_choices(choices)
        self.o = call_with_params(
            Xspress3DriverPart, readoutTime=0.002, name="m", mri="mri")
        list(self.o.create_attribute_models())
        self.process.start()

    def tearDown(self):
        del self.context
        self.process.stop(timeout=2)

    def test_configure(self):
        params = MagicMock()
        xs = LineGenerator("x", "mm", 0.0, 0.5, 3000, alternate=True)
        ys = LineGenerator("y", "mm", 0.0, 0.1, 2000)
        params.generator = CompoundGenerator([ys, xs], [], [], 0.1)
        params.generator.prepare()
        completed_steps = 0
        steps_to_do = 2000*3000
        part_info = ANY
        self.o.configure(
            self.context, completed_steps, steps_to_do, part_info, params)
        # Need to wait for the spawned mock start call to run
        self.o.start_future.result()
        assert self.child.handled_requests.mock_calls == [
            call.put('pointsPerRow', 15000),
            call.put('triggerMode', 'Hardware'),
            call.put('arrayCallbacks', True),
            call.put('arrayCounter', 0),
            call.put('imageMode', 'Multiple'),
            call.put('numImages', 6000000),
            call.put('exposure', 0.098),
            call.post('start')]
Example #9
0
 def setUp(self):
     self.process = Process("Process")
     self.context = Context(self.process)
     pmac_block = make_block_creator(__file__,
                                     "test_pmac_manager_block.yaml")
     self.child = self.create_child_block(pmac_block,
                                          self.process,
                                          mri_prefix="PMAC",
                                          config_dir="/tmp")
     # These are the child blocks we are interested in
     self.child_x = self.process.get_controller("BL45P-ML-STAGE-01:X")
     self.child_y = self.process.get_controller("BL45P-ML-STAGE-01:Y")
     self.child_cs1 = self.process.get_controller("PMAC:CS1")
     self.child_traj = self.process.get_controller("PMAC:TRAJ")
     self.child_status = self.process.get_controller("PMAC:STATUS")
     # CS1 needs to have the right port otherwise we will error
     self.set_attributes(self.child_cs1, port="CS1")
     self.o = PmacChildPart(name="pmac", mri="PMAC")
     self.context.set_notify_dispatch_request(
         self.o.notify_dispatch_request)
     self.process.start()
Example #10
0
    def setUp(self):
        self.p = Process("process1")

        self.p1, self.c1 = self.makeChildBlock("child1")
        self.p2, self.c2 = self.makeChildBlock("child2")
        self.p3, self.c3 = self.makeChildBlock("child3")
        self.c1._block.sinkportConnector.set_value("Connector3")
        self.c2._block.sinkportConnector.set_value("Connector1")
        self.c3._block.sinkportConnector.set_value("Connector2")

        # create a root block for the child blocks to reside in
        self.c = ManagerController(mri="mainBlock", config_dir="/tmp")
        for part in [self.p1, self.p2, self.p3]:
            self.c.add_part(part)
        self.p.add_controller(self.c)

        # Start the process
        # check that do_initial_reset works asynchronously
        assert self.c.state.value == sm.DISABLED
        self.p.start()
        assert self.c.state.value == sm.READY
Example #11
0
class TestHelloDemoSystem(unittest.TestCase):
    def setUp(self):
        self.process = Process("proc")
        parts = [call_with_params(HelloPart, name="hpart")]
        self.controller = Controller(self.process, "hello_block", parts)
        self.process.start()

    def tearDown(self):
        self.process.stop(timeout=1)

    def test_hello_good_input(self):
        q = Queue()
        request = Post(id=44,
                       path=["hello_block", "greet"],
                       parameters=dict(name="thing"),
                       callback=q.put)
        self.controller.handle_request(request)
        response = q.get(timeout=1.0)
        self.assertIsInstance(response, Return)
        assert response.id == 44
        assert response.value["greeting"] == "Hello thing"
class TestSystemWSCommsServerOnly(unittest.TestCase):
    socket = 8881

    def setUp(self):
        self.process = Process("proc", SyncFactory("sync"))
        Hello(self.process, dict(mri="hello"))
        self.process.add_comms(
            WebsocketServerComms(self.process, dict(port=self.socket)))
        self.process.start()

    def tearDown(self):
        self.process.stop()

    @gen.coroutine
    def send_message(self):
        conn = yield websocket_connect("ws://localhost:%s/ws" % self.socket)
        req = dict(type="malcolm:core/Post:1.0",
                   id=0,
                   endpoint=["hello", "greet"],
                   parameters=dict(name="me"))
        conn.write_message(json.dumps(req))
        resp = yield conn.read_message()
        resp = json.loads(resp)
        self.assertEqual(
            resp,
            dict(id=0,
                 type="malcolm:core/Return:1.0",
                 value=dict(greeting="Hello me")))
        conn.close()

    def test_server_and_simple_client(self):
        self.send_message()
Example #13
0
class TestCSPart(ChildTestCase):
    def setUp(self):
        self.process = Process("Process")
        self.child = self.create_child_block(cs_block,
                                             self.process,
                                             mri="PMAC:CS1",
                                             pv_prefix="PV:PRE")
        self.set_attributes(self.child, port="PMAC2CS1")
        c = ManagerController("PMAC", "/tmp")
        c.add_part(CSPart(mri="PMAC:CS1", cs=1))
        self.process.add_controller(c)
        self.process.start()
        self.b = c.block_view()

    def tearDown(self):
        self.process.stop(timeout=1)

    def test_init(self):
        assert "moveCS1" in self.b

    def test_move(self):
        self.mock_when_value_matches(self.child)
        # Move time is converted into milliseconds
        move_time = 2.3
        expected_move_time = move_time * 1000.0
        self.b.moveCS1(a=32, c=19.1, moveTime=move_time)
        assert self.child.handled_requests.mock_calls == [
            call.put("deferMoves", True),
            call.put("csMoveTime", expected_move_time),
            call.put("demandA", 32),
            call.put("demandC", 19.1),
            call.when_value_matches("demandA", 32, None),
            call.when_value_matches("demandC", 19.1, None),
            call.put("deferMoves", False),
        ]
class TestStatefulController(unittest.TestCase):
    def setUp(self):
        self.process = Process("proc")
        self.params = Mock()
        self.params.mri = "MyMRI"
        self.params.description = "My description"
        self.part = MyPart("testpart")
        self.o = StatefulController(self.process, [self.part], self.params)
        self.process.add_controller(self.params.mri, self.o)

    def start_process(self):
        self.process.start()
        self.addCleanup(self.stop_process)

    def stop_process(self):
        if self.process.started:
            self.process.stop(timeout=1)

    def test_process_init(self, ):
        assert not hasattr(self.part, "started")
        self.start_process()
        assert self.part.started

    def test_process_stop(self):
        self.start_process()
        assert not hasattr(self.part, "halted")
        self.process.stop(timeout=1)
        assert self.part.halted

    def test_init(self):
        assert self.o.state.value == "Disabled"
        self.start_process()
        assert self.o.state.value == "Ready"

    def test_reset_fails_from_ready(self):
        self.start_process()
        with self.assertRaises(TypeError):
            self.o.reset()
        assert not hasattr(self.part, "reset_done")

    def test_disable(self):
        self.start_process()
        assert not hasattr(self.part, "disable_done")
        self.o.disable()
        assert self.part.disable_done
        assert self.o.state.value == "Disabled"
        assert not hasattr(self.part, "reset_done")
        self.o.reset()
        assert self.part.reset_done
        assert self.o.state.value == "Ready"
Example #15
0
class TestMotorPreMovePart(ChildTestCase):
    def setUp(self):
        self.process = Process("test_process")
        self.context = Context(self.process)

        # Create a raw motor mock to handle axis request
        self.child = self.create_child_block(raw_motor_block,
                                             self.process,
                                             mri="BS",
                                             pv_prefix="PV:PRE")
        # Add Beam Selector object
        self.o = MotorPreMovePart(name="MotorPreMovePart", mri="BS", demand=50)

        controller = RunnableController("SCAN", "/tmp")
        controller.add_part(self.o)

        self.process.add_controller(controller)
        self.process.start()

    def tearDown(self):
        del self.context
        self.process.stop(timeout=1)

    def test_bs(self):
        b = self.context.block_view("SCAN")
        generator = CompoundGenerator([LineGenerator("x", "mm", 0, 1, 10)], [],
                                      [], 0.1)
        b.configure(generator)

        self.o.on_configure(self.context)

        assert self.child.handled_requests.mock_calls == [
            call.put("demand", 50)
        ]
Example #16
0
class TestLabelPart(unittest.TestCase):
    def setUp(self):
        self.o = call_with_params(LabelPart,
                                  initialValue="My label",
                                  group="mygroup")
        self.p = Process("proc")
        self.c = Controller(self.p, "mri", [self.o])
        self.p.add_controller("mri", self.c)
        self.p.start()
        self.b = self.c.block_view()

    def tearDown(self):
        self.p.stop(1)

    def test_init(self):
        assert self.o.name == "label"
        assert self.o.attr.value == "My label"
        assert self.o.attr.meta.tags == ("widget:textinput", "config",
                                         "group:mygroup")
        assert self.b.meta.label == "My label"

    def test_setter(self):
        self.b.label.put_value("My label2")
        assert self.b.label.value == "My label2"
        assert self.b.meta.label == "My label2"
Example #17
0
    def setUp(self):
        self.p = Process("process1")
        self.context = Context(self.p)

        self.p2 = Process("process2")
        self.context2 = Context(self.p2)

        # Make a motion block to act as our child
        for c in motion_block(mri="childBlock", config_dir="/tmp"):
            self.p.add_controller(c)
        self.b_child = self.context.block_view("childBlock")

        # create a root block for the RunnableController block to reside in
        self.c = RunnableController(mri="mainBlock", config_dir="/tmp")
        self.p.add_controller(self.c)
        self.b = self.context.block_view("mainBlock")
        self.ss = self.c.state_set

        # start the process off
        self.checkState(self.ss.DISABLED)
        self.p.start()
        self.checkState(self.ss.READY)
    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 setUp(self):
        self.process = Process("Process")
        self.context = Context(self.process)

        def child_block():
            controllers, parts = adbase_parts(prefix="prefix")
            controller = StatefulController("WINDOWS:DETECTOR")
            for part in parts:
                controller.add_part(part)
            return controllers + [controller]

        self.child = self.create_child_block(child_block, self.process)
        self.mock_when_value_matches(self.child)
        self.o = DetectorDriverPart(
            name="m",
            mri="WINDOWS:DETECTOR",
            soft_trigger_modes=["Internal"],
            runs_on_windows=True,
        )
        self.context.set_notify_dispatch_request(
            self.o.notify_dispatch_request)
        self.process.start()
    def setUp(self):
        self.process = Process("Process")
        self.context = Context(self.process)
        self.config_dir = tmp_dir("config_dir")
        pmac_block = make_block_creator(__file__,
                                        "test_pmac_manager_block.yaml")
        self.child = self.create_child_block(
            pmac_block,
            self.process,
            mri_prefix="PMAC",
            config_dir=self.config_dir.value,
        )
        # These are the child blocks we are interested in
        self.child_x = self.process.get_controller("BL45P-ML-STAGE-01:X")
        # self.child_y = self.process.get_controller(
        #    "BL45P-ML-STAGE-01:Y")
        self.child_cs1 = self.process.get_controller("PMAC:CS1")
        self.child_traj = self.process.get_controller("PMAC:TRAJ")
        self.child_status = self.process.get_controller("PMAC:STATUS")

        # CS1 needs to have the right port otherwise we will error
        self.set_attributes(self.child_cs1, port="CS1")
        self.move_time = 0.5
        self.o = BeamSelectorPart(
            name="beamSelector",
            mri="PMAC",
            selector_axis="x",
            imaging_angle=0,
            diffraction_angle=0.5,
            imaging_detector="imagingDetector",
            diffraction_detector="diffDetector",
            move_time=self.move_time,
        )
        self.context.set_notify_dispatch_request(
            self.o.notify_dispatch_request)
        self.process.start()

        pass
Example #21
0
class TestBrickPart(ChildTestCase):
    def setUp(self):
        self.process = Process("Process")
        self.context = Context(self.process)
        child = self.create_child_block(brick_block,
                                        self.process,
                                        mri="my_mri",
                                        prefix="PV:PRE")
        self.set_attributes(child, i10=1705244)
        self.o = BrickPart(name="part", mri="my_mri")
        self.process.start()

    def tearDown(self):
        self.process.stop(timeout=1)

    def test_init(self):
        registrar = Mock()
        self.o.setup(registrar)
        self.assert_hooked(self.o, ReportStatusHook, self.o.report_status)

    def test_report(self):
        returns = self.o.report_status(self.context)
        assert returns.i10 == 1705244
    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"
Example #23
0
    def setUp(self):
        self.p = Process("process")
        self.context = Context(self.p)

        # Make a motion block to act as our child
        for c in motion_block(mri="childBlock", config_dir="/tmp"):
            self.p.add_controller(c)
        self.b_child = self.context.block_view("childBlock")

        part = MisbehavingPart(mri="childBlock",
                               name="part",
                               initial_visibility=True)

        # create a root block for the RunnableController block to reside in
        self.c = RunnableController(mri="mainBlock", config_dir="/tmp")
        self.c.add_part(part)
        self.p.add_controller(self.c)
        self.b = self.context.block_view("mainBlock")
        self.ss = self.c.state_set

        # start the process off
        self.checkState(self.ss.DISABLED)
        self.p.start()
        self.checkState(self.ss.READY)
Example #24
0
    def setUp(self):
        self.p = Process('process1')

        self.p1, self.c1 = self.makeChildBlock('child1')
        self.p2, self.c2 = self.makeChildBlock('child2')
        self.p3, self.c3 = self.makeChildBlock('child3')
        self.c1._block.inportConnector.set_value('Connector3')
        self.c2._block.inportConnector.set_value('Connector1')
        self.c3._block.inportConnector.set_value('Connector2')

        # create a root block for the child blocks to reside in
        parts = [self.p1, self.p2, self.p3]
        self.c = call_with_params(ManagerController,
                                  self.p,
                                  parts,
                                  mri='mainBlock',
                                  configDir="/tmp")
        self.p.add_controller('mainBlock', self.c)

        # Start the process
        # check that do_initial_reset works asynchronously
        assert self.c.state.value == sm.DISABLED
        self.p.start()
        assert self.c.state.value == sm.READY
Example #25
0
def prepare_locals(args):
    from malcolm.core import Process
    from malcolm.yamlutil import make_include_creator

    if args.yaml:
        proc_name = os.path.basename(args.yaml).split(".")[-2]
        proc = Process(proc_name)
        controllers, parts = make_include_creator(args.yaml)()
        assert not parts, f"{args.yaml} defines parts"
        for controller in controllers:
            proc.add_controller(controller)
        proc_name = f"{proc_name} - imalcolm"
    else:
        proc = Process("Process")
        proc_name = "imalcolm"
    # set terminal title
    sys.stdout.write(f"]0;{proc_name}")

    if args.client:
        if args.client.startswith("ws://"):
            from malcolm.modules.web.controllers import WebsocketClientComms

            hostname, port = args.client[5:].split(":")
            comms = WebsocketClientComms(mri=f"{hostname}:{port}",
                                         hostname=hostname,
                                         port=int(port))
        elif args.client == "pva":
            from malcolm.modules.pva.controllers import PvaClientComms

            comms = PvaClientComms(mri="pva")
        else:
            raise ValueError(
                f"Don't know how to create client to {args.client}")
        proc.add_controller(comms)
    proc.start(timeout=60)
    return proc
Example #26
0
class TestStatsPluginPart(ChildTestCase):

    def setUp(self):
        self.process = Process("Process")
        self.context = Context(self.process)
        self.child = self.create_child_block(
            stats_plugin_block, self.process,
            mri="BLOCK-STAT", prefix="prefix")
        self.o = StatsPluginPart(name="m", mri="BLOCK-STAT")
        self.process.start()

    def tearDown(self):
        self.process.stop(timeout=2)

    def test_report_info(self):
        infos = self.o.report_status()
        assert len(infos) == 1
        assert infos[0].name == "sum"
        assert infos[0].attr == "STATS_TOTAL"

    def test_configure(self):
        fileDir = "/tmp"
        infos = self.o.configure(self.context, fileDir)
        assert infos is None
        expected_filename = "/tmp/BLOCK-STAT-attributes.xml"
        assert self.child.handled_requests.mock_calls == [
            call.put('computeStatistics', True),
            call.put('enableCallbacks', True),
            call.put('attributesFile', expected_filename)]
        expected_xml = """<?xml version="1.0" ?>
<Attributes>
<Attribute addr="0" datatype="DOUBLE" description="Sum of the array" name="STATS_TOTAL" source="TOTAL" type="PARAM" />
</Attributes>"""
        with open(expected_filename) as f:
            actual_xml = f.read().replace(">", ">\n")
        assert actual_xml.splitlines() == expected_xml.splitlines()
    def test_clear_raises_if_running(self):
        proc = Process("proc", SyncFactory("sync"))
        t = Task("testTask", proc)
        import time

        def f():
            time.sleep(0.05)

        t.define_spawn_function(f)
        start = time.time()
        t.start()
        self.assertRaises(AssertionError, t.define_spawn_function, None)
        t.wait()
        end = time.time()
        self.assertAlmostEqual(end - start, 0.05, delta=0.005)
        t.define_spawn_function(None)
Example #28
0
class TestCounterDemoSystem(unittest.TestCase):
    def setUp(self):
        self.process = Process("proc")
        self.controller = Controller("counting")
        self.controller.add_part(CounterPart("cpart"))
        self.process.add_controller(self.controller)
        self.process.start()

    def tearDown(self):
        self.process.stop(timeout=1)

    def test_counter_subscribe(self):
        q = Queue()
        # Subscribe to the value
        sub = Subscribe(id=20, path=["counting", "counter"], delta=False)
        sub.set_callback(q.put)
        self.controller.handle_request(sub)
        # Check initial return
        response = q.get(timeout=1.0)
        self.assertIsInstance(response, Update)
        assert response.id == 20
        assert response.value["typeid"] == "epics:nt/NTScalar:1.0"
        assert response.value["value"] == 0
        # Post increment()
        post = Post(id=21, path=["counting", "increment"])
        post.set_callback(q.put)
        self.controller.handle_request(post)
        # Check the value updates...
        response = q.get(timeout=1)
        self.assertIsInstance(response, Update)
        assert response.id == 20
        assert response.value["value"] == 1
        # ... then we get the return
        response = q.get(timeout=1)
        self.assertIsInstance(response, Return)
        assert response.id == 21
        assert response.value is None
        # Check we can put too
        put = Put(id=22, path=["counting", "counter", "value"], value=31)
        put.set_callback(q.put)
        self.controller.handle_request(put)
        # Check the value updates...
        response = q.get(timeout=1)
        self.assertIsInstance(response, Update)
        assert response.id == 20
        assert response.value["value"] == 31
        # ... then we get the return
        response = q.get(timeout=1)
        self.assertIsInstance(response, Return)
        assert response.id == 22
        assert response.value is None
        # And that there isn't anything else
        with self.assertRaises(TimeoutError):
            q.get(timeout=0.05)
Example #29
0
class TestSystemRest(unittest.TestCase):
    socket = 8886

    def setUp(self):
        self.process = Process("proc")
        self.hello = hello_block(mri="hello")[-1]
        self.process.add_controller(self.hello)
        self.server = web_server_block(mri="server", port=self.socket)[-1]
        self.process.add_controller(self.server)
        self.result = Queue()
        self.http_client = AsyncHTTPClient()
        self.process.start()

    def tearDown(self):
        self.process.stop(timeout=1)

    @gen.coroutine
    def get(self, mri):
        result = yield self.http_client.fetch("http://localhost:%s/rest/%s" %
                                              (self.socket, mri))
        cothread.Callback(self.result.put, result)

    @gen.coroutine
    def post(self, mri, method, args):
        req = HTTPRequest(
            "http://localhost:%s/rest/%s/%s" % (self.socket, mri, method),
            method="POST",
            body=args,
        )
        result = yield self.http_client.fetch(req)
        cothread.Callback(self.result.put, result)

    def test_get_hello(self):
        IOLoopHelper.call(self.get, "hello")
        result = self.result.get(timeout=2)
        assert result.body.decode().strip() == json_encode(self.hello._block)

    def test_post_hello(self):
        IOLoopHelper.call(self.post, "hello", "greet",
                          json_encode(dict(name="me")))
        result = self.result.get(timeout=2)
        assert result.body.decode().strip() == json_encode("Hello me")
    def setUp(self):
        self.process = Process()
        self.context = Context(self.process)

        # Create a PandA to which this part communicates
        self.panda = ManagerController("ML-PANDA-01", "/tmp")

        # Create a block for this part
        self.child = self.create_child_block(
            panda_alternating_div_block,
            self.process,
            mri="ML-DIV-01",
            panda="ML-PANDA-01",
        )

        self.part_under_test = PandAAlternatingDivPart(
            name="alternatingDivPart", mri="ML-DIV-01"
        )
Example #31
0
class TestMotionBlock(unittest.TestCase):
    def setUp(self):
        self.p = Process("proc")
        for c in motion_block("mri", config_dir="/tmp"):
            self.p.add_controller(c)
        self.p.start()
        self.b = self.p.block_view("mri")
        self.bx = self.p.block_view("mri:COUNTERX")
        self.by = self.p.block_view("mri:COUNTERY")

    def tearDown(self):
        self.p.stop()

    def test_move(self):
        assert self.bx.counter.value == 0
        self.b.xMove(32)
        assert self.bx.counter.value == 32
        assert self.by.counter.value == 0
        self.b.yMove(31)
        assert self.by.counter.value == 31
class TestSystemWSCommsServerAndClient(unittest.TestCase):
    socket = 8882

    def setUp(self):
        self.sf = SyncFactory("sync")
        self.process = Process("proc", self.sf)
        DefaultController("hello",
                          self.process,
                          parts=dict(hello=HelloPart(self.process, None)))
        DefaultController("counter",
                          self.process,
                          parts=dict(counter=CounterPart(self.process, None)))
        WebsocketServerComms(self.process, dict(port=self.socket))
        self.process.start()
        self.process2 = Process("proc2", self.sf)
        WebsocketClientComms(self.process2,
                             dict(hostname="localhost", port=self.socket))
        self.process2.start()

    def tearDown(self):
        self.process.stop()
        self.process2.stop()
        self.socket += 1

    def test_server_hello_with_malcolm_client(self):
        block2 = ClientController('hello', self.process2).block
        task = Task("task", self.process2)
        futures = task.when_matches(block2["state"], "Ready")
        task.wait_all(futures, timeout=1)
        ret = block2.say_hello("me2")
        self.assertEqual(ret, dict(greeting="Hello me2"))

    def test_server_counter_with_malcolm_client(self):
        block2 = ClientController('counter', self.process2).block
        task = Task("task", self.process2)
        futures = task.when_matches(block2["state"], "Ready")
        task.wait_all(futures, timeout=1)
        self.assertEqual(block2.counter, 0)
        block2.increment()
        self.assertEqual(block2.counter, 1)
Example #33
0
 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")
     catools.caput.reset_mock()
     catools.caget.side_effect = ["No Good", "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()
        self.context = Context(self.process)

        self.detector_mri = "ML-DET-01"
        self.block_mri = "ML-MULTI-01"

        # Create a detector to which this part communicates
        self.detector = ManagerController(self.detector_mri, "/tmp")

        # Create a block for this part
        self.child = self.create_child_block(
            double_trigger_block,
            self.process,
            mri=self.block_mri,
            detector=self.detector_mri,
        )

        self.double_trigger_part = DoubleTriggerPart(
            name="detectorDoubleTriggers", mri=self.block_mri)
class TestSystemWSCommsServerOnly(unittest.TestCase):
    socket = 8881

    def setUp(self):
        self.process = Process("proc", SyncFactory("sync"))
        Hello(self.process, dict(mri="hello"))
        self.process.add_comms(
            WebsocketServerComms(self.process, dict(port=self.socket)))
        self.process.start()

    def tearDown(self):
        self.process.stop()

    @gen.coroutine
    def send_message(self):
        conn = yield websocket_connect("ws://localhost:%s/ws" % self.socket)
        req = dict(
            type="malcolm:core/Post:1.0",
            id=0,
            endpoint=["hello", "greet"],
            parameters=dict(
                name="me"
            )
        )
        conn.write_message(json.dumps(req))
        resp = yield conn.read_message()
        resp = json.loads(resp)
        self.assertEqual(resp, dict(
            id=0,
            type="malcolm:core/Return:1.0",
            value=dict(
                greeting="Hello me"
            )
        ))
        conn.close()

    def test_server_and_simple_client(self):
        self.send_message()
Example #36
0
class TestChildPart(unittest.TestCase):

    def checkState(self, state):
        self.assertEqual(self.c.state.value, state)

    def makeChildBlock(self, blockMri):
        params = PortsPart.MethodMeta.prepare_input_map(name='Connector')
        port_part = PortsPart(self.p, params)

        partName = 'part%s' % blockMri
        params = DefaultController.MethodMeta.prepare_input_map(mri=blockMri)
        controller = DefaultController(self.p, [port_part], params)

        params = ChildPart.MethodMeta.prepare_input_map(
            mri=blockMri, name=partName)
        part = ChildPart(self.p, params)

        return part, controller

    def setUp(self):
        self.p = Process('process1', SyncFactory('threading'))

        self.p1, self.c1 = self.makeChildBlock('child1')
        self.p2, self.c2 = self.makeChildBlock('child2')
        self.p3, self.c3 = self.makeChildBlock('child3')

        # create a root block for the child blocks to reside in
        parts = [self.p1, self.p2, self.p3]
        params = RunnableController.MethodMeta.prepare_input_map(
            mri='mainBlock')
        self.c = RunnableController(self.p, parts, params)
        self.b = self.c.block

        params = ChildPart.MethodMeta.prepare_input_map(
            mri='mainBlock', name='mainPart')
        self.part = ChildPart(self.p, params)

        # Get the parent block into idle state
        self.p.start()

        # wait until block is Ready
        task = Task("block_ready_task", self.p)
        task.when_matches(self.c.block["state"], sm.IDLE, timeout=1)

        self.checkState(sm.IDLE)

    def tearDown(self):
        self.p.stop()

    def test_init(self):
        # check instantiation of object tree via logger names
        self.assertEqual(self.c._logger.name,
                         'RunnableController(mainBlock)')
        self.assertEqual(self.c.parts['partchild1']._logger.name,
                         'RunnableController(mainBlock).partchild1')
        self.assertEqual(self.c.parts['partchild2']._logger.name,
                         'RunnableController(mainBlock).partchild2')
        self.assertEqual(self.c.parts['partchild3']._logger.name,
                         'RunnableController(mainBlock).partchild3')

        self.assertEqual(self.c1.parts['Connector']._logger.name,
                         'DefaultController(child1).Connector')
        self.assertEqual(self.c2.parts['Connector']._logger.name,
                         'DefaultController(child2).Connector')
        self.assertEqual(self.c3.parts['Connector']._logger.name,
                         'DefaultController(child3).Connector')

        self.assertEqual(self.c1.block.inportConnector, '')
        self.assertEqual(self.c1.block.outportConnector, '')

    def test_reset(self):
        # TODO cover the clause 'state == RESETTING'
        self.c.disable()
        self.checkState(sm.DISABLED)
        self.c.reset()
        self.checkState(sm.IDLE)

    def test_pre_layout(self):
        outports = self.p1.pre_layout(None)
        self.assertEqual(len(outports), 1)

    def test_layout(self):
        self.c.edit()
        self.checkState(sm.EDITABLE)

        new_layout = Table(self.c.layout.meta)
        new_layout.name = ["partchild1", "partchild2", "partchild3"]
        new_layout.mri = ["part1", "part2", "part3"]
        new_layout.x = [10, 11, 12]
        new_layout.y = [20, 21, 22]
        new_layout.visible = [True, True, True]
        self.b.layout = new_layout
        self.assertEqual(self.c.parts['partchild1'].x, 10)
        self.assertEqual(self.c.parts['partchild1'].y, 20)
        self.assertEqual(self.c.parts['partchild1'].visible, True)
        self.assertEqual(self.c.parts['partchild2'].x, 11)
        self.assertEqual(self.c.parts['partchild2'].y, 21)
        self.assertEqual(self.c.parts['partchild2'].visible, True)
        self.assertEqual(self.c.parts['partchild3'].x, 12)
        self.assertEqual(self.c.parts['partchild3'].y, 22)
        self.assertEqual(self.c.parts['partchild3'].visible, True)

        new_layout.visible = [True, False, True]
        self.b.layout= new_layout
        self.assertEqual(self.c.parts['partchild1'].visible, True)
        self.assertEqual(self.c.parts['partchild2'].visible, False)
        self.assertEqual(self.c.parts['partchild3'].visible, True)

    def test_sever_all_inports(self):
        self.c1.block.inportConnector = 'Connector'
        self.c2.block.inportConnector = 'Connector'
        self.c3.block.inportConnector = 'Connector3'

        task = Task("Task1" , self.p)
        self.p1.sever_all_inports(task)
        task.wait_all([],5)
        self.assertEqual(self.c1.block.inportConnector, '')
        self.assertEqual(self.c2.block.inportConnector, 'Connector')
        self.assertEqual(self.c3.block.inportConnector, 'Connector3')

    def test_sever_inports_connected_to(self):
        self.c1.block.inportConnector = 'Connector'

        self.assertEqual(self.c1.block.inportConnector, 'Connector')

        task = Task("Task1" , self.p)
        out_port = {'Connector': 'pos'}
        self.p1.sever_inports_connected_to(task, out_port)
        self.assertEqual(self.c1.block.inportConnector, '')

    def test_get_flowgraph_ports(self):
        count = len(self.p1._get_flowgraph_ports('out'))
        self.assertEqual(count, 1)
        count = len(self.p1._get_flowgraph_ports('in'))
        self.assertEqual(count, 1)
class TestRunnableController(unittest.TestCase):

    def checkState(self, state, child=True, parent=True):
        if child:
            self.assertEqual(self.b_child.state, state)
        if parent:
            self.assertEqual(self.b.state, state)

    def checkSteps(self, configured, completed, total):
        self.assertEqual(self.b.configuredSteps, configured)
        self.assertEqual(self.b.completedSteps, completed)
        self.assertEqual(self.b.totalSteps, total)
        self.assertEqual(self.b_child.configuredSteps, configured)
        self.assertEqual(self.b_child.completedSteps, completed)
        self.assertEqual(self.b_child.totalSteps, total)

    def setUp(self):
        self.maxDiff = 5000

        self.p = Process('process1', SyncFactory('threading'))

        # Make a ticker block to act as our child
        params = Ticker.MethodMeta.prepare_input_map(mri="childBlock")
        self.b_child = Ticker(self.p, params)[-1]

        # Make an empty part for our parent
        params = Part.MethodMeta.prepare_input_map(name='part1')
        part1 = Part(self.p, params)

        # Make a RunnableChildPart to control the ticker
        params = RunnableChildPart.MethodMeta.prepare_input_map(
            mri='childBlock', name='part2')
        part2 = RunnableChildPart(self.p, params)

        # create a root block for the RunnableController block to reside in
        params = RunnableController.MethodMeta.prepare_input_map(
            mri='mainBlock')
        self.c = RunnableController(self.p, [part1, part2], params)
        self.b = self.c.block
        self.sm = self.c.stateMachine

        # start the process off
        self.p.start()

        # wait until block is Ready
        task = Task("block_ready_task", self.p)
        task.when_matches(self.b["state"], self.sm.IDLE, timeout=1)

        self.checkState(self.sm.IDLE)

    def tearDown(self):
        self.p.stop()

    def test_init(self):
        # the following block attributes should be created by a call to
        # set_attributes via _set_block_children in __init__
        self.assertEqual(self.b['totalSteps'].meta.typeid,
                         'malcolm:core/NumberMeta:1.0')
        self.assertEqual(self.b['layout'].meta.typeid,
                         'malcolm:core/TableMeta:1.0')
        self.assertEqual(self.b['completedSteps'].meta.typeid,
                         'malcolm:core/NumberMeta:1.0')
        self.assertEqual(self.b['configuredSteps'].meta.typeid,
                         'malcolm:core/NumberMeta:1.0')
        self.assertEqual(self.b['axesToMove'].meta.typeid,
                         'malcolm:core/StringArrayMeta:1.0')
        self.assertEqual(self.b['layoutName'].meta.typeid,
                         'malcolm:core/StringMeta:1.0')

        # the following hooks should be created via _find_hooks in __init__
        self.assertEqual(self.c.hook_names, {
            self.c.Reset: "Reset",
            self.c.Disable: "Disable",
            self.c.ReportOutports: "ReportOutports",
            self.c.Layout: "Layout",
            self.c.Load: "Load",
            self.c.Save: "Save",
            self.c.Validate: "Validate",
            self.c.ReportStatus: "ReportStatus",
            self.c.Configure: "Configure",
            self.c.PostConfigure: "PostConfigure",
            self.c.Run: "Run",
            self.c.PostRunReady: "PostRunReady",
            self.c.PostRunIdle: "PostRunIdle",
            self.c.Seek: "Seek",
            self.c.Pause: "Pause",
            self.c.Resume: "Resume",
            self.c.Abort: "Abort",
        })

        # check instantiation of object tree via logger names
        self.assertEqual(self.c._logger.name,
                         'RunnableController(mainBlock)')
        self.assertEqual(self.c.parts['part1']._logger.name,
                         'RunnableController(mainBlock).part1')
        self.assertEqual(self.c.parts['part2']._logger.name,
                         'RunnableController(mainBlock).part2')

    def test_edit(self):
        self.b.edit()
        self.checkState(self.sm.EDITABLE, child=False)

    def test_reset(self):
        self.b.disable()
        self.checkState(self.sm.DISABLED)
        self.b.reset()
        self.checkState(self.sm.IDLE)

    def test_set_axes_to_move(self):
        self.c.set_axes_to_move(['y'])
        self.assertEqual(self.c.axes_to_move.value, ['y'])

    def test_validate(self):
        line1 = LineGenerator('y', 'mm', 0, 2, 3)
        line2 = LineGenerator('x', 'mm', 0, 2, 2)
        compound = CompoundGenerator([line1, line2], [], [])
        actual = self.b.validate(generator=compound, axesToMove=['x'])
        self.assertEqual(actual["generator"], compound)
        self.assertEqual(actual["axesToMove"], ['x'])

    def prepare_half_run(self, duration=0.01, exception=0):
        line1 = LineGenerator('y', 'mm', 0, 2, 3)
        line2 = LineGenerator('x', 'mm', 0, 2, 2)
        duration = FixedDurationMutator(duration)
        compound = CompoundGenerator([line1, line2], [], [duration])
        self.b.configure(
            generator=compound, axesToMove=['x'], exceptionStep=exception)

    def test_configure_run(self):
        self.prepare_half_run()
        self.checkSteps(2, 0, 6)
        self.checkState(self.sm.READY)

        self.b.run()
        self.checkState(self.sm.READY)
        self.checkSteps(4, 2, 6)

        self.b.run()
        self.checkState(self.sm.READY)
        self.checkSteps(6, 4, 6)

        self.b.run()
        self.checkState(self.sm.IDLE)

    def test_abort(self):
        self.prepare_half_run()
        self.b.run()
        self.b.abort()
        self.checkState(self.sm.ABORTED)

    def test_pause_seek_resume(self):
        self.prepare_half_run()
        self.checkSteps(configured=2, completed=0, total=6)
        self.b.run()
        self.checkState(self.sm.READY)
        self.checkSteps(4, 2, 6)
        self.b.pause(completedSteps=1)
        self.checkState(self.sm.READY)
        self.checkSteps(2, 1, 6)
        self.b.run()
        self.checkSteps(4, 2, 6)
        self.b.completedSteps = 5
        self.checkSteps(6, 5, 6)
        self.b.run()
        self.checkState(self.sm.IDLE)

    def test_resume_in_run(self):
        self.prepare_half_run(duration=0.5)
        w = self.p.spawn(self.b.run)
        time.sleep(0.85)
        self.b.pause()
        self.checkState(self.sm.PAUSED)
        self.checkSteps(2, 1, 6)
        self.b.resume()
        # return to PRERUN should continue original run to completion and
        # READY state
        then = time.time()
        w.wait()
        self.assertAlmostEqual(time.time() - then, 0.5, delta=0.4)
        self.checkState(self.sm.READY)

    def test_run_exception(self):
        self.prepare_half_run(exception=1)
        with self.assertRaises(ResponseError):
            self.b.run()
        self.checkState(self.sm.FAULT)

    def test_run_stop(self):
        self.prepare_half_run(duration=0.5)
        w = self.p.spawn(self.b.run)
        time.sleep(0.5)
        self.b.abort()
        with self.assertRaises(AbortedError):
            w.get()
        self.checkState(self.sm.ABORTED)
Example #38
0
# Start some logging
# logging.basicConfig(level=logging.DEBUG)

from pkg_resources import require

require("numpy", "ruamel.yaml", "scanpointgenerator", "cothread")
sys.path.append(os.path.join(os.path.dirname(__file__), ".."))

from malcolm.core import SyncFactory, Process, Task
from malcolm.blocks.demo import SimulatorPMACManager
from scanpointgenerator import LineGenerator, CompoundGenerator, FixedDurationMutator

# Make the top level objects
sf = SyncFactory("Sync")
process = Process("Process", sf)

# Make the malcolm object
params = SimulatorPMACManager.MethodMeta.prepare_input_map(mriPrefix="TST-PMAC")
SimulatorPMACManager(process, params)
sim = process.get_block("TST-PMAC")

# Start the process
process.start()

# Wait for everything to settle down
task = Task("waiter", process)
task.when_matches(sim["state"], "Idle", timeout=10)

# Do a test
xs = LineGenerator("m1", "mm", -8.0, -12.0, 121, alternate_direction=True)
 def setUp(self):
     self.process = Process("proc", SyncFactory("sync"))
     Hello(self.process, dict(mri="hello"))
     self.process.add_comms(
         WebsocketServerComms(self.process, dict(port=self.socket)))
     self.process.start()
require("tornado", "numpy")
sys.path.append(os.path.join(os.path.dirname(__file__), ".."))

from malcolm.core import SyncFactory, Process
from malcolm.controllers import ManagerController
from malcolm.comms.websocket.websocketservercomms import WebsocketServerComms
from malcolm.includes.pandabox.hardware_collection import hardware_collection

# Input params
HOSTNAME = "localhost"
PORT = 8888
WSPORT = 8080

# Make the top level objects
sf = SyncFactory("Sync")
process = Process("Process", sf)

# Add the websocket server
params = WebsocketServerComms.MethodMeta.prepare_input_map(port=WSPORT)
comms = WebsocketServerComms(process, params)
process.add_comms(comms)

# We daemonise the server by double forking, but we leave the controlling
# terminal and other file connections alone.
if False and os.fork():
    # Exit first parent
    sys.exit(0)
# Do second fork to avoid generating zombies
if False and os.fork():
    sys.exit(0)
Example #41
0
def make_process():
    import sys
    import threading
    import argparse
    import logging
    from os import environ

    parser = argparse.ArgumentParser(
        description="Interactive shell for malcolm")
    parser.add_argument(
        '--client', '-c',
        help="Add a client to given server, like ws://localhost:8080 or pva")
    parser.add_argument(
        '--log', default="INFO",
        help="Lowest level of logs to see. One of: ERROR, WARNING, INFO, DEBUG "
        "Default is INFO")
    parser.add_argument(
        'yaml', nargs="?",
        help="The YAML file containing the blocks to be loaded"
    )
    args = parser.parse_args()
    # assuming loglevel is bound to the string value obtained from the
    # command line argument. Convert to upper case to allow the user to
    # specify --log=DEBUG or --log=debug
    numeric_level = getattr(logging, args.log.upper(), None)
    if not isinstance(numeric_level, int):
        raise ValueError('Invalid log level: %s' % args.log)
    logging.basicConfig(level=numeric_level)

    from malcolm.core import SyncFactory, Process
    from malcolm.yamlutil import make_include_creator

    try:
        environ['DISPLAY']
        # If this environment variable doesn't exist then there is probably no
        # X server for us to talk to.
    except KeyError:
        pass
    else:
        from PyQt4.Qt import QApplication

        # Start qt
        def start_qt():
            global app
            app = QApplication(sys.argv)
            app.setQuitOnLastWindowClosed(False)
            from malcolm.gui.guiopener import GuiOpener
            global opener
            opener = GuiOpener()
            app.exec_()

        qt_thread = threading.Thread(target=start_qt)
        qt_thread.start()

    sf = SyncFactory("Sync")

    if args.yaml:
        proc_name = os.path.basename(args.yaml).split(".")[-2]
        proc = Process(proc_name, sf)
        with open(args.yaml) as f:
            assembly = make_include_creator(f.read())
        assembly(proc, {})
        proc_name = "%s - imalcolm" % proc_name
    else:
        proc = Process("Process", sf)
        proc_name = "imalcolm"
    # set terminal title
    sys.stdout.write("\x1b]0;%s\x07" % proc_name)

    if args.client:
        if args.client.startswith("ws://"):
            from malcolm.comms.websocket import WebsocketClientComms
            hostname, port = args.client[5:].split(":")
            comms = WebsocketClientComms(
                proc, dict(hostname=hostname, port=int(port)))
            proc.add_comms(comms)
        else:
            raise ValueError(
                "Don't know how to create client to %s" % args.client)

    def gui(block):
        global opener
        opener.open_gui(block, proc)

    return proc, gui
class TestManagerController(unittest.TestCase):
    def checkState(self, state, child=True, parent=True):
        if child:
            self.assertEqual(self.c_child.state.value, state)
        if parent:
            self.assertEqual(self.c.state.value, state)

    def setUp(self):
        self.p = Process("process1", SyncFactory("threading"))

        # create a child ManagerController block
        params = ManagerController.MethodMeta.prepare_input_map(mri="childBlock")
        self.c_child = ManagerController(self.p, [], params)
        self.b_child = self.c_child.block

        self.sm = self.c_child.stateMachine

        params = Part.MethodMeta.prepare_input_map(name="part1")
        part1 = Part(self.p, params)
        params = {"name": "part2", "mri": "childBlock"}
        params = ChildPart.MethodMeta.prepare_input_map(**params)
        part2 = ChildPart(self.p, params)

        # create a root block for the ManagerController block to reside in
        parts = [part1, part2]
        params = {"mri": "mainBlock"}
        params = ManagerController.MethodMeta.prepare_input_map(**params)
        self.c = ManagerController(self.p, parts, params)
        self.b = self.c.block

        # check that do_initial_reset works asynchronously
        self.p.start()

        # wait until block is Ready
        task = Task("block_ready_task", self.p)
        task.when_matches(self.b["state"], self.sm.READY, timeout=1)

        self.checkState(self.sm.READY)

    def tearDown(self):
        self.p.stop()

    def test_init(self):

        # the following block attributes should be created by a call to
        # set_attributes via _set_block_children in __init__
        self.assertEqual(self.b["layout"].meta.typeid, "malcolm:core/TableMeta:1.0")
        self.assertEqual(self.b["layoutName"].meta.typeid, "malcolm:core/StringMeta:1.0")

        # the following hooks should be created via _find_hooks in __init__
        self.assertEqual(
            self.c.hook_names,
            {
                self.c.Reset: "Reset",
                self.c.Disable: "Disable",
                self.c.Layout: "Layout",
                self.c.ReportOutports: "ReportOutports",
                self.c.Load: "Load",
                self.c.Save: "Save",
            },
        )

        # check instantiation of object tree via logger names
        self.assertEqual(self.c._logger.name, "ManagerController(mainBlock)")
        self.assertEqual(self.c.parts["part1"]._logger.name, "ManagerController(mainBlock).part1")
        self.assertEqual(self.c.parts["part2"]._logger.name, "ManagerController(mainBlock).part2")
        self.assertEqual(self.c_child._logger.name, "ManagerController(childBlock)")

    def test_edit(self):
        self.c.edit()
        # editing only affects one level
        self.checkState(self.sm.EDITABLE, child=False)
        self.assertEqual(self.c.revert_structure, self.c._save_to_structure())

    def test_edit_exception(self):
        self.c.edit()
        with self.assertRaises(Exception):
            self.c.edit()

    def test_save(self):
        self.c.edit()
        params = {"layoutName": "testSaveLayout"}
        params = ManagerController.save.MethodMeta.prepare_input_map(**params)
        self.c.save(params)
        self.checkState(self.sm.AFTER_RESETTING, child=False)
        self.assertEqual(self.c.layout_name.value, "testSaveLayout")
        self.c.edit()
        params = {"layoutName": None}
        params = ManagerController.save.MethodMeta.prepare_input_map(**params)
        self.c.save(params)

    def test_revert(self):
        self.c.edit()
        self.c.revert()
        self.checkState(self.sm.AFTER_RESETTING, child=False)

    def test_set_and_load_layout(self):
        self.c.edit()
        self.checkState(self.sm.EDITABLE, child=False)

        new_layout = Table(self.c.layout.meta)
        new_layout.name = ["part2"]
        new_layout.mri = ["P45-MRI"]
        new_layout.x = [10]
        new_layout.y = [20]
        new_layout.visible = [True]
        self.b.layout = new_layout
        self.assertEqual(self.c.parts["part2"].x, 10)
        self.assertEqual(self.c.parts["part2"].y, 20)
        self.assertEqual(self.c.parts["part2"].visible, True)

        # save the layout, modify and restore it
        params = {"layoutName": "testSaveLayout"}
        params = ManagerController.save.MethodMeta.prepare_input_map(**params)
        self.c.save(params)

        self.c.edit()
        new_layout.x = [30]
        self.b.layout = new_layout
        self.assertEqual(self.c.parts["part2"].x, 30)
        self.b.layoutName = "testSaveLayout"
        self.assertEqual(self.c.parts["part2"].x, 10)
class TestSystemWSCommsServerAndClient(unittest.TestCase):
    socket = 8882

    def setUp(self):
        sf = SyncFactory("sync")
        self.process = Process("proc", sf)
        Hello(self.process, dict(mri="hello"))
        Counter(self.process, dict(mri="counter"))
        self.process.add_comms(
            WebsocketServerComms(self.process, dict(port=self.socket)))
        self.process.start()
        # If we don't wait long enough, sometimes the websocket_connect()
        # in process2 will hang...
        time.sleep(0.1)
        self.process2 = Process("proc2", sf)
        self.process2.add_comms(
            WebsocketClientComms(self.process2,
                             dict(hostname="localhost", port=self.socket)))
        self.process2.start()

    def tearDown(self):
        self.socket += 1
        self.process.stop()
        self.process2.stop()

    def test_server_hello_with_malcolm_client(self):
        block2 = self.process2.make_client_block("hello")
        task = Task("task", self.process2)
        futures = task.when_matches_async(block2["state"], "Ready")
        task.wait_all(futures, timeout=1)
        ret = block2.greet("me2")
        self.assertEqual(ret, dict(greeting="Hello me2"))

    def test_server_counter_with_malcolm_client(self):
        block2 = self.process2.make_client_block("counter")
        task = Task("task", self.process2)
        futures = task.when_matches_async(block2["state"], "Ready")
        task.wait_all(futures, timeout=1)
        self.assertEqual(block2.counter, 0)
        block2.increment()
        self.assertEqual(block2.counter, 1)