def test_config_file_is_unicode_clean(self): self.__files.create({ self.__config_name: textwrap.dedent("""\ # -*- coding: utf-8 -*- from shinysdr.i.test_config import StubDevice config.devices.add(u'•', StubDevice()) """), }) execute_config(self.__config, self.__config_name) self.assertEqual({u'•'}, set(self.__config.devices._values.keys()))
def test_db_content_warning(self): self.__files.create({ self.__config_name: { 'config.py': '', 'dbs-read-only': { 'foo.csv': 'Name\na', }, }, }) execute_config(self.__config, self.__config_name) self.__config.devices.add(u'stub_for_completion', StubDevice()) yield self.__config._wait_and_validate() self.log_tester.check( dict(log_format='{path}: {db_diagnostic}', path='foo.csv'), NO_NETWORK)
def test_default_config(self): write_default_config(self.__config_name) self.assertTrue(os.path.isdir(self.__config_name)) # Don't try to open a real device with open(self.__dirpath('config.py'), 'r') as f: conf_text = f.read() DEFAULT_DEVICE = "OsmoSDRDevice('')" self.assertIn(DEFAULT_DEVICE, conf_text) conf_text = conf_text.replace(DEFAULT_DEVICE, "OsmoSDRDevice('file=/dev/null,rate=100000')") with open(self.__dirpath('config.py'), 'w') as f: f.write(conf_text) execute_config(self.__config, self.__config_name) self.assertTrue(os.path.isdir(self.__dirpath('dbs-read-only'))) return self.__config._wait_and_validate()
def test_config_directory(self): self.__files.create({ self.__config_name: { 'config.py': 'config.features.enable("_test_disabled_feature")', 'dbs-read-only': { 'foo.csv': 'Frequency,Name', }, }, }) execute_config(self.__config, self.__config_name) # Config python was executed self.assertTrue(self.__config.features._get('_test_disabled_feature')) # Config-directory-related defaults were set self.assertEqual(self.__dirpath('state.json'), self.__config._state_filename) self.assertIn('foo.csv', self.__config.databases._get_read_only_databases())
def test_config_file(self): self.__files.create({ self.__config_name: 'config.features.enable("_test_disabled_feature")', 'dbs': { # DB CSV file we expect NOT to be loaded 'foo.csv': 'Frequency,Name', }, }) execute_config(self.__config, self.__config_name) # Config python was executed self.assertTrue(self.__config.features._get('_test_disabled_feature')) # Config-directory-related defaults were not set self.assertEqual(None, self.__config._state_filename) self.assertEqual(six.viewkeys(get_default_dbs()), six.viewkeys(self.__config.databases._get_read_only_databases()))
def test_traceback_processing(self): self.maxDiff = 1000 self.__files.create({ self.__config_name: 'config.devices.add("will-fail")' }) file_obj = six.StringIO() try: execute_config(self.__config, self.__config_name) self.fail('did not raise') except ConfigException: print_config_exception(sys.exc_info(), file_obj) self.assertEqual( file_obj.getvalue() .replace(self.__files.dir, '<tempdir>') .replace(__file__, '<config.py>'), textwrap.dedent("""\ An error occurred while executing the ShinySDR configuration file: File "<tempdir>/config", line 1, in <module> config.devices.add("will-fail") ConfigException: config.devices.add: no device(s) specified """))
def _main_async(reactor, argv=None, _abort_for_test=False): if argv is None: argv = sys.argv if not _abort_for_test: # Some log messages would be discarded if we did not set up things early. configure_logging() # Option parsing is done before importing the main modules so as to avoid the cost of initializing gnuradio if we are aborting early. TODO: Make that happen for createConfig too. argParser = argparse.ArgumentParser(prog=argv[0]) argParser.add_argument('config_path', metavar='CONFIG', help='path of configuration directory or file') argParser.add_argument( '--create', dest='createConfig', action='store_true', help='write template configuration file to CONFIG and exit') argParser.add_argument('-g, --go', dest='openBrowser', action='store_true', help='open the UI in a web browser') argParser.add_argument( '--force-run', dest='force_run', action='store_true', help='Run DSP even if no client is connected (for debugging).') args = argParser.parse_args(args=argv[1:]) # Verify we can actually run. # Note that this must be done before we actually load core modules, because we might get an import error then. version_report = yield _check_versions() if version_report: print(version_report, file=sys.stderr) sys.exit(1) # Write config file and exit if asked ... if args.createConfig: write_default_config(args.config_path) _log.info('Created default configuration at: {config_path}', config_path=args.config_path) sys.exit(0) # TODO: Consider using a return value or something instead # ... else read config file config_obj = Config(reactor=reactor, log=_log) try: execute_config(config_obj, args.config_path) yield config_obj._wait_and_validate() except ConfigException: print_config_exception(sys.exc_info(), sys.stderr) defer.returnValue(None) return _log.info('Constructing...') app = config_obj._create_app() reactor.addSystemEventTrigger('during', 'shutdown', app.close_all_devices) _log.info('Restoring state...') pfg = PersistenceFileGlue(reactor=reactor, root_object=app, filename=config_obj._state_filename, get_defaults=_app_defaults) _log.info('Starting web server...') services = MultiService() for maker in config_obj._service_makers: IService(maker(app)).setServiceParent(services) services.startService() _log.info('ShinySDR is ready.') for service in services: # TODO: should have an interface (currently no proper module to put it in) service.announce(args.openBrowser) if args.force_run: _log.debug('force_run') # TODO kludge, make this less digging into guts app.get_receive_flowgraph().get_monitor().state()['fft'].subscribe2( lambda v: None, the_subscription_context) if _abort_for_test: services.stopService() yield pfg.sync() defer.returnValue(app) else: yield defer.Deferred() # never fires