Add Voight Kampff support setting configurations
Adds the "Given the user's {config} is {value}" step implementation This will patch the configuration with a section from a dictionary that can either be a global (shipped in mycroft/res/{lang}/configurations.json) or shipped with the test definition. The file should be named the same as the feature file but instead of ".feature" the extension should be ".config.json". mycroft/res/text/en-us/configurations.json contains a couple of pre-defined configurations that can be applied - units (metric/imperial) - location (Stockholm) After each scenario any applied patch will be clearedpull/2576/head
parent
cd1c3b7c1d
commit
46c8a6b51f
|
@ -0,0 +1,33 @@
|
|||
{
|
||||
"unit system": {
|
||||
"metric": {"system_unit": "metric"},
|
||||
"imperial": {"system_unit": "imperial"}
|
||||
},
|
||||
"location": {
|
||||
"stockholm": {
|
||||
"location": {
|
||||
"city": {
|
||||
"name": "Stockholm",
|
||||
"state": {
|
||||
"code": "SE.18",
|
||||
"country": {
|
||||
"code": "SE",
|
||||
"name": "Sweden"
|
||||
},
|
||||
"name": "Stockholm"
|
||||
}
|
||||
},
|
||||
"coordinate": {
|
||||
"latitude": 59.38306,
|
||||
"longitude": 16.66667
|
||||
},
|
||||
"timezone": {
|
||||
"code": "Europe/Stockholm",
|
||||
"dst_offset": 7200000,
|
||||
"name": "Europe/Stockholm",
|
||||
"offset": 3600000
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -19,6 +19,7 @@ from behave.contrib.scenario_autoretry import patch_scenario_with_autoretry
|
|||
|
||||
from msm import MycroftSkillsManager
|
||||
from mycroft.audio import wait_while_speaking
|
||||
from mycroft.configuration import Configuration
|
||||
from mycroft.messagebus.client import MessageBusClient
|
||||
from mycroft.messagebus import Message
|
||||
from mycroft.util import create_daemon
|
||||
|
@ -92,6 +93,9 @@ def before_all(context):
|
|||
context.bus = bus
|
||||
context.matched_message = None
|
||||
context.log = log
|
||||
context.original_config = {}
|
||||
context.config = Configuration.get()
|
||||
Configuration.set_config_update_handlers(bus)
|
||||
|
||||
|
||||
def before_feature(context, feature):
|
||||
|
@ -110,9 +114,26 @@ def after_feature(context, feature):
|
|||
sleep(1)
|
||||
|
||||
|
||||
def reset_config(context):
|
||||
"""Reset configuration with changes stored in original_config of context.
|
||||
"""
|
||||
context.log.info('Resetting patched configuration...')
|
||||
|
||||
context.bus.emit(Message('configuration.patch.clear'))
|
||||
key = list(context.original_config)[0]
|
||||
while context.config[key] != context.original_config[key]:
|
||||
sleep(0.5)
|
||||
context.original_config = {}
|
||||
|
||||
|
||||
def after_scenario(context, scenario):
|
||||
"""Wait for mycroft completion and reset any changed state."""
|
||||
# TODO wait for skill handler complete
|
||||
sleep(0.5)
|
||||
wait_while_speaking()
|
||||
context.bus.clear_messages()
|
||||
context.matched_message = None
|
||||
|
||||
if context.original_config:
|
||||
# something has changed, reset changes by done in the context
|
||||
reset_config(context)
|
||||
|
|
|
@ -0,0 +1,105 @@
|
|||
# Copyright 2020 Mycroft AI Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
import json
|
||||
from os.path import join, exists
|
||||
import time
|
||||
|
||||
from behave import given
|
||||
from mycroft.messagebus import Message
|
||||
from mycroft.util import resolve_resource_file
|
||||
|
||||
|
||||
def patch_config(context, patch):
|
||||
"""Apply patch to config and wait for it to take effect.
|
||||
|
||||
Arguments:
|
||||
context: Behave context for test
|
||||
patch: patch to apply
|
||||
"""
|
||||
# store originals in context
|
||||
for key in patch:
|
||||
# If this patch is redefining an already changed key don't update
|
||||
if key not in context.original_config:
|
||||
context.original_config[key] = context.config.get(key)
|
||||
|
||||
# Patch config
|
||||
patch_config_msg = Message('configuration.patch', {'config': patch})
|
||||
context.bus.emit(patch_config_msg)
|
||||
|
||||
# Wait until one of the keys has been updated
|
||||
key = list(patch.keys())[0]
|
||||
while context.config.get(key) != patch[key]:
|
||||
time.sleep(0.5)
|
||||
|
||||
|
||||
def get_config_file_definition(configs_path, config, value):
|
||||
"""Read config definition file and return the matching patch dict.
|
||||
|
||||
Arguments:
|
||||
configs_path: path to the configuration patch json file
|
||||
config: config value to fetch from the file
|
||||
value: predefined value to fetch
|
||||
|
||||
Returns:
|
||||
Patch dictionary or None.
|
||||
"""
|
||||
with open(configs_path) as f:
|
||||
configs = json.load(f)
|
||||
return configs.get(config, {}).get(value)
|
||||
|
||||
|
||||
def get_global_config_definition(context, config, value):
|
||||
"""Get config definitions included with Mycroft.
|
||||
|
||||
Arguments:
|
||||
context: behave test context
|
||||
config: config value to fetch from the file
|
||||
value: predefined value to fetch
|
||||
|
||||
Returns:
|
||||
Patch dictionary or None.
|
||||
"""
|
||||
configs_path = resolve_resource_file(join('text', context.lang,
|
||||
'configurations.json'))
|
||||
return get_config_file_definition(configs_path, config, value)
|
||||
|
||||
|
||||
def get_feature_config_definition(context, config, value):
|
||||
"""Get config feature specific config defintion
|
||||
|
||||
Arguments:
|
||||
context: behave test context
|
||||
config: config value to fetch from the file
|
||||
value: predefined value to fetch
|
||||
|
||||
Returns:
|
||||
Patch dictionary or None.
|
||||
"""
|
||||
feature_config = context.feature.filename.replace('.feature',
|
||||
'.config.json')
|
||||
if exists(feature_config):
|
||||
return get_config_file_definition(feature_config, config, value)
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
@given('the user\'s {config} is {value}')
|
||||
def given_config(context, config, value):
|
||||
"""Patch the configuration with a specific config."""
|
||||
config = config.strip('"')
|
||||
value = value.strip('"')
|
||||
patch_dict = (get_feature_config_definition(context, config, value) or
|
||||
get_global_config_definition(context, config, value))
|
||||
patch_config(context, patch_dict)
|
|
@ -38,6 +38,13 @@ that anyi specified extra skills also gets installed into the environment.
|
|||
FEATURE_DIR = join(dirname(__file__), 'features') + '/'
|
||||
|
||||
|
||||
def copy_config_definition_files(source, destination):
|
||||
"""Copy all feature files from source to destination."""
|
||||
# Copy feature files to the feature directory
|
||||
for f in glob(join(source, '*.config.json')):
|
||||
shutil.copyfile(f, join(destination, basename(f)))
|
||||
|
||||
|
||||
def copy_feature_files(source, destination):
|
||||
"""Copy all feature files from source to destination."""
|
||||
# Copy feature files to the feature directory
|
||||
|
@ -141,6 +148,7 @@ def collect_test_cases(msm, skills):
|
|||
behave_dir = join(skill.path, 'test', 'behave')
|
||||
if exists(behave_dir):
|
||||
copy_feature_files(behave_dir, FEATURE_DIR)
|
||||
copy_config_definition_files(behave_dir, FEATURE_DIR)
|
||||
|
||||
step_dir = join(behave_dir, 'steps')
|
||||
if exists(step_dir):
|
||||
|
|
Loading…
Reference in New Issue