diff --git a/src/freeseer/frontend/controller/configuration.py b/src/freeseer/frontend/controller/configuration.py index 7f4ea28e..5f16782a 100644 --- a/src/freeseer/frontend/controller/configuration.py +++ b/src/freeseer/frontend/controller/configuration.py @@ -113,8 +113,8 @@ def update_config(config, data): Raises: HTTPError: If given data changes don't conform to config's schema. """ + for key, value in data.items(): - # TODO: Add json-schema validation when pr #646 is merged. try: opt_instance = config.options[key] value = opt_instance.decode(value) @@ -126,6 +126,37 @@ def update_config(config, data): config.save() +def pack_configuration(config, include=[]): + """ + Returns a response for the given config. + + Args: + config: A Config instance. + include: An optional list of Config options to include in response. + + Returns: + A dict containing the given configuration, and its schema. If an + 'include' list is given, only the options listed are returned in + the configuration. + """ + conf = {} + schema = {} + + if include: + for key in include: + option = config.options[key] + conf[key] = option.presentation(config.values[key]) + schema[key] = option.schema() + else: + conf = config.values + schema = config.schema() + + return { + 'configuration': conf, + 'schema': schema, + } + + @configuration.before_app_first_request def configure_configuration(): """ @@ -142,7 +173,8 @@ def load_profile_configuration(profile): HTTPError: If profile does not exist. """ profile_instance = load_profile(profile) - return profile_instance.get_config('freeseer.conf', settings.FreeseerConfig, storage_args=['Global'], read_only=False) + return profile_instance.get_config('freeseer.conf', settings.FreeseerConfig, storage_args=['Global'], + read_only=False) def load_profile(profile): @@ -216,7 +248,7 @@ def view_profile(profile): HTTPError: If profile doesn't exist. """ profile_configuration = load_profile_configuration(profile) - return {'profile_configuration': profile_configuration.values} + return pack_configuration(profile_configuration) @configuration.route('/profiles', methods=['POST']) @@ -291,10 +323,7 @@ def view_general_configuration(profile): HTTPError: If profile does not exist. """ profile_configuration = load_profile_configuration(profile) - return { - 'default_language': profile_configuration.default_language, - 'auto_hide': profile_configuration.auto_hide, - } + return pack_configuration(profile_configuration, include=['default_language', 'auto_hide']) @configuration.route('/profiles//general', methods=['PATCH']) @@ -311,6 +340,8 @@ def modify_general_configuration(profile): changes = request.form update_config(profile_configuration, changes) return '' + + # # General Configuration Endpoints # @@ -330,17 +361,17 @@ def view_recording_configuration(profile): HTTPError: If profile does not exist. """ profile_configuration = load_profile_configuration(profile) - return { - 'record_to_file': profile_configuration.record_to_file, - 'videodir': profile_configuration.videodir, - 'record_to_file_plugin': profile_configuration.record_to_file_plugin, - 'record_to_stream': profile_configuration.record_to_stream, - 'record_to_stream_plugin': profile_configuration.record_to_stream_plugin, - 'enable_audio_recording': profile_configuration.enable_audio_recording, - 'audiomixer': profile_configuration.audiomixer, - 'enable_video_recording': profile_configuration.enable_video_recording, - 'videomixer': profile_configuration.videomixer, - } + return pack_configuration(profile_configuration, include=[ + 'record_to_file', + 'videodir', + 'record_to_file_plugin', + 'record_to_stream', + 'record_to_stream_plugin', + 'enable_audio_recording', + 'audiomixer', + 'enable_video_recording', + 'videomixer', + ]) @configuration.route('/profiles//recording', methods=['PATCH']) @@ -357,6 +388,8 @@ def modify_recording_configuration(profile): changes = request.form update_config(profile_configuration, changes) return '' + + # # End recording configuration endpoints. # @@ -380,6 +413,8 @@ def list_plugin_category(profile, category): return { 'plugins': [plugin.name for plugin in plugin_infos] } + + # # End of plugin category endpoints. # @@ -410,9 +445,7 @@ def view_plugin_instance(profile, category, plugin, id): HTTPError: If profile, category, or plugin do not exist. """ plugin_config = get_plugin_config(profile, category, plugin, id) - return { - 'configuration': plugin_config.values - } + return pack_configuration(plugin_config) @configuration.route('/profiles//recording//', methods=['POST']) @@ -441,6 +474,7 @@ def modify_plugin_instance(profile, category, plugin, id): changes = request.form update_config(plugin_config, changes) return '' + # # End of plugin endpoints. # diff --git a/src/freeseer/tests/frontend/controller/test_configuration.py b/src/freeseer/tests/frontend/controller/test_configuration.py index 9d9ae14f..e0092a9b 100644 --- a/src/freeseer/tests/frontend/controller/test_configuration.py +++ b/src/freeseer/tests/frontend/controller/test_configuration.py @@ -32,6 +32,15 @@ from freeseer.frontend.controller import server +def pack_schema(config, include): + """Returns a partial schema from the options in 'include'.""" + schema = {} + for key in include: + schema[key] = config.options[key].schema() + print schema + return schema + + class TestConfigurationApp: @pytest.fixture(scope='module') def test_client(self): @@ -63,8 +72,18 @@ def test_list_profiles(self, test_client): assert response.status_code == 200 assert expected == data - def test_view_profile(self, test_client): + def test_view_profile(self, test_client, configuration): response = test_client.get('/profiles/testing') + configuration.config = configuration.profile.get_config('freeseer.conf', + settings.FreeseerConfig, + ['Global'], + read_only=True) + expected = { + 'configuration': configuration.config.values, + 'schema': configuration.config.schema(), + } + data = json.loads(response.data) + assert expected == data assert response.status_code == 200 def test_view_profile_nonexistant_id(self, test_client): @@ -136,8 +155,11 @@ def test_view_general_configuration(self, test_client, configuration): ['Global'], read_only=True) assert response_data == { - 'default_language': general.default_language, - 'auto_hide': general.auto_hide, + 'configuration': { + 'default_language': general.default_language, + 'auto_hide': general.auto_hide, + }, + 'schema': pack_schema(general, ['default_language', 'auto_hide']), } assert response.status_code == 200 @@ -158,72 +180,87 @@ def test_modify_general_configuration(self, test_client, configuration): def test_view_recording_configuration(self, test_client, configuration): response = test_client.get('/profiles/testing/recording') - response_data = json.loads(response.data) - config = configuration.config - assert response.status_code == 200 - assert response_data == { - 'record_to_file': config.record_to_file, - 'videodir': config.videodir, - 'record_to_file_plugin': config.record_to_file_plugin, - 'record_to_stream': config.record_to_stream, - 'record_to_stream_plugin': config.record_to_stream_plugin, - 'enable_audio_recording': config.enable_audio_recording, - 'audiomixer': config.audiomixer, - 'enable_video_recording': config.enable_video_recording, - 'videomixer': config.videomixer, - } - - def test_list_plugin_category(self, test_client, configuration): - response = test_client.get('/profiles/testing/recording/audioinput') - plugin_infos = configuration.plugin_manager.get_plugins_of_category('AudioInput') - expected = {'plugins': [plugin.name for plugin in plugin_infos]} data = json.loads(response.data) - assert data == expected - assert response.status_code == 200 - - def test_list_plugin_instances(self, test_client, configuration): - response = test_client.get('/profiles/testing/recording/audioinput/jackaudiosource') - assert response.status_code == 501 - - def test_view_plugin_instance(self, test_client, configuration): - response = test_client.get('/profiles/testing/recording/audioinput/jackaudiosource/0') - plugin = configuration.plugin_manager.get_plugin_by_name('Jack Audio Source', 'AudioInput') - plugin_object = plugin.plugin_object - plugin_object.set_instance(0) - plugin_object.load_config(configuration.plugin_manager) + config = configuration.config expected = { - 'configuration': plugin_object.config.values + 'configuration': { + 'record_to_file': config.record_to_file, + 'videodir': config.videodir, + 'record_to_file_plugin': config.record_to_file_plugin, + 'record_to_stream': config.record_to_stream, + 'record_to_stream_plugin': config.record_to_stream_plugin, + 'enable_audio_recording': config.enable_audio_recording, + 'audiomixer': config.audiomixer, + 'enable_video_recording': config.enable_video_recording, + 'videomixer': config.videomixer, + }, + 'schema': pack_schema(config, [ + 'record_to_file', + 'videodir', + 'record_to_file_plugin', + 'record_to_stream', + 'record_to_stream_plugin', + 'enable_audio_recording', + 'audiomixer', + 'enable_video_recording', + 'videomixer', + ]), } - data = json.loads(response.data) - assert response.status_code == 200 - assert expected == data - - def test_view_invalid_plugin_name(self, test_client, configuration): - response = test_client.get('/profiles/testing/recording/audioinput/fakeaudiosource/0') - data = json.loads(response.data) - assert data['error_message'] == 'Invalid Plugin Name: fakeaudiosource' - assert response.status_code == 400 - - def test_view_invalid_plugin_category(self, test_client, configuration): - response = test_client.get('/profiles/testing/recording/fakeinput/jackaudiosource/0') - data = json.loads(response.data) - assert data['error_message'] == 'Invalid Plugin Category: fakeinput' - assert response.status_code == 400 - - def test_create_plugin_instance(self, test_client, configuration): - response = test_client.post('/profiles/testing/recording/audioinput/jackaudiosource') - assert response.status_code == 501 - - def test_modify_plugin_instance(profile, test_client, configuration): - response = test_client.patch('/profiles/testing/recording/audioinput/jackaudiosource/0', - data={ - 'client': 'testclient', - 'connect': 'testconnect', - }) - plugin = configuration.plugin_manager.get_plugin_by_name('Jack Audio Source', 'AudioInput') - plugin_object = plugin.plugin_object - plugin_object.set_instance(0) - - assert plugin_object.config.client == 'testclient' - assert plugin_object.config.connect == 'testconnect' assert response.status_code == 200 + assert expected['configuration'] == data['configuration'] + + def test_list_plugin_category(self, test_client, configuration): + response = test_client.get('/profiles/testing/recording/audioinput') + plugin_infos = configuration.plugin_manager.get_plugins_of_category('AudioInput') + expected = {'plugins': [plugin.name for plugin in plugin_infos]} + data = json.loads(response.data) + assert data == expected + assert response.status_code == 200 + + def test_list_plugin_instances(self, test_client, configuration): + response = test_client.get('/profiles/testing/recording/audioinput/jackaudiosource') + assert response.status_code == 501 + + def test_view_plugin_instance(self, test_client, configuration): + response = test_client.get('/profiles/testing/recording/audioinput/jackaudiosource/0') + plugin = configuration.plugin_manager.get_plugin_by_name('Jack Audio Source', 'AudioInput') + plugin_object = plugin.plugin_object + plugin_object.set_instance(0) + plugin_object.load_config(configuration.plugin_manager) + expected = { + 'configuration': plugin_object.config.values, + 'schema': plugin_object.config.schema(), + } + data = json.loads(response.data) + assert response.status_code == 200 + assert expected == data + + def test_view_invalid_plugin_name(self, test_client, configuration): + response = test_client.get('/profiles/testing/recording/audioinput/fakeaudiosource/0') + data = json.loads(response.data) + assert data['error_message'] == 'Invalid Plugin Name: fakeaudiosource' + assert response.status_code == 400 + + def test_view_invalid_plugin_category(self, test_client, configuration): + response = test_client.get('/profiles/testing/recording/fakeinput/jackaudiosource/0') + data = json.loads(response.data) + assert data['error_message'] == 'Invalid Plugin Category: fakeinput' + assert response.status_code == 400 + + def test_create_plugin_instance(self, test_client, configuration): + response = test_client.post('/profiles/testing/recording/audioinput/jackaudiosource') + assert response.status_code == 501 + + def test_modify_plugin_instance(profile, test_client, configuration): + response = test_client.patch('/profiles/testing/recording/audioinput/jackaudiosource/0', + data={ + 'client': 'testclient', + 'connect': 'testconnect', + }) + plugin = configuration.plugin_manager.get_plugin_by_name('Jack Audio Source', 'AudioInput') + plugin_object = plugin.plugin_object + plugin_object.set_instance(0) + + assert plugin_object.config.client == 'testclient' + assert plugin_object.config.connect == 'testconnect' + assert response.status_code == 200