Add nodepool command tests

This commit does a small refactor of the base DB test class so that it
can be used by other child classes without duplicating the work in the
existing nodepool test cases. With this in place add a new test class to
test nodepool commands.

Currently only image-update is tested, but it should be easy to add
tests for the other commands that nodepool supports.

Change-Id: I6ea488a896cc456600da576af6086f95f4938bde
This commit is contained in:
Clark Boylan 2015-02-12 11:40:35 -08:00
parent 1a5ea47257
commit 74ef962fbe
4 changed files with 204 additions and 70 deletions

View File

@ -21,11 +21,16 @@ import os
import random
import string
import subprocess
import threading
import tempfile
import time
import fixtures
import testresources
import testtools
from nodepool import allocation
TRUE_VALUES = ('true', '1', 'yes')
@ -72,6 +77,31 @@ class BaseTestCase(testtools.TestCase, testresources.ResourcedTestCase):
self.useFixture(fixtures.MonkeyPatch('subprocess.Popen',
LoggingPopenFactory))
def wait_for_threads(self):
whitelist = ['APScheduler',
'MainThread',
'NodePool',
'NodeUpdateListener',
'Gearman client connect',
'Gearman client poll',
'fake-provider',
'fake-provider1',
'fake-provider2',
'fake-dib-provider',
'fake-jenkins',
'fake-target',
'DiskImageBuilder queue',
]
while True:
done = True
for t in threading.enumerate():
if t.name not in whitelist:
done = False
if done:
return
time.sleep(0.1)
class AllocatorTestCase(object):
def setUp(self):
@ -139,3 +169,42 @@ class DBTestCase(BaseTestCase):
f = MySQLSchemaFixture()
self.useFixture(f)
self.dburi = f.dburi
def setup_config(self, filename):
configfile = os.path.join(os.path.dirname(__file__),
'fixtures', filename)
config = open(configfile).read()
(fd, path) = tempfile.mkstemp()
os.write(fd, config.format(dburi=self.dburi))
os.close(fd)
return path
def wait_for_config(self, pool):
for x in range(300):
if pool.config is not None:
return
time.sleep(0.1)
def waitForImage(self, pool, provider_name, image_name):
self.wait_for_config(pool)
while True:
self.wait_for_threads()
with pool.getDB().getSession() as session:
image = session.getCurrentSnapshotImage(provider_name,
image_name)
if image:
break
time.sleep(1)
self.wait_for_threads()
def waitForNodes(self, pool):
self.wait_for_config(pool)
allocation_history = allocation.AllocationHistory()
while True:
self.wait_for_threads()
with pool.getDB().getSession() as session:
needed = pool.getNeededNodes(session, allocation_history)
if not needed:
break
time.sleep(1)
self.wait_for_threads()

74
nodepool/tests/fixtures/node_cmd.yaml vendored Normal file
View File

@ -0,0 +1,74 @@
script-dir: .
dburi: '{dburi}'
cron:
check: '*/15 * * * *'
cleanup: '*/1 * * * *'
image-update: '14 2 * * *'
zmq-publishers:
- tcp://localhost:8881
#gearman-servers:
# - host: localhost
labels:
- name: fake-label1
image: fake-image1
min-ready: 1
providers:
- name: fake-provider1
- name: fake-label2
image: fake-image2
min-ready: 1
providers:
- name: fake-provider2
providers:
- name: fake-provider1
keypair: 'if-present-use-this-keypair'
username: 'fake'
password: 'fake'
auth-url: 'fake'
project-id: 'fake'
max-servers: 96
pool: 'fake'
networks:
- net-id: 'some-uuid'
rate: 0.0001
images:
- name: fake-image1
base-image: 'Fake Precise'
min-ram: 8192
name-filter: 'Fake'
meta:
key: value
key2: value
setup: prepare_node_devstack.sh
- name: fake-provider2
keypair: 'if-present-use-this-keypair'
username: 'fake'
password: 'fake'
auth-url: 'fake'
project-id: 'fake'
max-servers: 96
pool: 'fake'
networks:
- net-id: 'some-uuid'
rate: 0.0001
images:
- name: fake-image2
base-image: 'Fake Precise'
min-ram: 8192
name-filter: 'Fake'
meta:
key: value
key2: value
setup: prepare_node_devstack.sh
targets:
- name: fake-target
jenkins:
url: https://jenkins.example.org/
user: fake
apikey: fake

View File

@ -0,0 +1,61 @@
# Copyright (C) 2015 OpenStack Foundation
#
# 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 sys # noqa making sure its available for monkey patching
import fixtures
from nodepool.cmd import nodepoolcmd
from nodepool import tests
class TestNodepoolCMD(tests.DBTestCase):
def patch_argv(self, *args):
argv = ["nodepool"]
argv.extend(args)
self.useFixture(fixtures.MonkeyPatch('sys.argv', argv))
def test_snapshot_image_update(self):
configfile = self.setup_config("node.yaml")
self.patch_argv("-c", configfile, "image-update",
"fake-provider", "fake-image")
nodepoolcmd.main()
def test_dib_image_update(self):
configfile = self.setup_config("node_dib.yaml")
self.patch_argv("-c", configfile, "image-update",
"fake-dib-provider", "fake-dib-image")
nodepoolcmd.main()
def test_dib_snapshot_image_update(self):
configfile = self.setup_config("node_dib_and_snap.yaml")
self.patch_argv("-c", configfile, "image-update",
"fake-provider1", "fake-dib-image")
nodepoolcmd.main()
self.patch_argv("-c", configfile, "image-update",
"fake-provider2", "fake-dib-image")
nodepoolcmd.main()
def test_dib_snapshot_image_update_all(self):
configfile = self.setup_config("node_dib_and_snap.yaml")
self.patch_argv("-c", configfile, "image-update",
"all", "fake-dib-image")
nodepoolcmd.main()
def test_image_update_all(self):
configfile = self.setup_config("node_cmd.yaml")
self.patch_argv("-c", configfile, "image-update",
"all", "fake-image1")
nodepoolcmd.main()

View File

@ -13,87 +13,17 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import os
import tempfile
import threading
import time
from nodepool import allocation
from nodepool import tests
from nodepool import nodedb
import nodepool.nodepool
class TestNodepool(tests.DBTestCase):
def setup_config(self, filename):
configfile = os.path.join(os.path.dirname(tests.__file__),
'fixtures', filename)
config = open(configfile).read()
(fd, path) = tempfile.mkstemp()
os.write(fd, config.format(dburi=self.dburi))
os.close(fd)
return path
def wait_for_threads(self):
whitelist = ['APScheduler',
'MainThread',
'NodePool',
'NodeUpdateListener',
'Gearman client connect',
'Gearman client poll',
'fake-provider',
'fake-provider1',
'fake-provider2',
'fake-dib-provider',
'fake-jenkins',
'fake-target',
'DiskImageBuilder queue'
]
while True:
done = True
for t in threading.enumerate():
if t.name not in whitelist:
done = False
if done:
return
time.sleep(0.1)
def wait_for_config(self, pool):
for x in range(300):
if pool.config is not None:
return
time.sleep(0.1)
def test_db(self):
db = nodedb.NodeDatabase(self.dburi)
with db.getSession() as session:
session.getNodes()
def waitForImage(self, pool, provider_name, image_name):
self.wait_for_config(pool)
while True:
self.wait_for_threads()
with pool.getDB().getSession() as session:
image = session.getCurrentSnapshotImage(provider_name,
image_name)
if image:
break
time.sleep(1)
self.wait_for_threads()
def waitForNodes(self, pool):
self.wait_for_config(pool)
allocation_history = allocation.AllocationHistory()
while True:
self.wait_for_threads()
with pool.getDB().getSession() as session:
needed = pool.getNeededNodes(session, allocation_history)
if not needed:
break
time.sleep(1)
self.wait_for_threads()
def test_node(self):
"""Test that an image and node are created"""
configfile = self.setup_config('node.yaml')