master
Tom Wilson 6 years ago
parent 3e6e481a0f
commit e464ff942b

@ -42,9 +42,13 @@ def control_confspec():
class CoreUpdateState():
"""
A container for all state that might need communicating remotely to Control. Abstracts the
Statesman topics away from other parts of the Agent.
"""
def __init__(self, cmd_reader, cmd_result_writer):
"""
Control update handler for the `/update` core endpoint.
Control update handler for the `/update` core endpoint. Needs a reference to the CommandRunner
"""
self.topic_bundle = statesman.TopicBundle({
'status': statesman.StateWriter(),

@ -78,6 +78,8 @@ class Agent():
def start(self):
# After this point, plugins may already have their own threads running if they create
# them during init
plugin_interfaces, self.interface_functions = plugin.init_plugins(
self.plugin_configs, self.core_config, {})
@ -97,6 +99,19 @@ class Agent():
log.warning("Shepherd control config section not present. Will not attempt to"
" connect to Shepherd Control server.")
# Shift Control check to when it actually tries to find config, and just set
# control_enabled to false.
# Does all the other cmd_runner and update state stuff need to happen still if
# control is disabled?
# Should Core really need to know anything about the command runner, or should it
# just hand the interface functions in directly to Control?
# Need somewhere to eventually pass in the hooks Tasks will need for the lowpower stuff,
# probably just another init_plugins arg.
# Eventually when the dust settles we might revisit converting the core "shepherd"
# namespace stuff into it's own plugin interface, as it's using a lot of the same
# mechanisms, but we're having to pass it all around individually.
# tasks.init_tasks(self.core_config) # seperate tasks.start?
# plugin.start() # Run the plugin `.run` hooks in seperate threads
@ -226,8 +241,9 @@ def core_confspec():
confspec.add_specs(optional=True, spec_dict={
"root_dir":
(StringSpec(helptext="Operating directory for shepherd to place working files."),
"./shepherd"),
(StringSpec(helptext="Operating directory for shepherd to place working files."
" Relative to the directory containing the default config file."),
"./"),
"custom_config_path":
StringSpec(helptext="Path to custom config layer TOML file."),
"compiled_config_path":

@ -186,7 +186,6 @@ def test_command_runner():
wr_msg = list(cmd_runner.cmd_result_writer._messages.values())[-1]
assert wr_msg == [15, 9]
# Control/Plugin integration tests
# Test command_runner with actual plugin

@ -0,0 +1,94 @@
# pylint: disable=redefined-outer-name
from pathlib import Path
import logging
import pytest
from shepherd.agent import core
@pytest.fixture
def local_agent():
return core.Agent(control_enabled=False)
@pytest.fixture
def basic_config(tmp_path):
def_conf_file = tmp_path / "shepherd_default.toml"
def_conf_file.write_text("""
[shepherd]
name = "shepherd-test"
""")
return def_conf_file
@pytest.fixture
def custom_config(tmp_path):
def_conf_file = tmp_path / "shepherd_default.toml"
def_conf_file.write_text("""
[shepherd]
name = "shepherd-test"
custom_config_path = "shepherd_custom.toml"
""")
custom_conf_file = tmp_path / "shepherd_custom.toml"
custom_conf_file.write_text("""
[shepherd]
name = "shepherd-custom"
""")
return def_conf_file
@pytest.fixture
def plugin_config(tmp_path, request):
plugin_dir = Path(request.fspath.dirname)/'assets'
def_conf_file = tmp_path / "shepherd_default.toml"
def_conf_file.write_text(F"""
[shepherd]
name = "shepherd-test"
plugin_dir = "{plugin_dir}"
[classtestplugin]
spec1 = "asdf"
""")
return def_conf_file
def test_local_agent(local_agent):
pass
def test_local_agent_load(local_agent, basic_config):
local_agent.load(basic_config)
def test_local_compiled_conf(local_agent, basic_config):
local_agent.load(basic_config)
compiled_conf = (basic_config.parent / "compiled-config.toml").read_text()
assert 'name = "shepherd-test"' in compiled_conf
# Paths should be resolved to absolute
assert 'plugin_dir = "/' in compiled_conf
assert 'Compiled Shepherd config' in compiled_conf
def test_custom_conf_load(local_agent, custom_config):
local_agent.load(custom_config)
assert local_agent.core_config["name"] == "shepherd-custom"
def test_new_device_trigger(local_agent, custom_config, caplog):
caplog.set_level(logging.INFO)
(custom_config.parent / "shepherd.new").touch()
local_agent.load(custom_config)
assert "'new device' mode enabled" in caplog.text
assert (custom_config.parent / "shepherd.identity").exists()
def test_local_agent_start(local_agent, basic_config):
local_agent.load(basic_config)
local_agent.start()
def test_local_agent_plugin_start(local_agent, plugin_config):
local_agent.load(plugin_config)
local_agent.start()
assert local_agent.interface_functions["classtestplugin"].instance_method(
3) == "instance method 3"
Loading…
Cancel
Save