Abstract common cloud driver tests
We want to test node launch and image upload (if relevant) in the same manner for every cloud driver, so abstract those tests into a base class that is shared. Change-Id: I9d000fc9e385286122d818bb5490d6aa07ecd800
This commit is contained in:
parent
f9a368b1c8
commit
08a3c43dd7
@ -26,16 +26,17 @@ from zuul.driver.aws.awsmodel import AwsProviderNode
|
||||
|
||||
from tests.fake_aws import FakeAws, FakeAwsProviderEndpoint
|
||||
from tests.base import (
|
||||
ZuulTestCase,
|
||||
iterate_timeout,
|
||||
simple_layout,
|
||||
return_data,
|
||||
)
|
||||
from tests.unit.test_launcher import ImageMocksFixture
|
||||
from tests.unit.test_cloud_driver import BaseCloudDriverTest
|
||||
|
||||
|
||||
class TestAwsDriver(ZuulTestCase):
|
||||
class TestAwsDriver(BaseCloudDriverTest):
|
||||
config_file = 'zuul-connections-nodepool.conf'
|
||||
cloud_test_image_format = 'raw'
|
||||
mock_aws = mock_aws()
|
||||
debian_return_data = {
|
||||
'zuul': {
|
||||
@ -146,13 +147,38 @@ class TestAwsDriver(ZuulTestCase):
|
||||
super().tearDown()
|
||||
|
||||
@simple_layout('layouts/nodepool.yaml', enable_nodepool=True)
|
||||
def test_aws_config(self):
|
||||
aws_conn = self.scheds.first.sched.connections.connections['aws']
|
||||
self.assertEqual('fake', aws_conn.access_key_id)
|
||||
layout = self.scheds.first.sched.abide.tenants.get('tenant-one').layout
|
||||
provider = layout.providers['aws-us-east-1-main']
|
||||
endpoint = provider.getEndpoint()
|
||||
self.assertEqual([], list(endpoint.listInstances()))
|
||||
def test_aws_node_lifecycle(self):
|
||||
self._test_node_lifecycle('debian-normal')
|
||||
|
||||
@simple_layout('layouts/aws/nodepool-image-snapshot.yaml',
|
||||
enable_nodepool=True)
|
||||
@return_data(
|
||||
'build-debian-local-image',
|
||||
'refs/heads/master',
|
||||
debian_return_data,
|
||||
)
|
||||
def test_aws_diskimage_snapshot(self):
|
||||
self._test_diskimage()
|
||||
|
||||
@simple_layout('layouts/aws/nodepool-image-image.yaml',
|
||||
enable_nodepool=True)
|
||||
@return_data(
|
||||
'build-debian-local-image',
|
||||
'refs/heads/master',
|
||||
debian_return_data,
|
||||
)
|
||||
def test_aws_diskimage_image(self):
|
||||
self._test_diskimage()
|
||||
|
||||
@simple_layout('layouts/aws/nodepool-image-ebs-direct.yaml',
|
||||
enable_nodepool=True)
|
||||
@return_data(
|
||||
'build-debian-local-image',
|
||||
'refs/heads/master',
|
||||
debian_return_data,
|
||||
)
|
||||
def test_aws_diskimage_ebs_direct(self):
|
||||
self._test_diskimage()
|
||||
|
||||
@simple_layout('layouts/nodepool.yaml', enable_nodepool=True)
|
||||
def test_state_machines_instance(self):
|
||||
@ -219,54 +245,3 @@ class TestAwsDriver(ZuulTestCase):
|
||||
'zuul.driver.aws.awsendpoint.AwsProviderEndpoint.'
|
||||
'_completeCreateInstance', return_value=None)):
|
||||
yield
|
||||
|
||||
# Test the 3 image import methods:
|
||||
|
||||
def _test_aws_diskimage_import(self):
|
||||
self.waitUntilSettled()
|
||||
self.assertHistory([
|
||||
dict(name='build-debian-local-image', result='SUCCESS'),
|
||||
], ordered=False)
|
||||
|
||||
name = 'review.example.com%2Forg%2Fcommon-config/debian-local'
|
||||
artifacts = self.launcher.image_build_registry.\
|
||||
getArtifactsForImage(name)
|
||||
self.assertEqual(1, len(artifacts))
|
||||
self.assertEqual('raw', artifacts[0].format)
|
||||
self.assertTrue(artifacts[0].validated)
|
||||
uploads = self.launcher.image_upload_registry.getUploadsForImage(
|
||||
name)
|
||||
self.assertEqual(1, len(uploads))
|
||||
self.assertEqual(artifacts[0].uuid, uploads[0].artifact_uuid)
|
||||
self.assertIn('ami-', uploads[0].external_id)
|
||||
self.assertTrue(uploads[0].validated)
|
||||
|
||||
@simple_layout('layouts/aws/nodepool-image-snapshot.yaml',
|
||||
enable_nodepool=True)
|
||||
@return_data(
|
||||
'build-debian-local-image',
|
||||
'refs/heads/master',
|
||||
debian_return_data,
|
||||
)
|
||||
def test_aws_diskimage_snapshot(self):
|
||||
self._test_aws_diskimage_import()
|
||||
|
||||
@simple_layout('layouts/aws/nodepool-image-image.yaml',
|
||||
enable_nodepool=True)
|
||||
@return_data(
|
||||
'build-debian-local-image',
|
||||
'refs/heads/master',
|
||||
debian_return_data,
|
||||
)
|
||||
def test_aws_diskimage_image(self):
|
||||
self._test_aws_diskimage_import()
|
||||
|
||||
@simple_layout('layouts/aws/nodepool-image-ebs-direct.yaml',
|
||||
enable_nodepool=True)
|
||||
@return_data(
|
||||
'build-debian-local-image',
|
||||
'refs/heads/master',
|
||||
debian_return_data,
|
||||
)
|
||||
def test_aws_diskimage_ebs_direct(self):
|
||||
self._test_aws_diskimage_import()
|
||||
|
102
tests/unit/test_cloud_driver.py
Normal file
102
tests/unit/test_cloud_driver.py
Normal file
@ -0,0 +1,102 @@
|
||||
# Copyright 2024 Acme Gating, LLC
|
||||
#
|
||||
# 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 testtools
|
||||
from kazoo.exceptions import NoNodeError
|
||||
|
||||
from zuul import model
|
||||
from zuul.launcher.client import LauncherClient
|
||||
|
||||
from tests.base import (
|
||||
ZuulTestCase,
|
||||
iterate_timeout,
|
||||
)
|
||||
|
||||
|
||||
class BaseCloudDriverTest(ZuulTestCase):
|
||||
cloud_test_connection_type = 'ssh'
|
||||
cloud_test_image_format = ''
|
||||
|
||||
def _assertProviderNodeAttributes(self, pnode):
|
||||
self.assertEqual(pnode.connection_type,
|
||||
self.cloud_test_connection_type)
|
||||
self.assertIsNotNone(pnode.interface_ip)
|
||||
|
||||
def _test_node_lifecycle(self, label):
|
||||
# Call this in a test to run a node lifecycle
|
||||
nodeset = model.NodeSet()
|
||||
nodeset.addNode(model.Node("node", label))
|
||||
|
||||
ctx = self.createZKContext(None)
|
||||
request = self.requestNodes([n.label for n in nodeset.getNodes()])
|
||||
|
||||
client = LauncherClient(self.zk_client, None)
|
||||
request = client.getRequest(request.uuid)
|
||||
|
||||
self.assertEqual(request.state, model.NodesetRequest.State.FULFILLED)
|
||||
self.assertEqual(len(request.nodes), 1)
|
||||
|
||||
client.acceptNodeset(request, nodeset)
|
||||
self.waitUntilSettled()
|
||||
|
||||
with testtools.ExpectedException(NoNodeError):
|
||||
# Request should be gone
|
||||
request.refresh(ctx)
|
||||
|
||||
for node in nodeset.getNodes():
|
||||
pnode = node._provider_node
|
||||
self.assertIsNotNone(pnode)
|
||||
self.assertTrue(pnode.hasLock())
|
||||
self._assertProviderNodeAttributes(pnode)
|
||||
|
||||
client.useNodeset(nodeset)
|
||||
self.waitUntilSettled()
|
||||
|
||||
for node in nodeset.getNodes():
|
||||
pnode = node._provider_node
|
||||
self.assertTrue(pnode.hasLock())
|
||||
self.assertTrue(pnode.state, pnode.State.IN_USE)
|
||||
|
||||
client.returnNodeset(nodeset)
|
||||
self.waitUntilSettled()
|
||||
|
||||
for node in nodeset.getNodes():
|
||||
pnode = node._provider_node
|
||||
self.assertFalse(pnode.hasLock())
|
||||
self.assertTrue(pnode.state, pnode.State.USED)
|
||||
|
||||
for _ in iterate_timeout(60, "node to be deleted"):
|
||||
try:
|
||||
pnode.refresh(ctx)
|
||||
except NoNodeError:
|
||||
break
|
||||
|
||||
def _test_diskimage(self):
|
||||
self.waitUntilSettled()
|
||||
self.assertHistory([
|
||||
dict(name='build-debian-local-image', result='SUCCESS'),
|
||||
], ordered=False)
|
||||
|
||||
name = 'review.example.com%2Forg%2Fcommon-config/debian-local'
|
||||
artifacts = self.launcher.image_build_registry.\
|
||||
getArtifactsForImage(name)
|
||||
self.assertEqual(1, len(artifacts))
|
||||
self.assertEqual(self.cloud_test_image_format, artifacts[0].format)
|
||||
self.assertTrue(artifacts[0].validated)
|
||||
uploads = self.launcher.image_upload_registry.getUploadsForImage(
|
||||
name)
|
||||
self.assertEqual(1, len(uploads))
|
||||
self.assertEqual(artifacts[0].uuid, uploads[0].artifact_uuid)
|
||||
self.assertIsNotNone(uploads[0].external_id)
|
||||
self.assertTrue(uploads[0].validated)
|
@ -464,55 +464,6 @@ class TestLauncher(ZuulTestCase):
|
||||
request.delete(ctx)
|
||||
self.waitUntilSettled()
|
||||
|
||||
@simple_layout('layouts/nodepool.yaml', enable_nodepool=True)
|
||||
def test_node_lifecycle(self):
|
||||
nodeset = model.NodeSet()
|
||||
nodeset.addNode(model.Node("node", "debian-normal"))
|
||||
|
||||
ctx = self.createZKContext(None)
|
||||
request = self.requestNodes([n.label for n in nodeset.getNodes()])
|
||||
|
||||
client = LauncherClient(self.zk_client, None)
|
||||
request = client.getRequest(request.uuid)
|
||||
|
||||
self.assertEqual(request.state, model.NodesetRequest.State.FULFILLED)
|
||||
self.assertEqual(len(request.nodes), 1)
|
||||
|
||||
client.acceptNodeset(request, nodeset)
|
||||
self.waitUntilSettled()
|
||||
|
||||
with testtools.ExpectedException(NoNodeError):
|
||||
# Request should be gone
|
||||
request.refresh(ctx)
|
||||
|
||||
for node in nodeset.getNodes():
|
||||
pnode = node._provider_node
|
||||
self.assertIsNotNone(pnode)
|
||||
self.assertTrue(pnode.hasLock())
|
||||
|
||||
client.useNodeset(nodeset)
|
||||
self.waitUntilSettled()
|
||||
|
||||
for node in nodeset.getNodes():
|
||||
pnode = node._provider_node
|
||||
self.assertTrue(pnode.hasLock())
|
||||
self.assertTrue(pnode.state, pnode.State.IN_USE)
|
||||
self.assertEqual(pnode.connection_type, 'ssh')
|
||||
|
||||
client.returnNodeset(nodeset)
|
||||
self.waitUntilSettled()
|
||||
|
||||
for node in nodeset.getNodes():
|
||||
pnode = node._provider_node
|
||||
self.assertFalse(pnode.hasLock())
|
||||
self.assertTrue(pnode.state, pnode.State.USED)
|
||||
|
||||
for _ in iterate_timeout(60, "node to be deleted"):
|
||||
try:
|
||||
pnode.refresh(ctx)
|
||||
except NoNodeError:
|
||||
break
|
||||
|
||||
@simple_layout('layouts/nodepool.yaml', enable_nodepool=True)
|
||||
def test_lost_nodeset_request(self):
|
||||
ctx = self.createZKContext(None)
|
||||
|
@ -15,11 +15,7 @@
|
||||
import os
|
||||
|
||||
import fixtures
|
||||
import testtools
|
||||
from kazoo.exceptions import NoNodeError
|
||||
|
||||
from zuul import model
|
||||
from zuul.launcher.client import LauncherClient
|
||||
from zuul.driver.openstack import OpenstackDriver
|
||||
|
||||
from tests.fake_openstack import (
|
||||
@ -29,14 +25,15 @@ from tests.fake_openstack import (
|
||||
from tests.base import (
|
||||
FIXTURE_DIR,
|
||||
ZuulTestCase,
|
||||
iterate_timeout,
|
||||
simple_layout,
|
||||
return_data,
|
||||
)
|
||||
from tests.unit.test_launcher import ImageMocksFixture
|
||||
from tests.unit.test_cloud_driver import BaseCloudDriverTest
|
||||
|
||||
|
||||
class BaseOpenstackDriverTest(ZuulTestCase):
|
||||
cloud_test_image_format = 'qcow2'
|
||||
config_file = 'zuul-connections-nodepool.conf'
|
||||
debian_return_data = {
|
||||
'zuul': {
|
||||
@ -78,70 +75,12 @@ class BaseOpenstackDriverTest(ZuulTestCase):
|
||||
def tearDown(self):
|
||||
super().tearDown()
|
||||
|
||||
def _test_openstack_node_lifecycle(self, label):
|
||||
nodeset = model.NodeSet()
|
||||
nodeset.addNode(model.Node("node", label))
|
||||
|
||||
ctx = self.createZKContext(None)
|
||||
request = self.requestNodes([n.label for n in nodeset.getNodes()])
|
||||
|
||||
client = LauncherClient(self.zk_client, None)
|
||||
request = client.getRequest(request.uuid)
|
||||
|
||||
self.assertEqual(request.state, model.NodesetRequest.State.FULFILLED)
|
||||
self.assertEqual(len(request.nodes), 1)
|
||||
|
||||
client.acceptNodeset(request, nodeset)
|
||||
self.waitUntilSettled()
|
||||
|
||||
with testtools.ExpectedException(NoNodeError):
|
||||
# Request should be gone
|
||||
request.refresh(ctx)
|
||||
|
||||
for node in nodeset.getNodes():
|
||||
pnode = node._provider_node
|
||||
self.assertIsNotNone(pnode)
|
||||
self.assertTrue(pnode.hasLock())
|
||||
|
||||
client.useNodeset(nodeset)
|
||||
self.waitUntilSettled()
|
||||
|
||||
for node in nodeset.getNodes():
|
||||
pnode = node._provider_node
|
||||
self.assertTrue(pnode.hasLock())
|
||||
self.assertTrue(pnode.state, pnode.State.IN_USE)
|
||||
self.assertEqual(pnode.connection_type, 'ssh')
|
||||
|
||||
client.returnNodeset(nodeset)
|
||||
self.waitUntilSettled()
|
||||
|
||||
for node in nodeset.getNodes():
|
||||
pnode = node._provider_node
|
||||
self.assertFalse(pnode.hasLock())
|
||||
self.assertTrue(pnode.state, pnode.State.USED)
|
||||
|
||||
for _ in iterate_timeout(60, "node to be deleted"):
|
||||
try:
|
||||
pnode.refresh(ctx)
|
||||
except NoNodeError:
|
||||
break
|
||||
|
||||
|
||||
class TestOpenstackDriver(BaseOpenstackDriverTest):
|
||||
# TODO: make this a generic driver test
|
||||
@simple_layout('layouts/openstack/nodepool.yaml', enable_nodepool=True)
|
||||
def test_openstack_config(self):
|
||||
layout = self.scheds.first.sched.abide.tenants.get('tenant-one').layout
|
||||
provider = layout.providers['openstack-main']
|
||||
endpoint = provider.getEndpoint()
|
||||
self.assertEqual([], list(endpoint.listInstances()))
|
||||
|
||||
# TODO: make this a generic driver test
|
||||
class TestOpenstackDriver(BaseOpenstackDriverTest, BaseCloudDriverTest):
|
||||
@simple_layout('layouts/openstack/nodepool.yaml', enable_nodepool=True)
|
||||
def test_openstack_node_lifecycle(self):
|
||||
self._test_openstack_node_lifecycle('debian-normal')
|
||||
self._test_node_lifecycle('debian-normal')
|
||||
|
||||
# TODO: make this a generic driver test
|
||||
@simple_layout('layouts/openstack/nodepool-image.yaml',
|
||||
enable_nodepool=True)
|
||||
@return_data(
|
||||
@ -150,27 +89,12 @@ class TestOpenstackDriver(BaseOpenstackDriverTest):
|
||||
BaseOpenstackDriverTest.debian_return_data,
|
||||
)
|
||||
def test_openstack_diskimage(self):
|
||||
self.waitUntilSettled()
|
||||
self.assertHistory([
|
||||
dict(name='build-debian-local-image', result='SUCCESS'),
|
||||
], ordered=False)
|
||||
|
||||
name = 'review.example.com%2Forg%2Fcommon-config/debian-local'
|
||||
artifacts = self.launcher.image_build_registry.\
|
||||
getArtifactsForImage(name)
|
||||
self.assertEqual(1, len(artifacts))
|
||||
self.assertEqual('qcow2', artifacts[0].format)
|
||||
self.assertTrue(artifacts[0].validated)
|
||||
uploads = self.launcher.image_upload_registry.getUploadsForImage(
|
||||
name)
|
||||
self.assertEqual(1, len(uploads))
|
||||
self.assertEqual(artifacts[0].uuid, uploads[0].artifact_uuid)
|
||||
self.assertIsNotNone(uploads[0].external_id)
|
||||
self.assertTrue(uploads[0].validated)
|
||||
self._test_diskimage()
|
||||
|
||||
|
||||
# Openstack-driver specific tests
|
||||
class TestOpenstackDriverFloatingIp(BaseOpenstackDriverTest):
|
||||
class TestOpenstackDriverFloatingIp(BaseOpenstackDriverTest,
|
||||
BaseCloudDriverTest):
|
||||
# This test is for nova-net clouds with floating ips that require
|
||||
# manual attachment.
|
||||
openstack_needs_floating_ip = True
|
||||
@ -178,13 +102,14 @@ class TestOpenstackDriverFloatingIp(BaseOpenstackDriverTest):
|
||||
|
||||
@simple_layout('layouts/openstack/nodepool.yaml', enable_nodepool=True)
|
||||
def test_openstack_fip(self):
|
||||
self._test_openstack_node_lifecycle('debian-normal')
|
||||
self._test_node_lifecycle('debian-normal')
|
||||
|
||||
|
||||
class TestOpenstackDriverAutoAttachFloatingIp(BaseOpenstackDriverTest):
|
||||
class TestOpenstackDriverAutoAttachFloatingIp(BaseOpenstackDriverTest,
|
||||
BaseCloudDriverTest):
|
||||
openstack_needs_floating_ip = True
|
||||
openstack_auto_attach_floating_ip = True
|
||||
|
||||
@simple_layout('layouts/openstack/nodepool.yaml', enable_nodepool=True)
|
||||
def test_openstack_auto_attach_fip(self):
|
||||
self._test_openstack_node_lifecycle('debian-normal')
|
||||
self._test_node_lifecycle('debian-normal')
|
||||
|
Loading…
x
Reference in New Issue
Block a user