Exemplo n.º 1
0
def get_images(screen, n_images, beamline='Aramis', dry_run=None):

    print('Start get_images for screen %s, %i images, beamline %s' %
          (screen, n_images, beamline))

    meta_dict_1 = get_meta_data(screen)

    positioner = pyscan.BsreadPositioner(n_messages=n_images)
    settings = pyscan.scan_settings(settling_time=0.01,
                                    measurement_interval=0.2,
                                    n_measurements=1)

    pipeline_client = PipelineClient("http://sf-daqsync-01:8889/")
    cam_instance_name = str(screen) + "_sp1"
    stream_address = pipeline_client.get_instance_stream(cam_instance_name)
    stream_host, stream_port = get_host_port_from_stream_address(
        stream_address)

    # Configure bsread
    pyscan.config.bs_default_host = stream_host
    pyscan.config.bs_default_port = stream_port

    logging.getLogger("mflow.mflow").setLevel(logging.ERROR)

    readables = get_readables(beamline)

    raw_output = pyscan.scan(positioner=positioner,
                             readables=readables,
                             settings=settings)
    output = [[x] for x in raw_output]

    result_dict = pyscan_result_to_dict(readables, output, scrap_bs=True)

    for ax in ['x_axis', 'y_axis']:
        arr = result_dict[ax] * 1e-6  # convert to m
        if len(arr.shape) == 3:
            result_dict[ax + '_m'] = arr[0, 0, :]
        elif len(arr.shape) == 2:
            result_dict[ax + '_m'] = arr[0, :]
        else:
            raise ValueError('Unexpected', len(arr.shape))

    meta_dict_2 = get_meta_data(screen)

    output_dict = {
        'pyscan_result': result_dict,
        'meta_data_begin': meta_dict_1,
        'meta_data_end': meta_dict_2,
    }

    print('End get_images')

    return output_dict
Exemplo n.º 2
0
    def test_a_quick_start(self):
        from cam_server import PipelineClient
        from cam_server.utils import get_host_port_from_stream_address
        from bsread import source, SUB

        # Create a pipeline client.
        client = PipelineClient()

        # ADDITIONAL, FOR THE TEST
        camera_name = "simulation"
        client = self.pipeline_client
        client.create_instance_from_config(
            configuration={"camera_name": camera_name},
            instance_id=camera_name + "_sp1")

        # Define the camera name you want to read. This should be the same camera you are streaming in screen panel.
        camera_name = "simulation"

        # Format of the instance id when screen_panel creates a pipeline.
        pipeline_instance_id = camera_name + "_sp1"

        # Get the stream for the pipelie instance.
        stream_address = client.get_instance_stream(pipeline_instance_id)

        # Extract the stream host and port from the stream_address.
        stream_host, stream_port = get_host_port_from_stream_address(
            stream_address)

        # Open connection to the stream. When exiting the 'with' section, the source disconnects by itself.
        with source(host=stream_host, port=stream_port,
                    mode=SUB) as input_stream:
            input_stream.connect()

            # Read one message.
            message = input_stream.receive()

            # Print out the received stream data - dictionary.
            print("Dictionary with data:\n", message.data.data)

            # Print out the X center of mass.
            print("X center of mass: ",
                  message.data.data["x_center_of_mass"].value)
class PipelineClientTest(unittest.TestCase):
    def setUp(self):
        self.host = "0.0.0.0"
        self.cam_port = 8880
        self.pipeline_port = 8881
        self.cam_manager_port = 8888
        self.pipeline_manager_port = 8889

        for port in self.cam_port, self.pipeline_port, self.cam_manager_port, self.pipeline_manager_port:
            print("Port ", port, "avilable: ", is_port_available(port))

        test_base_dir = os.path.split(os.path.abspath(__file__))[0]
        self.cam_config_folder = os.path.join(test_base_dir, "camera_config/")
        self.pipeline_config_folder = os.path.join(test_base_dir,
                                                   "pipeline_config/")
        self.background_config_folder = os.path.join(test_base_dir,
                                                     "background_config/")
        self.user_scripts_folder = os.path.join(test_base_dir, "user_scripts/")
        self.temp_folder = os.path.join(test_base_dir, "temp/")

        require_folder(self.background_config_folder)
        require_folder(self.user_scripts_folder)
        require_folder(self.temp_folder)

        cam_server_address = "http://%s:%s" % (self.host, self.cam_port)
        pipeline_server_address = "http://%s:%s" % (self.host,
                                                    self.pipeline_port)
        cam_server_proxy_address = "http://%s:%s" % (self.host,
                                                     self.cam_manager_port)
        pipeline_server_proxy_address = "http://%s:%s" % (
            self.host, self.pipeline_manager_port)

        self.cam_process = Process(target=start_camera_worker,
                                   args=(self.host, self.cam_port,
                                         self.user_scripts_folder))
        self.cam_process.start()

        self.pipeline_process = Process(
            target=start_pipeline_worker,
            args=(self.host, self.pipeline_port, self.temp_folder,
                  self.temp_folder, cam_server_proxy_address))
        self.pipeline_process.start()

        self.cam_proxy_process = Process(
            target=start_camera_manager,
            args=(self.host, self.cam_manager_port, cam_server_address,
                  self.cam_config_folder, self.user_scripts_folder))
        self.cam_proxy_process.start()

        self.pipeline_proxy_process = Process(
            target=start_pipeline_manager,
            args=(self.host, self.pipeline_manager_port,
                  pipeline_server_address, self.pipeline_config_folder,
                  self.background_config_folder,
                  config.DEFAULT_BACKGROUND_FILES_DAYS_TO_LIVE,
                  self.user_scripts_folder, cam_server_proxy_address))
        self.pipeline_proxy_process.start()
        self.cam_client = CamClient(cam_server_proxy_address)
        self.pipeline_client = PipelineClient(pipeline_server_proxy_address)

        # Give it some time to start.
        sleep(1.0)  # Give it some time to start.

    def tearDown(self):
        test_cleanup([self.pipeline_client, self.cam_client], [
            self.pipeline_proxy_process, self.cam_proxy_process,
            self.pipeline_process, self.cam_process
        ], [
            os.path.join(self.pipeline_config_folder, "testing_config.json"),
            os.path.join(self.temp_folder, "Test.py"),
            os.path.join(self.temp_folder, "Test2.py"),
            os.path.join(self.user_scripts_folder, "Test.py"),
            os.path.join(self.user_scripts_folder, "Test2.py"),
            self.background_config_folder,
            self.user_scripts_folder,
            self.temp_folder,
        ])

    def test_client(self):
        expected_pipelines = [
            "pipeline_example_1", "pipeline_example_2", "pipeline_example_3",
            "pipeline_example_4"
        ]
        for pipeline in expected_pipelines:
            self.assertIn(pipeline, self.pipeline_client.get_pipelines(),
                          "Test config pipelines have changed?")
        expected_pipelines = set(self.pipeline_client.get_pipelines())

        camera_config = self.pipeline_client.get_pipeline_config(
            "pipeline_example_4")
        self.pipeline_client.save_pipeline_config("testing_config",
                                                  camera_config)

        with self.assertRaisesRegex(
                ValueError, "Camera name not specified in configuration."):
            self.pipeline_client.save_pipeline_config("testing_config", {})

        with self.assertRaisesRegex(
                ValueError, "Camera name not specified in configuration."):
            self.pipeline_client.save_pipeline_config("testing_config",
                                                      {"invalid": "config"})

        with self.assertRaisesRegex(
                ValueError,
                "pipeline_type 'invalid' not present in mapping. Available"):
            self.pipeline_client.save_pipeline_config(
                "testing_config", {
                    "camera_name": "simulation",
                    "pipeline_type": "invalid"
                })

        expected_pipelines.add("testing_config")

        self.assertSetEqual(set(self.pipeline_client.get_pipelines()),
                            expected_pipelines,
                            "Testing config was not added.")

        stream_address_1 = self.pipeline_client.get_instance_stream(
            "testing_config")
        stream_address_2 = self.pipeline_client.get_instance_stream(
            "testing_config")
        self.assertEqual(
            len(self.pipeline_client.get_server_info()["active_instances"]), 1,
            "Instance not started or too many instances started.")

        with self.assertRaisesRegex(ValueError,
                                    "Config updates cannot be empty."):
            self.pipeline_client.set_instance_config("testing_config", {})

        with self.assertRaisesRegex(
                ValueError, "Cannot set config on a read only instance."):
            self.pipeline_client.set_instance_config(
                "testing_config", {"camera_name": "simulation"})

        self.assertEqual(stream_address_1, stream_address_2,
                         "Stream addresses should be equal.")

        self.pipeline_client.stop_instance("testing_config")

        self.assertEqual(
            len(self.pipeline_client.get_server_info()["active_instances"]), 0,
            "The instance should be stopped.")

        instance_id_1, instance_stream_1 = self.pipeline_client.create_instance_from_name(
            "testing_config")
        instance_id_2, instance_stream_2 = self.pipeline_client.create_instance_from_name(
            "testing_config")

        instance_info = self.pipeline_client.get_instance_info(instance_id_1)
        self.assertTrue("last_start_time" in instance_info)
        self.assertTrue("statistics" in instance_info)

        with self.assertRaisesRegex(
                ValueError,
                "Cannot change the camera name on a running instance. "
                "Stop the instance first."):
            self.pipeline_client.set_instance_config(
                instance_id_1, {"camera_name": "different_camera"})

        self.pipeline_client.set_instance_config(
            instance_id_2, {
                "image_threshold": 99999,
                "image_region_of_interest": [0, 200, 0, 200]
            })

        # Wait for the config update.
        sleep(0.5)

        pipeline_host, pipeline_port = get_host_port_from_stream_address(
            instance_stream_2)

        with source(host=pipeline_host, port=pipeline_port,
                    mode=SUB) as stream:
            data = stream.receive()
            self.assertIsNotNone(data,
                                 "This should really not happen anymore.")
            # shape 200, 200 -> Account for the region of interest change.
            self.assertTrue(
                numpy.array_equal(data.data.data["image"].value,
                                  numpy.zeros(shape=(200, 200))),
                "Array should be all zeros, because of the threshold config.")

            # Adjust width and height with the region of interest.
            self.assertEqual(data.data.data["width"].value, 200,
                             "Region of interest not takes into account.")
            self.assertEqual(data.data.data["height"].value, 200,
                             "Region of interest not takes into account.")

        self.assertNotEqual(instance_id_1, instance_id_2,
                            "Instances should be different.")
        self.assertNotEqual(instance_stream_1, instance_stream_2,
                            "Stream addresses should be different.")

        self.assertEqual(
            len(self.pipeline_client.get_server_info()["active_instances"]), 2,
            "Two instances should be running.")

        instance_stream_3 = self.pipeline_client.get_instance_stream(
            instance_id_2)
        self.assertEqual(instance_stream_2, instance_stream_3,
                         "Stream addresses should be equal.")

        self.assertEqual(
            len(self.pipeline_client.get_server_info()["active_instances"]), 2,
            "Two instances should be running, get does not increase the number of instances."
        )

        self.pipeline_client.create_instance_from_config(
            {"camera_name": "simulation"})
        self.pipeline_client.create_instance_from_config(
            {"camera_name": "simulation"})

        self.assertEqual(
            len(self.pipeline_client.get_server_info()["active_instances"]), 4,
            "Two new instances should be created.")

        with self.assertRaisesRegex(
                ValueError, "You must specify either the pipeline name or the "
                "configuration for the pipeline."):
            self.pipeline_client.create_instance_from_config({})

        with self.assertRaisesRegex(
                ValueError, "Camera name not specified in configuration."):
            self.pipeline_client.create_instance_from_config(
                {"invalid": "config"})

        background_id = self.pipeline_client.collect_background("simulation")
        expected_background_file = os.path.join(self.background_config_folder,
                                                background_id + ".npy")

        # Unfortunately there is not way of knowing (from client side) how many images were collected.
        background_id_2 = self.pipeline_client.collect_background(
            "simulation", 5)

        self.assertNotEqual(background_id, background_id_2,
                            "Background should be different.")

        with self.assertRaisesRegex(Exception, "n_images must be a number."):
            self.pipeline_client.collect_background("simulation",
                                                    "invalid_number")

        pipeline_config = {
            "camera_name": "simulation",
            "background_image": background_id
        }

        instance_id, stream_address = self.pipeline_client.create_instance_from_config(
            pipeline_config)

        instance_config = self.pipeline_client.get_instance_config(instance_id)

        # We need to account for the expended config.
        expected_config = {}
        expected_config.update(PipelineConfig.DEFAULT_CONFIGURATION)
        expected_config.update(pipeline_config)

        self.assertDictEqual(expected_config, instance_config,
                             "Set and retrieved instances are not equal.")

        instance_info = self.pipeline_client.get_instance_info(instance_id)
        self.assertEqual(instance_info["instance_id"], instance_id,
                         "Requested and retireved instances are different.")
        self.assertEqual(instance_info["stream_address"], stream_address,
                         "Different stream address.")
        self.assertTrue(instance_info["is_stream_active"],
                        "Stream should be active.")
        self.assertFalse(instance_info["read_only"],
                         "It should not be read only.")
        self.assertEqual(instance_info["camera_name"], "simulation",
                         "Wrong camera name.")
        self.assertDictEqual(instance_info["config"], expected_config,
                             "Config is not equal")

        self.pipeline_client.stop_instance(instance_id)

        with self.assertRaisesRegex(
                ValueError, "Instance '%s' does not exist." % instance_id):
            self.pipeline_client.get_instance_info(instance_id)

        with self.assertRaisesRegex(
                ValueError, "Instance 'invalid instance' does not exist."):
            self.pipeline_client.get_instance_info("invalid instance")

        self.assertTrue(os.path.exists(expected_background_file))
        os.remove(expected_background_file)

        self.pipeline_client.stop_all_instances()

        self.assertTrue(
            "testing_config" in self.pipeline_client.get_pipelines(),
            "Pre requirement for next test.")

        self.pipeline_client.delete_pipeline_config("testing_config")
        self.assertFalse(
            "testing_config" in self.pipeline_client.get_pipelines(),
            "Pipeline should not exist anymore.")

        instance_id, stream_address = self.pipeline_client.create_instance_from_config(
            {
                "camera_name": "simulation",
                "image_threshold": 10
            }, "custom_instance")

        self.assertEqual(instance_id, "custom_instance",
                         "Custom instance not set properly.")

        self.assertTrue(
            self.pipeline_client.is_instance_running("custom_instance"),
            "Instance with custom instance id not present.")

        self.assertEqual(
            self.pipeline_client.get_instance_config("custom_instance")
            ["image_threshold"], 10, "Config not set on custom instance id.")

        with self.assertRaisesRegex(
                ValueError,
                "Instance with id 'custom_instance' is already present and running. "
                "Use another instance_id or stop the current instance if you want "
                "to reuse the same instance_id."):
            self.pipeline_client.create_instance_from_config(
                {"camera_name": "simulation"}, "custom_instance")

        self.pipeline_client.stop_instance("custom_instance")

        # The instance is now stopped, it should overwrite it.
        self.pipeline_client.create_instance_from_config(
            {
                "camera_name": "simulation",
                "image_threshold": 20
            }, "custom_instance")

        self.assertEqual(
            self.pipeline_client.get_instance_config(
                "custom_instance")["image_threshold"], 20,
            "Instance with custom id not overwritten.")

        self.pipeline_client.save_pipeline_config("testing_config", {
            "camera_name": "simulation",
            "image_threshold": 30
        })

        with self.assertRaisesRegex(
                ValueError,
                "Instance with id 'custom_instance' is already present and running. "
                "Use another instance_id or stop the current instance if you want "
                "to reuse the same instance_id."):
            self.pipeline_client.create_instance_from_name(
                "testing_config", "custom_instance")

        self.assertEqual(
            self.pipeline_client.get_instance_config("custom_instance")
            ["image_threshold"], 20, "Instance should not have changed.")

        data = self.pipeline_client.get_instance_message("custom_instance")
        self.assertIsNotNone(data)
        self.assertTrue("image" in data.data.data)

        self.pipeline_client.stop_instance("custom_instance")

        self.pipeline_client.create_instance_from_name("testing_config",
                                                       "custom_instance")

        self.assertEqual(
            self.pipeline_client.get_instance_config("custom_instance")
            ["image_threshold"], 30, "Instance should have changed.")

        background_1 = self.pipeline_client.collect_background("simulation")
        background_2 = self.pipeline_client.collect_background("simulation")

        self.assertNotEqual(background_1, background_2)

        latest_background = self.pipeline_client.get_latest_background(
            "simulation")

        self.assertEqual(latest_background, background_2,
                         "Wrong background set as latest.")

        with self.assertRaisesRegex(
                ValueError,
                "No background matches for the specified prefix 'does not exist'."
        ):
            self.pipeline_client.get_latest_background("does not exist")

        expected_cameras = [
            'camera_example_1', 'camera_example_3', 'camera_example_2',
            'camera_example_4', 'simulation', 'simulation2'
        ]

        #self.assertEqual(set(self.pipeline_client.get_cameras()), set(expected_cameras),
        #                 "Expected cameras not present.")
        for camera in expected_cameras:
            self.assertIn(camera, set(self.pipeline_client.get_cameras()),
                          "Not getting expected camera: " + camera)

        configuration = {"camera_name": "simulation", "threshold": 50}

        stream_address_1 = self.pipeline_client.get_instance_stream_from_config(
            configuration)
        stream_address_2 = self.pipeline_client.get_instance_stream_from_config(
            configuration)

        self.assertEqual(
            stream_address_1, stream_address_2,
            "Requesting the same config should give you the same instance.")

        self.pipeline_client.stop_all_instances()
        self.cam_client.stop_all_instances()

        instance_id, stream_address = self.pipeline_client.create_instance_from_config(
            {
                "camera_name": "simulation",
                "pipeline_type": "store",
                'stream_port': 10000
            })

        with self.assertRaisesRegex(
                ValueError, "Cannot get message from 'store' pipeline type."):
            self.pipeline_client.get_instance_message(instance_id)

        host, port = get_host_port_from_stream_address(stream_address)

        with source(host=host, port=port, mode=PULL) as stream:
            data = stream.receive()

        self.assertIsNotNone(data)
        self.assertEqual(
            len(data.data.data), 1,
            "Only the image should be present in the received data.")
        self.assertTrue(
            "simulation" + config.EPICS_PV_SUFFIX_IMAGE in data.data.data,
            "Camera name should be used instead of 'image'.")

        self.pipeline_client.stop_all_instances()

        #Transparent pipeline
        instance_id, instance_stream = self.pipeline_client.create_instance_from_name(
            "simulation")
        cfg = self.pipeline_client.get_instance_config(instance_id)
        cfg["function"] = "transparent"
        self.pipeline_client.set_instance_config(instance_id, cfg)
        time.sleep(.5)
        data = self.pipeline_client.get_instance_message(instance_id)
        self.assertIsNotNone(data)
        # Cam_server fields + processing_parameters
        required_fields = set([
            "image", "timestamp", "width", "height", "x_axis", "y_axis",
            "processing_parameters"
        ])
        self.assertSetEqual(required_fields, set(data.data.data.keys()),
                            "Bad transparent pipeline fields.")

        self.pipeline_client.stop_all_instances()
        time.sleep(1.0)

    def test_background_file(self):

        bg = self.pipeline_client.get_latest_background("simulation")
        image = self.pipeline_client.get_background_image(bg)
        self.assertGreater(len(image.content), 0)

        image = self.pipeline_client.get_background_image_bytes(bg)
        dtype = image["dtype"]
        shape = image["shape"]
        bytes = base64.b64decode(image["bytes"].encode())

        x_size, y_size = get_simulated_camera().get_geometry()
        self.assertEqual(shape, [y_size, x_size])

        image_array = numpy.frombuffer(bytes, dtype=dtype).reshape(shape)
        self.assertIsNotNone(image_array)

    def test_user_scripts(self):
        script_name = "Test.py"
        script_content = "print('Hello world')"
        self.pipeline_client.set_user_script(script_name, script_content)

        scripts = self.pipeline_client.get_user_scripts()
        self.assertIn(script_name, scripts)

        ret = self.pipeline_client.get_user_script(script_name)
        self.assertEqual(ret, script_content)
        filename = "temp/Test2.py"
        with open(filename, "w") as data_file:
            data_file.write(script_content)

        self.pipeline_client.upload_user_script(filename)
        os.remove(filename)
        self.pipeline_client.download_user_script(filename)
        with open(filename, "r") as data_file:
            ret = data_file.read()
        self.assertEqual(ret, script_content)

        script_content = """
from cam_server.pipeline.data_processing import functions, processor
def process_image(image, pulse_id, timestamp, x_axis, y_axis, parameters, bsdata):
    ret = processor.process_image(image, pulse_id, timestamp, x_axis, y_axis, parameters, bsdata)
    ret["average_value"] = float(ret["intensity"]) / len(ret["x_axis"]) / len(ret["y_axis"])
    return ret
        """
        filename = "temp/Test.py"
        with open(filename, "w") as data_file:
            data_file.write(script_content)

        instance_id, stream_address = self.pipeline_client.create_instance_from_config(
            {"camera_name": "simulation"})
        host, port = get_host_port_from_stream_address(stream_address)

        with source(host=host, port=port, mode=SUB) as stream:
            data = stream.receive()
            self.assertIsNotNone(data,
                                 "This should really not happen anymore.")
            self.assertIsNotNone(data.data.data["width"].value)
            self.assertIsNotNone(data.data.data["height"].value)

        self.pipeline_client.set_function_script(instance_id, filename)
        time.sleep(1.0)
        with source(host=host, port=port, mode=SUB) as stream:
            data = stream.receive()
            print(data.data.data.keys())
            self.assertIsNotNone(data.data.data["average_value"].value)
Exemplo n.º 4
0
def data_streaker_offset(streaker,
                         offset_range,
                         screen,
                         n_images,
                         dry_run,
                         beamline='Aramis'):

    print(
        'Start data_streaker_offset for streaker %s, screen %s, beamline %s, dry_run %s'
        % (streaker, screen, beamline, dry_run))
    meta_dict_1 = get_meta_data(screen)

    pipeline_client = PipelineClient('http://sf-daqsync-01:8889/')
    offset_pv = streaker + ':CENTER'

    current_val = caget(offset_pv + '.RBV')

    # Start from closer edge of scan
    if abs(current_val - offset_range[0]) > abs(current_val -
                                                offset_range[-1]):
        offset_range = offset_range[::-1]

    if dry_run:
        screen = 'simulation'
        writables = None
        positioner = pyscan.TimePositioner(time_interval=(1.1 * n_images),
                                           n_intervals=len(offset_range))

    else:
        positions = offset_range * 1e3  # convert to mm
        positioner = pyscan.VectorPositioner(positions=positions.tolist())
        writables = [
            pyscan.epics_pv(pv_name=offset_pv,
                            readback_pv_name=offset_pv + '.RBV',
                            tolerance=0.005)
        ]

    cam_instance_name = screen + '_sp1'
    stream_address = pipeline_client.get_instance_stream(cam_instance_name)
    stream_host, stream_port = get_host_port_from_stream_address(
        stream_address)

    # Configure bsread
    pyscan.config.bs_default_host = stream_host
    pyscan.config.bs_default_port = stream_port

    logging.getLogger('mflow.mflow').setLevel(logging.ERROR)

    settings = pyscan.scan_settings(settling_time=1,
                                    n_measurements=n_images,
                                    write_timeout=60)

    readables = get_readables(beamline)

    raw_output = pyscan.scan(positioner=positioner,
                             readables=readables,
                             settings=settings,
                             writables=writables)
    result_dict = pyscan_result_to_dict(readables, raw_output, scrap_bs=True)
    #import pdb; pdb.set_trace()
    for ax in ['x_axis', 'y_axis']:
        arr = result_dict[ax] * 1e-6
        if len(arr.shape) == 3:
            result_dict[ax + '_m'] = arr[0][0]
        elif len(arr.shape) == 2:
            result_dict[ax + '_m'] = arr[0]
        else:
            raise ValueError('Unexpected', len(arr.shape))

    meta_dict_2 = get_meta_data(screen)

    output = {
        'pyscan_result': result_dict,
        'streaker_offsets': offset_range,
        'screen': screen,
        'n_images': n_images,
        'dry_run': dry_run,
        'streaker': streaker,
        'meta_data_begin': meta_dict_1,
        'meta_data_end': meta_dict_2,
    }
    print('End data_streaker_offset')
    return output
Exemplo n.º 5
0
class PipelineClientTest(unittest.TestCase):
    def setUp(self):
        self.host = "0.0.0.0"
        self.cam_port = 8888
        self.pipeline_port = 8889

        test_base_dir = os.path.split(os.path.abspath(__file__))[0]
        self.cam_config_folder = os.path.join(test_base_dir, "camera_config/")
        self.pipeline_config_folder = os.path.join(test_base_dir,
                                                   "pipeline_config/")
        self.background_config_folder = os.path.join(test_base_dir,
                                                     "background_config/")

        cam_server_address = "http://%s:%s" % (self.host, self.cam_port)
        pipeline_server_address = "http://%s:%s" % (self.host,
                                                    self.pipeline_port)

        self.cam_process = Process(target=start_camera_server,
                                   args=(self.host, self.cam_port,
                                         self.cam_config_folder))
        self.cam_process.start()

        self.pipeline_process = Process(
            target=start_pipeline_server,
            args=(self.host, self.pipeline_port, self.pipeline_config_folder,
                  self.background_config_folder, cam_server_address))
        self.pipeline_process.start()

        self.cam_client = CamClient(cam_server_address)
        self.pipeline_client = PipelineClient(pipeline_server_address)

        # Give it some time to start.
        sleep(1)

    def tearDown(self):

        os.kill(self.cam_process.pid, signal.SIGINT)
        os.kill(self.pipeline_process.pid, signal.SIGINT)

        self.cam_process.join()
        self.pipeline_process.join()

        try:
            os.remove(
                os.path.join(self.pipeline_config_folder,
                             "testing_config.json"))
        except:
            pass
        # Wait for the server to die.
        sleep(1)

    def test_client(self):
        expected_pipelines = set([
            "pipeline_example_1", "pipeline_example_2", "pipeline_example_3",
            "pipeline_example_4"
        ])

        self.assertSetEqual(set(self.pipeline_client.get_pipelines()),
                            expected_pipelines,
                            "Test config pipelines have changed?")

        camera_config = self.pipeline_client.get_pipeline_config(
            "pipeline_example_4")
        self.pipeline_client.save_pipeline_config("testing_config",
                                                  camera_config)

        with self.assertRaisesRegex(
                ValueError, "Camera name not specified in configuration."):
            self.pipeline_client.save_pipeline_config("testing_config", {})

        with self.assertRaisesRegex(
                ValueError, "Camera name not specified in configuration."):
            self.pipeline_client.save_pipeline_config("testing_config",
                                                      {"invalid": "config"})

        with self.assertRaisesRegex(
                ValueError,
                "pipeline_type 'invalid' not present in mapping. Available"):
            self.pipeline_client.save_pipeline_config(
                "testing_config", {
                    "camera_name": "simulation",
                    "pipeline_type": "invalid"
                })

        expected_pipelines.add("testing_config")

        self.assertSetEqual(set(self.pipeline_client.get_pipelines()),
                            expected_pipelines,
                            "Testing config was not added.")

        stream_address_1 = self.pipeline_client.get_instance_stream(
            "testing_config")
        stream_address_2 = self.pipeline_client.get_instance_stream(
            "testing_config")
        self.assertEqual(
            len(self.pipeline_client.get_server_info()["active_instances"]), 1,
            "Instance not started or too many instances started.")

        with self.assertRaisesRegex(ValueError,
                                    "Config updates cannot be empty."):
            self.pipeline_client.set_instance_config("testing_config", {})

        with self.assertRaisesRegex(
                ValueError, "Cannot set config on a read only instance."):
            self.pipeline_client.set_instance_config(
                "testing_config", {"camera_name": "simulation"})

        self.assertEqual(stream_address_1, stream_address_2,
                         "Stream addresses should be equal.")

        self.pipeline_client.stop_instance("testing_config")

        self.assertEqual(
            len(self.pipeline_client.get_server_info()["active_instances"]), 0,
            "The instance should be stopped.")

        instance_id_1, instance_stream_1 = self.pipeline_client.create_instance_from_name(
            "testing_config")
        instance_id_2, instance_stream_2 = self.pipeline_client.create_instance_from_name(
            "testing_config")

        instance_info = self.pipeline_client.get_instance_info(instance_id_1)
        self.assertTrue("last_start_time" in instance_info)
        self.assertTrue("statistics" in instance_info)

        with self.assertRaisesRegex(
                ValueError,
                "Cannot change the camera name on a running instance. "
                "Stop the instance first."):
            self.pipeline_client.set_instance_config(
                instance_id_1, {"camera_name": "different_camera"})

        self.pipeline_client.set_instance_config(
            instance_id_2, {
                "image_threshold": 99999,
                "image_region_of_interest": [0, 200, 0, 200]
            })

        # Wait for the config update.
        sleep(0.5)

        pipeline_host, pipeline_port = get_host_port_from_stream_address(
            instance_stream_2)

        with source(host=pipeline_host, port=pipeline_port,
                    mode=SUB) as stream:
            data = stream.receive()
            self.assertIsNotNone(data,
                                 "This should really not happen anymore.")
            # shape 200, 200 -> Account for the region of interest change.
            self.assertTrue(
                numpy.array_equal(data.data.data["image"].value,
                                  numpy.zeros(shape=(200, 200))),
                "Array should be all zeros, because of the threshold config.")

            # Adjust width and height with the region of interest.
            self.assertEqual(data.data.data["width"].value, 200,
                             "Region of interest not takes into account.")
            self.assertEqual(data.data.data["height"].value, 200,
                             "Region of interest not takes into account.")

        self.assertNotEqual(instance_id_1, instance_id_2,
                            "Instances should be different.")
        self.assertNotEqual(instance_stream_1, instance_stream_2,
                            "Stream addresses should be different.")

        self.assertEqual(
            len(self.pipeline_client.get_server_info()["active_instances"]), 2,
            "Two instances should be running.")

        instance_stream_3 = self.pipeline_client.get_instance_stream(
            instance_id_2)
        self.assertEqual(instance_stream_2, instance_stream_3,
                         "Stream addresses should be equal.")

        self.assertEqual(
            len(self.pipeline_client.get_server_info()["active_instances"]), 2,
            "Two instances should be running, get does not increase the number of instances."
        )

        self.pipeline_client.create_instance_from_config(
            {"camera_name": "simulation"})
        self.pipeline_client.create_instance_from_config(
            {"camera_name": "simulation"})

        self.assertEqual(
            len(self.pipeline_client.get_server_info()["active_instances"]), 4,
            "Two new instances should be created.")

        with self.assertRaisesRegex(
                ValueError, "You must specify either the pipeline name or the "
                "configuration for the pipeline."):
            self.pipeline_client.create_instance_from_config({})

        with self.assertRaisesRegex(
                ValueError, "Camera name not specified in configuration."):
            self.pipeline_client.create_instance_from_config(
                {"invalid": "config"})

        background_id = self.pipeline_client.collect_background("simulation")
        expected_background_file = os.path.join(self.background_config_folder,
                                                background_id + ".npy")

        # Unfortunately there is not way of knowing (from client side) how many images were collected.
        background_id_2 = self.pipeline_client.collect_background(
            "simulation", 5)

        self.assertNotEqual(background_id, background_id_2,
                            "Background should be different.")

        with self.assertRaisesRegex(Exception, "n_images must be a number."):
            self.pipeline_client.collect_background("simulation",
                                                    "invalid_number")

        pipeline_config = {
            "camera_name": "simulation",
            "background_image": background_id
        }

        instance_id, stream_address = self.pipeline_client.create_instance_from_config(
            pipeline_config)

        instance_config = self.pipeline_client.get_instance_config(instance_id)

        # We need to account for the expended config.
        expected_config = {}
        expected_config.update(PipelineConfig.DEFAULT_CONFIGURATION)
        expected_config.update(pipeline_config)

        self.assertDictEqual(expected_config, instance_config,
                             "Set and retrieved instances are not equal.")

        instance_info = self.pipeline_client.get_instance_info(instance_id)
        self.assertEqual(instance_info["instance_id"], instance_id,
                         "Requested and retireved instances are different.")
        self.assertEqual(instance_info["stream_address"], stream_address,
                         "Different stream address.")
        self.assertTrue(instance_info["is_stream_active"],
                        "Stream should be active.")
        self.assertFalse(instance_info["read_only"],
                         "It should not be read only.")
        self.assertEqual(instance_info["camera_name"], "simulation",
                         "Wrong camera name.")
        self.assertDictEqual(instance_info["config"], expected_config,
                             "Config is not equal")

        self.pipeline_client.stop_instance(instance_id)

        with self.assertRaisesRegex(
                ValueError, "Instance '%s' does not exist." % instance_id):
            self.pipeline_client.get_instance_info(instance_id)

        with self.assertRaisesRegex(
                ValueError, "Instance 'invalid instance' does not exist."):
            self.pipeline_client.get_instance_info("invalid instance")

        self.assertTrue(os.path.exists(expected_background_file))
        os.remove(expected_background_file)

        self.pipeline_client.stop_all_instances()

        self.assertTrue(
            "testing_config" in self.pipeline_client.get_pipelines(),
            "Pre requirement for next test.")

        self.pipeline_client.delete_pipeline_config("testing_config")
        self.assertFalse(
            "testing_config" in self.pipeline_client.get_pipelines(),
            "Pipeline should not exist anymore.")

        instance_id, stream_address = self.pipeline_client.create_instance_from_config(
            {
                "camera_name": "simulation",
                "image_threshold": 10
            }, "custom_instance")

        self.assertEqual(instance_id, "custom_instance",
                         "Custom instance not set properly.")

        self.assertTrue(
            "custom_instance"
            in self.pipeline_client.get_server_info()["active_instances"],
            "Instance with custom instance id not present.")

        self.assertEqual(
            self.pipeline_client.get_instance_config("custom_instance")
            ["image_threshold"], 10, "Config not set on custom instance id.")

        with self.assertRaisesRegex(
                ValueError,
                "Instance with id 'custom_instance' is already present and running. "
                "Use another instance_id or stop the current instance if you want "
                "to reuse the same instance_id."):
            self.pipeline_client.create_instance_from_config(
                {"camera_name": "simulation"}, "custom_instance")

        self.pipeline_client.stop_instance("custom_instance")

        # The instance is now stopped, it should overwrite it.
        self.pipeline_client.create_instance_from_config(
            {
                "camera_name": "simulation",
                "image_threshold": 20
            }, "custom_instance")

        self.assertEqual(
            self.pipeline_client.get_instance_config(
                "custom_instance")["image_threshold"], 20,
            "Instance with custom id not overwritten.")

        self.pipeline_client.save_pipeline_config("testing_config", {
            "camera_name": "simulation",
            "image_threshold": 30
        })

        with self.assertRaisesRegex(
                ValueError,
                "Instance with id 'custom_instance' is already present and running. "
                "Use another instance_id or stop the current instance if you want "
                "to reuse the same instance_id."):
            self.pipeline_client.create_instance_from_name(
                "testing_config", "custom_instance")

        self.assertEqual(
            self.pipeline_client.get_instance_config("custom_instance")
            ["image_threshold"], 20, "Instance should not have changed.")

        data = self.pipeline_client.get_instance_message("custom_instance")
        self.assertIsNotNone(data)
        self.assertTrue("image" in data.data.data)

        self.pipeline_client.stop_instance("custom_instance")

        self.pipeline_client.create_instance_from_name("testing_config",
                                                       "custom_instance")

        self.assertEqual(
            self.pipeline_client.get_instance_config("custom_instance")
            ["image_threshold"], 30, "Instance should have changed.")

        background_1 = self.pipeline_client.collect_background("simulation")
        background_2 = self.pipeline_client.collect_background("simulation")

        self.assertNotEqual(background_1, background_2)

        latest_background = self.pipeline_client.get_latest_background(
            "simulation")

        self.assertEqual(latest_background, background_2,
                         "Wrong background set as latest.")

        with self.assertRaisesRegex(
                ValueError,
                "No background matches for the specified prefix 'does not exist'."
        ):
            self.pipeline_client.get_latest_background("does not exist")

        expected_cameras = [
            'camera_example_1', 'camera_example_3', 'camera_example_2',
            'camera_example_4', 'simulation'
        ]

        self.assertEqual(set(self.pipeline_client.get_cameras()),
                         set(expected_cameras),
                         "Expected cameras not present.")

        configuration = {"camera_name": "simulation", "threshold": 50}

        stream_address_1 = self.pipeline_client.get_instance_stream_from_config(
            configuration)
        stream_address_2 = self.pipeline_client.get_instance_stream_from_config(
            configuration)

        self.assertEqual(
            stream_address_1, stream_address_2,
            "Requesting the same config should give you the same instance.")

        self.pipeline_client.stop_all_instances()
        self.cam_client.stop_all_cameras()

        instance_id, stream_address = self.pipeline_client.create_instance_from_config(
            {
                "camera_name": "simulation",
                "pipeline_type": "store"
            })

        with self.assertRaisesRegex(
                ValueError, "Cannot get message from 'store' pipeline type."):
            self.pipeline_client.get_instance_message(instance_id)

        host, port = get_host_port_from_stream_address(stream_address)

        with source(host=host, port=port, mode=PULL) as stream:
            data = stream.receive()

        self.assertIsNotNone(data)
        self.assertEqual(
            len(data.data.data), 1,
            "Only the image should be present in the received data.")
        self.assertTrue("simulation" in data.data.data,
                        "Camera name should be used instead of 'image'.")

        self.pipeline_client.stop_all_instances()