def dome(): set_config('dome', { 'brand': 'Simulacrum', 'driver': 'simulator', }) return create_dome_simulator()
def create_mount_simulator(mount_info=None, earth_location=None, *args, **kwargs): # Remove mount simulator current_simulators = get_config('simulator', default=[]) logger.warning(f'Current simulators: {current_simulators}') with suppress(ValueError): current_simulators.remove('mount') mount_config = mount_info or { 'model': 'Mount Simulator', 'driver': 'simulator', 'serial': { 'port': '/dev/FAKE' } } # Set mount device info to simulator set_config('mount', mount_config) earth_location = earth_location or create_location_from_config()['earth_location'] logger.debug(f"Loading mount driver: pocs.mount.{mount_config['driver']}") try: module = load_module(f"panoptes.pocs.mount.{mount_config['driver']}") except error.NotFound as e: raise error.MountNotFound(f'Error loading mount module: {e!r}') mount = module.Mount(earth_location, *args, **kwargs) logger.success(f"{mount_config['driver'].title()} mount created") return mount
def test_bad_scheduler_fields_file(config_host, config_port): set_config('scheduler.fields_file', 'foobar') site_details = create_location_from_config() with pytest.raises(error.NotFound): create_scheduler_from_config(observer=site_details['observer']) reset_conf(config_host, config_port)
def do_setup_pocs(self, *arg): """Setup and initialize a POCS instance.""" args, kwargs = string_to_params(*arg) simulator = kwargs.get('simulator', list()) if isinstance(simulator, str): simulator = [simulator] # Set whatever simulators were passed during setup client.set_config('simulator', simulator) # Retrieve what was set simulators = client.get_config('simulator', default=list()) if len(simulators): print_warning(f'Using simulators: {simulators}') if 'POCSTIME' in os.environ: print_warning("Clearing POCSTIME variable") del os.environ['POCSTIME'] try: mount = create_mount_from_config() cameras = create_cameras_from_config() scheduler = create_scheduler_from_config() observatory = Observatory(mount=mount, cameras=cameras, scheduler=scheduler) self.pocs = POCS(observatory) self.pocs.initialize() except error.PanError as e: print_warning('Problem setting up POCS: {}'.format(e))
def test_create_mount_without_mount_info(config_host, config_port): # Set the mount config to none and then don't pass anything for error. set_config('mount', None) set_config('simulator', hardware.get_all_names(without=['mount'])) with pytest.raises(error.MountNotFound): create_mount_from_config(mount_info=None) reset_conf(config_host, config_port)
def test_create_mount_simulator_with_config(config_host, config_port): # Remove mount from list of simulators. set_config('simulator', hardware.get_all_names(without=['mount'])) # But setting the driver to `simulator` should return simulator. set_config('mount.driver', 'simulator') mount = create_mount_from_config() assert isinstance(mount, AbstractMount) is True reset_conf(config_host, config_port)
def test_camera_wrong_type(): # Remove mount simulator set_config('simulator', hardware.get_all_names(without='camera')) with pytest.raises(AttributeError): Observatory(cameras=[Time.now()]) with pytest.raises(AssertionError): Observatory(cameras={'Cam00': Time.now()})
def test_create_mount_with_earth_location(config_host, config_port): # Get location to pass manually. loc = create_location_from_config() # Set config to not have a location. set_config('location', None) set_config('simulator', hardware.get_all_names()) assert isinstance(create_mount_from_config(earth_location=loc['earth_location']), AbstractMount) is True reset_conf(config_host, config_port)
def test_loading_target_file_check_file(observer, simple_fields_file, constraints): set_config('scheduler.check_file', False) scheduler = Scheduler(observer, fields_file=simple_fields_file, constraints=constraints) # Check the hidden property as the public one # will populate if not found. assert len(scheduler._observations)
def test_create_mount_with_mount_info(config_host, config_port): # Pass the mount info directly with nothing in config. mount_info = get_config('mount', default=dict()) mount_info['driver'] = 'simulator' # Remove info from config. set_config('mount', None) set_config('simulator', hardware.get_all_names(without=['mount'])) assert isinstance(create_mount_from_config(mount_info=mount_info), AbstractMount) is True reset_conf(config_host, config_port)
def mount(location): with suppress(KeyError): del os.environ['POCSTIME'] set_config('mount', { 'brand': 'bisque', 'template_dir': 'resources/bisque', }) return Mount(location=location)
def test_bad_mount_driver(config_host, config_port): # Remove the mount from the list of simulators so it thinks we have a real one. simulators = get_config('simulator') with suppress(KeyError, AttributeError): simulators.pop('mount') set_config('simulator', simulators) # Set a bad port, which should cause a fail before actual mount creation. set_config('mount.serial.driver', 'foobar') with pytest.raises(error.MountNotFound): create_mount_from_config() reset_conf(config_host, config_port)
def dynamic_config_server(config_host, config_port, config_server_args, images_dir, db_name): """If a test requires changing the configuration we use a function-scoped testing server. We only do this on tests that require it so we are not constantly starting and stopping the config server unless necessary. To use this, each test that requires it must use the `dynamic_config_server` and `config_port` fixtures and must pass the `config_port` to all instances that are created (propogated through PanBase). """ logger = get_root_logger() logger.critical(f'Starting config_server for testing function') def start_config_server(): # Load the config items into the app config. for k, v in config_server_args.items(): app.config[k] = v # Start the actual flask server. app.run(host=config_host, port=config_port) proc = Process(target=start_config_server) proc.start() logger.info(f'config_server started with PID={proc.pid}') # Give server time to start time.sleep(1) # Adjust various config items for testing unit_name = 'Generic PANOPTES Unit' unit_id = 'PAN000' logger.info(f'Setting testing name and unit_id to {unit_id}') set_config('name', unit_name, port=config_port) set_config('pan_id', unit_id, port=config_port) logger.info(f'Setting testing database to {db_name}') set_config('db.name', db_name, port=config_port) fields_file = 'simulator.yaml' logger.info(f'Setting testing scheduler fields_file to {fields_file}') set_config('scheduler.fields_file', fields_file, port=config_port) # TODO(wtgee): determine if we need separate directories for each module. logger.info(f'Setting temporary image directory for testing') set_config('directories.images', images_dir, port=config_port) yield logger.critical(f'Killing config_server started with PID={proc.pid}') proc.terminate()
def set_config(self, key, new_value, *args, **kwargs): """Thin-wrapper around client based set_config that sets default port. See `panoptes.utils.config.client.set_config` for more information. Args: key (str): The key name to use, can be namespaced with dots. new_value (any): The value to store. *args: Passed to set_config **kwargs: Passed to set_config """ config_value = None if key == 'simulator' and new_value == 'all': # Don't use hardware.get_simulator_names because it checks config. new_value = hardware.ALL_NAMES try: self.logger.trace(f'Setting config key={key!r} new_value={new_value!r}') config_value = client.set_config(key, new_value, host=self._config_host, port=self._config_port, *args, **kwargs) self.logger.trace(f'Config set config_value={config_value!r}') except ConnectionError as e: # pragma: no cover self.logger.critical(f'Cannot connect to config_server from {self.__class__}: {e!r}') return config_value
def test_config_reset(config_host, config_port): # Reset config via url url = f'http://{config_host}:{config_port}/reset-config' def reset_conf(): response = requests.post(url, data=serializers.to_json({'reset': True}), headers={'Content-Type': 'application/json'}) assert response.ok reset_conf() # Check we are at default value. assert get_config('location.horizon') == 30 * u.degree # Set to new value. set_config_return = set_config('location.horizon', 3 * u.degree) assert set_config_return == {'location.horizon': 3 * u.degree} # Check we have changed. assert get_config('location.horizon') == 3 * u.degree reset_conf() # Check we are at default again. assert get_config('location.horizon') == 30 * u.degree
def test_config_client(): assert isinstance(get_config(), dict) assert get_config('location.horizon') == 30 * u.degree assert set_config('location.horizon', 47 * u.degree) == { 'location.horizon': 47 * u.degree } assert get_config('location.horizon') == 47 * u.degree # Without parsing the result contains the double-quotes since that's what the raw # response has. assert get_config('location.horizon', parse=False) == '"47.0 deg"' assert set_config('location.horizon', 42 * u.degree, parse=False) == { 'location.horizon': '42.0 deg' }
def dynamic_config_server(config_host, config_port, config_path, images_dir, db_name): """If a test requires changing the configuration we use a function-scoped testing server. We only do this on tests that require it so we are not constantly starting and stopping the config server unless necessary. To use this, each test that requires it must use the `dynamic_config_server` and `config_port` fixtures and must pass the `config_port` to all instances that are created (propogated through PanBase). """ print(f'Starting config_server for testing function') proc = config_server( host=config_host, port=config_port, config_file=config_path, ignore_local=True, ) print(f'config_server started with PID={proc.pid}') # Give server time to start time.sleep(1) # Adjust various config items for testing unit_name = 'Generic PANOPTES Unit' unit_id = 'PAN000' print(f'Setting testing name and unit_id to {unit_id}') set_config('name', unit_name, port=config_port) set_config('pan_id', unit_id, port=config_port) print(f'Setting testing database to {db_name}') set_config('db.name', db_name, port=config_port) fields_file = 'simulator.yaml' print(f'Setting testing scheduler fields_file to {fields_file}') set_config('scheduler.fields_file', fields_file, port=config_port) # TODO(wtgee): determine if we need separate directories for each module. print(f'Setting temporary image directory for testing') set_config('directories.images', images_dir, port=config_port) yield print(f'Killing config_server started with PID={proc.pid}') proc.terminate()
def test_set_dome(): set_config('dome', { 'brand': 'Simulacrum', 'driver': 'simulator', }) dome = create_dome_simulator() obs = Observatory(dome=dome) assert obs.has_dome is True obs.set_dome(dome=None) assert obs.has_dome is False obs.set_dome(dome=dome) assert obs.has_dome is True err_msg = 'Dome is not an instance of .*AbstractDome' with pytest.raises(TypeError, match=err_msg): obs.set_dome('dome') err_msg = ".*missing 1 required positional argument.*" with pytest.raises(TypeError, match=err_msg): obs.set_dome()
def test_config_client_bad(dynamic_config_server, config_port, caplog): # Bad host will return `None` but also throw error assert set_config('foo', 42, host='foobaz') is None assert caplog.records[-1].levelname == "INFO" assert caplog.records[-1].message.startswith("Problem with set_config") # Bad host will return `None` but also throw error assert get_config('foo', host='foobaz') is None assert caplog.records[-1].levelname == "INFO" assert caplog.records[-1].message.startswith("Problem with get_config")
def static_config_server(config_host, static_config_port, config_server_args, images_dir, db_name): logger = get_root_logger() logger.critical(f'Starting config_server for testing session') def start_config_server(): # Load the config items into the app config. for k, v in config_server_args.items(): app.config[k] = v # Start the actual flask server. app.run(host=config_host, port=static_config_port) proc = Process(target=start_config_server) proc.start() logger.info(f'config_server started with PID={proc.pid}') # Give server time to start time.sleep(1) # Adjust various config items for testing unit_name = 'Generic PANOPTES Unit' unit_id = 'PAN000' logger.info(f'Setting testing name and unit_id to {unit_id}') set_config('name', unit_name, port=static_config_port) set_config('pan_id', unit_id, port=static_config_port) logger.info(f'Setting testing database to {db_name}') set_config('db.name', db_name, port=static_config_port) fields_file = 'simulator.yaml' logger.info(f'Setting testing scheduler fields_file to {fields_file}') set_config('scheduler.fields_file', fields_file, port=static_config_port) # TODO(wtgee): determine if we need separate directories for each module. logger.info(f'Setting temporary image directory for testing') set_config('directories.images', images_dir, port=static_config_port) yield logger.critical(f'Killing config_server started with PID={proc.pid}') proc.terminate()
def dome(): # Install our test handlers for the duration. serial.protocol_handler_packages.append('panoptes.pocs.dome') # Modify the config so that the dome uses the right controller and port. set_config('simulator', hardware.get_all_names(without=['dome'])) set_config( 'dome', { 'brand': 'Astrohaven', 'driver': 'astrohaven', 'port': 'astrohaven_simulator://', }) the_dome = create_dome_simulator() yield the_dome with suppress(Exception): the_dome.disconnect() # Remove our test handlers. serial.protocol_handler_packages.remove('panoptes.pocs.dome')
def test_operate_dome(): # Remove dome and night simulator set_config('simulator', hardware.get_all_names(without=['dome', 'night'])) set_config('dome', { 'brand': 'Simulacrum', 'driver': 'simulator', }) set_config('dome', { 'brand': 'Simulacrum', 'driver': 'simulator', }) dome = create_dome_simulator() observatory = Observatory(dome=dome) assert observatory.has_dome assert observatory.open_dome() assert observatory.dome.is_open assert not observatory.dome.is_closed assert observatory.open_dome() assert observatory.dome.is_open assert not observatory.dome.is_closed assert observatory.close_dome() assert observatory.dome.is_closed assert not observatory.dome.is_open assert observatory.close_dome() assert observatory.dome.is_closed assert not observatory.dome.is_open assert observatory.open_dome() assert observatory.dome.is_open assert not observatory.dome.is_closed
def test_config_client(dynamic_config_server, config_port): assert isinstance(get_config(port=config_port), dict) assert set_config('location.horizon', 47 * u.degree, port=config_port) == { 'location.horizon': 47 * u.degree } # With parsing assert get_config('location.horizon', port=config_port) == 47 * u.degree # Without parsing assert get_config('location.horizon', port=config_port, parse=False) == '47.0 deg'
def static_config_server(config_host, static_config_port, config_path, images_dir, db_name): logger = get_root_logger() logger.critical(f'Starting config_server for testing session') proc = config_server( host=config_host, port=static_config_port, config_file=config_path, ignore_local=True, ) logger.info(f'config_server started with PID={proc.pid}') # Give server time to start time.sleep(1) # Adjust various config items for testing unit_name = 'Generic PANOPTES Unit' unit_id = 'PAN000' logger.info(f'Setting testing name and unit_id to {unit_id}') set_config('name', unit_name, port=static_config_port) set_config('pan_id', unit_id, port=static_config_port) logger.info(f'Setting testing database to {db_name}') set_config('db.name', db_name, port=static_config_port) fields_file = 'simulator.yaml' logger.info(f'Setting testing scheduler fields_file to {fields_file}') set_config('scheduler.fields_file', fields_file, port=static_config_port) # TODO(wtgee): determine if we need separate directories for each module. logger.info(f'Setting temporary image directory for testing') set_config('directories.images', images_dir, port=static_config_port) yield logger.critical(f'Killing config_server started with PID={proc.pid}') proc.terminate()
def config_setter(context, key, new_value, parse=True): """Set an item in the config server. """ host = context.obj.get('host') port = context.obj.get('port') logger.debug( f'Setting config key={key!r} new_value={new_value!r} on {host}:{port}' ) config_entry = set_config(key, new_value, host=host, port=port, parse=parse) click.echo(config_entry)
def test_set_mount(): obs = Observatory() assert obs.mount is None obs.set_mount(mount=None) assert obs.mount is None set_config( 'mount', { 'brand': 'Simulacrum', 'driver': 'simulator', 'model': 'panoptes.pocs.camera.simulator.dslr', }) mount = create_mount_from_config() obs.set_mount(mount=mount) assert isinstance(obs.mount, AbstractMount) is True err_msg = 'Mount is not an instance of .*AbstractMount' with pytest.raises(TypeError, match=err_msg): obs.set_mount(mount='mount') err_msg = ".*missing 1 required positional argument.*" with pytest.raises(TypeError, match=err_msg): obs.set_mount()
def test_config_client_bad(caplog): # Bad host will return `None` but also throw error assert set_config('foo', 42, host='foobaz') is None assert caplog.records[-1].levelname == "WARNING" assert caplog.records[-1].message.startswith("Problem with set_config") # Bad host will return `None` but also throw error assert get_config('foo', host='foobaz') is None found_log = False for rec in caplog.records[-5:]: if rec.levelname == 'WARNING' and rec.message.startswith( 'Problem with get_config'): found_log = True assert found_log
def test_config_reset(dynamic_config_server, config_port, config_host): # Check we are at default. assert get_config('location.horizon', port=config_port) == 30 * u.degree # Set to new value. set_config_return = set_config('location.horizon', 47 * u.degree, port=config_port) assert set_config_return == {'location.horizon': 47 * u.degree} # Check we have changed. assert get_config('location.horizon', port=config_port) == 47 * u.degree # Reset config url = f'http://{config_host}:{config_port}/reset-config' response = requests.post(url, data=serializers.to_json({'reset': True}), headers={'Content-Type': 'application/json'}) assert response.ok # Check we are at default again. assert get_config('location.horizon', port=config_port) == 30 * u.degree
def test_bad_site(config_host, config_port): set_config('location', {}) with pytest.raises(error.PanError): Observatory() reset_conf(config_host, config_port)
def images_dir(tmpdir_factory): directory = tmpdir_factory.mktemp('images') set_config('directories.images', str(directory)) return str(directory)