Add Unit/Integration tests for Dryd-33

- Add unit tests for a couple bugs pointed out by Dryd-33 work
- Add integration tests for work implemented via Dryd-33

Change-Id: I814ee9631fb488dedf484ff8e9c8db0866c9f280
This commit is contained in:
Scott Hussey 2017-12-12 12:06:56 -06:00
parent 693d71cd61
commit 3d9724717c
10 changed files with 193 additions and 33 deletions

View File

@ -17,9 +17,10 @@ from threading import Thread
import time import time
import drydock_provisioner.objects.fields as hd_fields import drydock_provisioner.objects.fields as hd_fields
import drydock_provisioner.statemgmt as statemgmt
import drydock_provisioner.error as errors import drydock_provisioner.error as errors
from drydock_provisioner.orchestrator.actions.orchestrator import Noop
class ProviderDriver(object): class ProviderDriver(object):
"""Generic driver for executing driver actions.""" """Generic driver for executing driver actions."""
@ -47,8 +48,9 @@ class ProviderDriver(object):
task_action = task.action task_action = task.action
if task_action in self.supported_actions: if task_action in self.supported_actions:
task_runner = DriverActionRunner(task_id, self.state_manager, # Just use the Noop action
self.orchestrator) task_action = Noop(task, self.orchestrator, self.state_manager)
task_runner = DriverActionRunner(task_action)
task_runner.start() task_runner.start()
while task_runner.is_alive(): while task_runner.is_alive():
@ -62,17 +64,12 @@ class ProviderDriver(object):
# Execute a single task in a separate thread # Execute a single task in a separate thread
class DriverActionRunner(Thread): class DriverActionRunner(Thread):
def __init__(self, action=None, state_manager=None, orchestrator=None): def __init__(self, action=None):
super().__init__() super().__init__()
self.orchestrator = orchestrator
if isinstance(state_manager, statemgmt.DesignState):
self.state_manager = state_manager
else:
raise errors.DriverError("Invalid state manager specified")
self.action = action self.action = action
self.orchestrator = action.orchestrator
self.state_manager = action.state_manager
def run(self): def run(self):
self.run_action() self.run_action()

View File

@ -21,7 +21,7 @@ from drydock_provisioner.drivers.driver import ProviderDriver
class OobDriver(ProviderDriver): class OobDriver(ProviderDriver):
"""Genneric driver for OOB actions.""" """Genneric driver for OOB actions."""
oob_types_supported = [''] oob_types_supported = ['ipmi']
def __init__(self, **kwargs): def __init__(self, **kwargs):
super(OobDriver, self).__init__(**kwargs) super(OobDriver, self).__init__(**kwargs)

View File

@ -380,7 +380,8 @@ class Task(object):
'request_context': 'request_context':
json.dumps(self.request_context.to_dict()) json.dumps(self.request_context.to_dict())
if self.request_context is not None else None, if self.request_context is not None else None,
'node_filter': self.node_filter, 'node_filter':
self.node_filter,
'action': 'action':
self.action, self.action,
'terminated': 'terminated':

View File

@ -86,7 +86,8 @@ class BaseAction(object):
self.task.register_subtask(split_task) self.task.register_subtask(split_task)
action = self.__class__(split_task, self.orchestrator, action = self.__class__(split_task, self.orchestrator,
self.state_manager) self.state_manager)
split_tasks[split_task.get_id().bytes] = te.submit(action.start) split_tasks[split_task.get_id().bytes] = te.submit(
action.start)
return split_tasks return split_tasks
@ -185,7 +186,9 @@ class Noop(BaseAction):
else: else:
self.logger.debug("Marked task as successful.") self.logger.debug("Marked task as successful.")
self.task.set_status(hd_fields.TaskStatus.Complete) self.task.set_status(hd_fields.TaskStatus.Complete)
self.task.success() target_nodes = self.orchestrator.get_target_nodes(self.task)
for n in target_nodes:
self.task.success(focus=n.name)
self.task.add_status_msg( self.task.add_status_msg(
msg="Noop action.", ctx_type='NA', ctx='NA', error=False) msg="Noop action.", ctx_type='NA', ctx='NA', error=False)
self.task.save() self.task.save()

View File

@ -302,7 +302,6 @@ class Orchestrator(object):
def get_target_nodes(self, task, failures=False, successes=False): def get_target_nodes(self, task, failures=False, successes=False):
"""Compute list of target nodes for given ``task``. """Compute list of target nodes for given ``task``.
If failures is true, then create a node_filter based on task result If failures is true, then create a node_filter based on task result
failures. If successes is true, then create a node_filter based on failures. If successes is true, then create a node_filter based on
task result successes. If both are true, raise an exception. If neither task result successes. If both are true, raise an exception. If neither

View File

@ -0,0 +1,57 @@
# Copyright 2017 AT&T Intellectual Property. All other rights reserved.
#
# 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.
"""Generic testing for the orchestrator."""
import drydock_provisioner.orchestrator.orchestrator as orch
import drydock_provisioner.objects.fields as hd_fields
from drydock_provisioner.orchestrator.actions.orchestrator import PrepareNodes
class TestActionPrepareNodes(object):
def test_preparenodes(self, input_files, deckhand_ingester, setup,
drydock_state):
input_file = input_files.join("deckhand_fullsite.yaml")
design_ref = "file://%s" % str(input_file)
# Build a dummy object that looks like an oslo_config object
# so the orchestrator is configured w/ Noop drivers
class DummyConf(object):
oob_driver = ['drydock_provisioner.drivers.oob.driver.OobDriver']
node_driver = 'drydock_provisioner.drivers.node.driver.NodeDriver'
network_driver = None
orchestrator = orch.Orchestrator(
enabled_drivers=DummyConf(),
state_manager=drydock_state,
ingester=deckhand_ingester)
task = orchestrator.create_task(
design_ref=design_ref,
action=hd_fields.OrchestratorAction.PrepareNodes)
action = PrepareNodes(task, orchestrator, drydock_state)
action.start()
task = drydock_state.get_task(task.get_id())
assert task.result.status == hd_fields.ActionResult.Success
# check that the PrepareNodes action was split
# with 2 nodes in the definition
assert len(task.subtask_id_list) == 2
for st_id in task.subtask_id_list:
st = drydock_state.get_task(st_id)
assert st.action == hd_fields.OrchestratorAction.PrepareNodes

View File

@ -12,8 +12,6 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
"""Generic testing for the orchestrator.""" """Generic testing for the orchestrator."""
import pytest
import drydock_provisioner.orchestrator.orchestrator as orch import drydock_provisioner.orchestrator.orchestrator as orch
import drydock_provisioner.objects.fields as hd_fields import drydock_provisioner.objects.fields as hd_fields
@ -21,7 +19,6 @@ from drydock_provisioner.orchestrator.actions.orchestrator import PrepareSite
class TestActionPrepareSite(object): class TestActionPrepareSite(object):
@pytest.mark.skip(reason="test failure fixed in next PS")
def test_preparesite(self, input_files, deckhand_ingester, setup, def test_preparesite(self, input_files, deckhand_ingester, setup,
drydock_state): drydock_state):
input_file = input_files.join("deckhand_fullsite.yaml") input_file = input_files.join("deckhand_fullsite.yaml")

View File

@ -18,19 +18,17 @@ import time
import drydock_provisioner.orchestrator.orchestrator as orch import drydock_provisioner.orchestrator.orchestrator as orch
import drydock_provisioner.objects.fields as hd_fields import drydock_provisioner.objects.fields as hd_fields
from drydock_provisioner.ingester.ingester import Ingester
class TestClass(object): class TestClass(object):
def test_task_complete(self, setup, blank_state): def test_task_complete(self, yaml_ingester, input_files, setup, blank_state):
ingester = Ingester() input_file = input_files.join("fullsite.yaml")
ingester.enable_plugin( design_ref = "file://%s" % str(input_file)
'drydock_provisioner.ingester.plugins.yaml.YamlIngester')
orchestrator = orch.Orchestrator( orchestrator = orch.Orchestrator(
state_manager=blank_state, ingester=ingester) state_manager=blank_state, ingester=yaml_ingester)
orch_task = orchestrator.create_task( orch_task = orchestrator.create_task(
action=hd_fields.OrchestratorAction.Noop) action=hd_fields.OrchestratorAction.Noop,
design_ref=design_ref)
orch_task.set_status(hd_fields.TaskStatus.Queued) orch_task.set_status(hd_fields.TaskStatus.Queued)
orch_task.save() orch_task.save()
@ -47,15 +45,15 @@ class TestClass(object):
orchestrator.stop_orchestrator() orchestrator.stop_orchestrator()
orch_thread.join(10) orch_thread.join(10)
def test_task_termination(self, setup, blank_state): def test_task_termination(self, input_files, yaml_ingester, setup, blank_state):
ingester = Ingester() input_file = input_files.join("fullsite.yaml")
ingester.enable_plugin( design_ref = "file://%s" % str(input_file)
'drydock_provisioner.ingester.plugins.yaml.YamlIngester')
orchestrator = orch.Orchestrator( orchestrator = orch.Orchestrator(
state_manager=blank_state, ingester=ingester) state_manager=blank_state, ingester=yaml_ingester)
orch_task = orchestrator.create_task( orch_task = orchestrator.create_task(
action=hd_fields.OrchestratorAction.Noop) action=hd_fields.OrchestratorAction.Noop,
design_ref=design_ref)
orch_task.set_status(hd_fields.TaskStatus.Queued) orch_task.set_status(hd_fields.TaskStatus.Queued)
orch_task.save() orch_task.save()

View File

@ -38,6 +38,33 @@ class TestPostgres(object):
assert result assert result
def task_task_node_filter(self, blank_state):
"""Test that a persisted task persists node filter."""
ctx = DrydockRequestContext()
ctx.user = 'sh8121'
ctx.external_marker = str(uuid.uuid4())
node_filter = {
'filter_set_type': 'union',
'filter_set': [{
'node_names': ['foo'],
'filter_type': 'union'
}]
}
task = objects.Task(
action='deploy_node',
node_filter=node_filter,
design_ref='http://foo.bar/design',
context=ctx)
result = blank_state.post_task(task)
assert result
saved_task = blank_state.get_task(task.get_id())
assert saved_task.node_filter == node_filter
def test_subtask_append(self, blank_state): def test_subtask_append(self, blank_state):
"""Test that the atomic subtask append method works.""" """Test that the atomic subtask append method works."""

View File

@ -0,0 +1,81 @@
# Copyright 2017 AT&T Intellectual Property. All other rights reserved.
#
# 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.
"""Test the node filter logic in the orchestrator."""
import drydock_provisioner.objects as objects
import drydock_provisioner.objects.fields as hd_fields
class TestTaskFilterGeneration(object):
def test_task_success_focus(self, setup):
"""Test that marking a task successful works correctly."""
task = objects.Task(
action=hd_fields.OrchestratorAction.Noop,
design_ref="http://foo.com")
task.success(focus='foo')
assert task.result.status == hd_fields.ActionResult.Success
assert 'foo' in task.result.successes
def test_task_failure_focus(self, setup):
"""Test that marking a task failed works correctly."""
task = objects.Task(
action=hd_fields.OrchestratorAction.Noop,
design_ref="http://foo.com")
task.failure(focus='foo')
assert task.result.status == hd_fields.ActionResult.Failure
assert 'foo' in task.result.failures
def test_task_success_nf(self, setup):
"""Test that a task can generate a node filter based on its success."""
task = objects.Task(
action=hd_fields.OrchestratorAction.Noop,
design_ref="http://foo.com")
expected_nf = {
'filter_set_type': 'intersection',
'filter_set': [{
'node_names': ['foo'],
'filter_type': 'union',
}]
}
task.success(focus='foo')
nf = task.node_filter_from_successes()
assert nf == expected_nf
def test_task_failure_nf(self, setup):
"""Test that a task can generate a node filter based on its failure."""
task = objects.Task(
action=hd_fields.OrchestratorAction.Noop,
design_ref="http://foo.com")
expected_nf = {
'filter_set_type': 'intersection',
'filter_set': [{
'node_names': ['foo'],
'filter_type': 'union',
}]
}
task.failure(focus='foo')
nf = task.node_filter_from_failures()
assert nf == expected_nf