Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-app / synnefo / tools / burnin.py @ 9e4682b5

History | View | Annotate | Download (39 kB)

1 9e4682b5 John Giannelos
 #!/usr/bin/env python
2 5a140b23 Vangelis Koukis
3 5a140b23 Vangelis Koukis
# Copyright 2011 GRNET S.A. All rights reserved.
4 5a140b23 Vangelis Koukis
#
5 5a140b23 Vangelis Koukis
# Redistribution and use in source and binary forms, with or
6 5a140b23 Vangelis Koukis
# without modification, are permitted provided that the following
7 5a140b23 Vangelis Koukis
# conditions are met:
8 5a140b23 Vangelis Koukis
#
9 5a140b23 Vangelis Koukis
#   1. Redistributions of source code must retain the above
10 5a140b23 Vangelis Koukis
#      copyright notice, this list of conditions and the following
11 5a140b23 Vangelis Koukis
#      disclaimer.
12 5a140b23 Vangelis Koukis
#
13 5a140b23 Vangelis Koukis
#   2. Redistributions in binary form must reproduce the above
14 5a140b23 Vangelis Koukis
#      copyright notice, this list of conditions and the following
15 5a140b23 Vangelis Koukis
#      disclaimer in the documentation and/or other materials
16 5a140b23 Vangelis Koukis
#      provided with the distribution.
17 5a140b23 Vangelis Koukis
#
18 5a140b23 Vangelis Koukis
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
19 5a140b23 Vangelis Koukis
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 5a140b23 Vangelis Koukis
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 5a140b23 Vangelis Koukis
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
22 5a140b23 Vangelis Koukis
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 5a140b23 Vangelis Koukis
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 5a140b23 Vangelis Koukis
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
25 5a140b23 Vangelis Koukis
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26 5a140b23 Vangelis Koukis
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 5a140b23 Vangelis Koukis
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
28 5a140b23 Vangelis Koukis
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 5a140b23 Vangelis Koukis
# POSSIBILITY OF SUCH DAMAGE.
30 5a140b23 Vangelis Koukis
#
31 5a140b23 Vangelis Koukis
# The views and conclusions contained in the software and
32 5a140b23 Vangelis Koukis
# documentation are those of the authors and should not be
33 5a140b23 Vangelis Koukis
# interpreted as representing official policies, either expressed
34 5a140b23 Vangelis Koukis
# or implied, of GRNET S.A.
35 5a140b23 Vangelis Koukis
36 5a140b23 Vangelis Koukis
"""Perform integration testing on a running Synnefo deployment"""
37 5a140b23 Vangelis Koukis
38 21bbbc9b Vangelis Koukis
import __main__
39 5a140b23 Vangelis Koukis
import datetime
40 5a140b23 Vangelis Koukis
import inspect
41 5a140b23 Vangelis Koukis
import logging
42 5a140b23 Vangelis Koukis
import os
43 5a140b23 Vangelis Koukis
import paramiko
44 21bbbc9b Vangelis Koukis
import prctl
45 5a140b23 Vangelis Koukis
import subprocess
46 21bbbc9b Vangelis Koukis
import signal
47 5a140b23 Vangelis Koukis
import socket
48 bc14ba88 Vangelis Koukis
import struct
49 5a140b23 Vangelis Koukis
import sys
50 5a140b23 Vangelis Koukis
import time
51 5a140b23 Vangelis Koukis
52 5a140b23 Vangelis Koukis
from IPy import IP
53 21bbbc9b Vangelis Koukis
from multiprocessing import Process, Queue
54 bc14ba88 Vangelis Koukis
from random import choice
55 21bbbc9b Vangelis Koukis
56 1c636ad6 John Giannelos
from kamaki.clients import ClientError, ComputeClient, CycladesClient
57 1c636ad6 John Giannelos
from kamaki.config import Config
58 1c636ad6 John Giannelos
59 bc14ba88 Vangelis Koukis
from vncauthproxy.d3des import generate_response as d3des_generate_response
60 5a140b23 Vangelis Koukis
61 5a140b23 Vangelis Koukis
# Use backported unittest functionality if Python < 2.7
62 5a140b23 Vangelis Koukis
try:
63 5a140b23 Vangelis Koukis
    import unittest2 as unittest
64 5a140b23 Vangelis Koukis
except ImportError:
65 bc14ba88 Vangelis Koukis
    if sys.version_info < (2, 7):
66 bc14ba88 Vangelis Koukis
        raise Exception("The unittest2 package is required for Python < 2.7")
67 5a140b23 Vangelis Koukis
    import unittest
68 5a140b23 Vangelis Koukis
69 5a140b23 Vangelis Koukis
70 21bbbc9b Vangelis Koukis
API = None
71 21bbbc9b Vangelis Koukis
TOKEN = None
72 38d247df Kostas Papadimitriou
DEFAULT_API = "http://127.0.0.1:8000/api/v1.1"
73 38d247df Kostas Papadimitriou
74 5a140b23 Vangelis Koukis
# A unique id identifying this test run
75 21bbbc9b Vangelis Koukis
TEST_RUN_ID = datetime.datetime.strftime(datetime.datetime.now(),
76 21bbbc9b Vangelis Koukis
                                         "%Y%m%d%H%M%S")
77 21bbbc9b Vangelis Koukis
SNF_TEST_PREFIX = "snf-test-"
78 5a140b23 Vangelis Koukis
79 5a140b23 Vangelis Koukis
# Setup logging (FIXME - verigak)
80 5a140b23 Vangelis Koukis
logging.basicConfig(format="%(message)s")
81 00f87624 Vangelis Koukis
log = logging.getLogger("burnin")
82 5a140b23 Vangelis Koukis
log.setLevel(logging.INFO)
83 5a140b23 Vangelis Koukis
84 5a140b23 Vangelis Koukis
class UnauthorizedTestCase(unittest.TestCase):
85 5a140b23 Vangelis Koukis
    def test_unauthorized_access(self):
86 5a140b23 Vangelis Koukis
        """Test access without a valid token fails"""
87 1c636ad6 John Giannelos
        falseToken = '12345'
88 1c636ad6 John Giannelos
        conf = Config()
89 1c636ad6 John Giannelos
        conf.set('compute_token', falseToken)
90 99d41650 John Giannelos
        c=ComputeClient(conf)
91 1c636ad6 John Giannelos
92 5a140b23 Vangelis Koukis
        with self.assertRaises(ClientError) as cm:
93 5a140b23 Vangelis Koukis
            c.list_servers()
94 5a140b23 Vangelis Koukis
        self.assertEqual(cm.exception.status, 401)
95 5a140b23 Vangelis Koukis
96 5a140b23 Vangelis Koukis
97 5a140b23 Vangelis Koukis
class ImagesTestCase(unittest.TestCase):
98 5a140b23 Vangelis Koukis
    """Test image lists for consistency"""
99 5a140b23 Vangelis Koukis
    @classmethod
100 5a140b23 Vangelis Koukis
    def setUpClass(cls):
101 5a140b23 Vangelis Koukis
        """Initialize kamaki, get (detailed) list of images"""
102 5a140b23 Vangelis Koukis
        log.info("Getting simple and detailed list of images")
103 1c636ad6 John Giannelos
104 1c636ad6 John Giannelos
        conf = Config()
105 1c636ad6 John Giannelos
        conf.set('compute_token', TOKEN)
106 1c636ad6 John Giannelos
        cls.client = ComputeClient(conf)
107 5a140b23 Vangelis Koukis
        cls.images = cls.client.list_images()
108 5a140b23 Vangelis Koukis
        cls.dimages = cls.client.list_images(detail=True)
109 5a140b23 Vangelis Koukis
110 5a140b23 Vangelis Koukis
    def test_001_list_images(self):
111 5a140b23 Vangelis Koukis
        """Test image list actually returns images"""
112 5a140b23 Vangelis Koukis
        self.assertGreater(len(self.images), 0)
113 5a140b23 Vangelis Koukis
114 5a140b23 Vangelis Koukis
    def test_002_list_images_detailed(self):
115 5a140b23 Vangelis Koukis
        """Test detailed image list is the same length as list"""
116 5a140b23 Vangelis Koukis
        self.assertEqual(len(self.dimages), len(self.images))
117 5a140b23 Vangelis Koukis
118 5a140b23 Vangelis Koukis
    def test_003_same_image_names(self):
119 5a140b23 Vangelis Koukis
        """Test detailed and simple image list contain same names"""
120 5a140b23 Vangelis Koukis
        names = sorted(map(lambda x: x["name"], self.images))
121 5a140b23 Vangelis Koukis
        dnames = sorted(map(lambda x: x["name"], self.dimages))
122 5a140b23 Vangelis Koukis
        self.assertEqual(names, dnames)
123 5a140b23 Vangelis Koukis
124 5a140b23 Vangelis Koukis
    def test_004_unique_image_names(self):
125 5a140b23 Vangelis Koukis
        """Test images have unique names"""
126 5a140b23 Vangelis Koukis
        names = sorted(map(lambda x: x["name"], self.images))
127 5a140b23 Vangelis Koukis
        self.assertEqual(sorted(list(set(names))), names)
128 5a140b23 Vangelis Koukis
129 5a140b23 Vangelis Koukis
    def test_005_image_metadata(self):
130 5a140b23 Vangelis Koukis
        """Test every image has specific metadata defined"""
131 1c636ad6 John Giannelos
        keys = frozenset(["os", "description", "size"])
132 5a140b23 Vangelis Koukis
        for i in self.dimages:
133 5a140b23 Vangelis Koukis
            self.assertTrue(keys.issubset(i["metadata"]["values"].keys()))
134 5a140b23 Vangelis Koukis
135 5a140b23 Vangelis Koukis
136 5a140b23 Vangelis Koukis
class FlavorsTestCase(unittest.TestCase):
137 5a140b23 Vangelis Koukis
    """Test flavor lists for consistency"""
138 5a140b23 Vangelis Koukis
    @classmethod
139 5a140b23 Vangelis Koukis
    def setUpClass(cls):
140 5a140b23 Vangelis Koukis
        """Initialize kamaki, get (detailed) list of flavors"""
141 5a140b23 Vangelis Koukis
        log.info("Getting simple and detailed list of flavors")
142 1c636ad6 John Giannelos
143 1c636ad6 John Giannelos
        conf = Config()
144 1c636ad6 John Giannelos
        conf.set('compute_token', TOKEN)
145 1c636ad6 John Giannelos
        cls.client = ComputeClient(conf)
146 5a140b23 Vangelis Koukis
        cls.flavors = cls.client.list_flavors()
147 5a140b23 Vangelis Koukis
        cls.dflavors = cls.client.list_flavors(detail=True)
148 5a140b23 Vangelis Koukis
149 5a140b23 Vangelis Koukis
    def test_001_list_flavors(self):
150 5a140b23 Vangelis Koukis
        """Test flavor list actually returns flavors"""
151 5a140b23 Vangelis Koukis
        self.assertGreater(len(self.flavors), 0)
152 5a140b23 Vangelis Koukis
153 5a140b23 Vangelis Koukis
    def test_002_list_flavors_detailed(self):
154 5a140b23 Vangelis Koukis
        """Test detailed flavor list is the same length as list"""
155 5a140b23 Vangelis Koukis
        self.assertEquals(len(self.dflavors), len(self.flavors))
156 5a140b23 Vangelis Koukis
157 5a140b23 Vangelis Koukis
    def test_003_same_flavor_names(self):
158 5a140b23 Vangelis Koukis
        """Test detailed and simple flavor list contain same names"""
159 5a140b23 Vangelis Koukis
        names = sorted(map(lambda x: x["name"], self.flavors))
160 5a140b23 Vangelis Koukis
        dnames = sorted(map(lambda x: x["name"], self.dflavors))
161 5a140b23 Vangelis Koukis
        self.assertEqual(names, dnames)
162 5a140b23 Vangelis Koukis
163 5a140b23 Vangelis Koukis
    def test_004_unique_flavor_names(self):
164 5a140b23 Vangelis Koukis
        """Test flavors have unique names"""
165 5a140b23 Vangelis Koukis
        names = sorted(map(lambda x: x["name"], self.flavors))
166 5a140b23 Vangelis Koukis
        self.assertEqual(sorted(list(set(names))), names)
167 5a140b23 Vangelis Koukis
168 5a140b23 Vangelis Koukis
    def test_005_well_formed_flavor_names(self):
169 5a140b23 Vangelis Koukis
        """Test flavors have names of the form CxxRyyDzz
170 5a140b23 Vangelis Koukis

171 5a140b23 Vangelis Koukis
        Where xx is vCPU count, yy is RAM in MiB, zz is Disk in GiB
172 5a140b23 Vangelis Koukis

173 5a140b23 Vangelis Koukis
        """
174 5a140b23 Vangelis Koukis
        for f in self.dflavors:
175 5a140b23 Vangelis Koukis
            self.assertEqual("C%dR%dD%d" % (f["cpu"], f["ram"], f["disk"]),
176 5a140b23 Vangelis Koukis
                             f["name"],
177 5a140b23 Vangelis Koukis
                             "Flavor %s does not match its specs." % f["name"])
178 5a140b23 Vangelis Koukis
179 5a140b23 Vangelis Koukis
180 5a140b23 Vangelis Koukis
class ServersTestCase(unittest.TestCase):
181 5a140b23 Vangelis Koukis
    """Test server lists for consistency"""
182 5a140b23 Vangelis Koukis
    @classmethod
183 5a140b23 Vangelis Koukis
    def setUpClass(cls):
184 5a140b23 Vangelis Koukis
        """Initialize kamaki, get (detailed) list of servers"""
185 5a140b23 Vangelis Koukis
        log.info("Getting simple and detailed list of servers")
186 1c636ad6 John Giannelos
187 1c636ad6 John Giannelos
        conf = Config()
188 1c636ad6 John Giannelos
        conf.set('compute_token', TOKEN)
189 1c636ad6 John Giannelos
        cls.client = ComputeClient(conf)
190 5a140b23 Vangelis Koukis
        cls.servers = cls.client.list_servers()
191 5a140b23 Vangelis Koukis
        cls.dservers = cls.client.list_servers(detail=True)
192 5a140b23 Vangelis Koukis
193 5a140b23 Vangelis Koukis
    def test_001_list_servers(self):
194 5a140b23 Vangelis Koukis
        """Test server list actually returns servers"""
195 5a140b23 Vangelis Koukis
        self.assertGreater(len(self.servers), 0)
196 5a140b23 Vangelis Koukis
197 5a140b23 Vangelis Koukis
    def test_002_list_servers_detailed(self):
198 5a140b23 Vangelis Koukis
        """Test detailed server list is the same length as list"""
199 5a140b23 Vangelis Koukis
        self.assertEqual(len(self.dservers), len(self.servers))
200 5a140b23 Vangelis Koukis
201 5a140b23 Vangelis Koukis
    def test_003_same_server_names(self):
202 5a140b23 Vangelis Koukis
        """Test detailed and simple flavor list contain same names"""
203 5a140b23 Vangelis Koukis
        names = sorted(map(lambda x: x["name"], self.servers))
204 5a140b23 Vangelis Koukis
        dnames = sorted(map(lambda x: x["name"], self.dservers))
205 5a140b23 Vangelis Koukis
        self.assertEqual(names, dnames)
206 5a140b23 Vangelis Koukis
207 5a140b23 Vangelis Koukis
208 5a140b23 Vangelis Koukis
# This class gets replicated into actual TestCases dynamically
209 5a140b23 Vangelis Koukis
class SpawnServerTestCase(unittest.TestCase):
210 5a140b23 Vangelis Koukis
    """Test scenario for server of the specified image"""
211 5a140b23 Vangelis Koukis
212 5a140b23 Vangelis Koukis
    @classmethod
213 5a140b23 Vangelis Koukis
    def setUpClass(cls):
214 5a140b23 Vangelis Koukis
        """Initialize a kamaki instance"""
215 bc14ba88 Vangelis Koukis
        log.info("Spawning server for image `%s'", cls.imagename)
216 1c636ad6 John Giannelos
217 1c636ad6 John Giannelos
        conf = Config()
218 1c636ad6 John Giannelos
        conf.set('compute_token', TOKEN)
219 1c636ad6 John Giannelos
        cls.client = ComputeClient(conf)
220 74193008 John Giannelos
        cls.cyclades = CycladesClient(conf)
221 5a140b23 Vangelis Koukis
222 5a140b23 Vangelis Koukis
    def _get_ipv4(self, server):
223 bc14ba88 Vangelis Koukis
        """Get the public IPv4 of a server from the detailed server info"""
224 1c636ad6 John Giannelos
225 5a140b23 Vangelis Koukis
        public_addrs = filter(lambda x: x["id"] == "public",
226 5a140b23 Vangelis Koukis
                              server["addresses"]["values"])
227 5a140b23 Vangelis Koukis
        self.assertEqual(len(public_addrs), 1)
228 5a140b23 Vangelis Koukis
        ipv4_addrs = filter(lambda x: x["version"] == 4,
229 5a140b23 Vangelis Koukis
                            public_addrs[0]["values"])
230 5a140b23 Vangelis Koukis
        self.assertEqual(len(ipv4_addrs), 1)
231 5a140b23 Vangelis Koukis
        return ipv4_addrs[0]["addr"]
232 5a140b23 Vangelis Koukis
233 5a140b23 Vangelis Koukis
    def _get_ipv6(self, server):
234 bc14ba88 Vangelis Koukis
        """Get the public IPv6 of a server from the detailed server info"""
235 5a140b23 Vangelis Koukis
        public_addrs = filter(lambda x: x["id"] == "public",
236 5a140b23 Vangelis Koukis
                              server["addresses"]["values"])
237 5a140b23 Vangelis Koukis
        self.assertEqual(len(public_addrs), 1)
238 5a140b23 Vangelis Koukis
        ipv6_addrs = filter(lambda x: x["version"] == 6,
239 5a140b23 Vangelis Koukis
                            public_addrs[0]["values"])
240 5a140b23 Vangelis Koukis
        self.assertEqual(len(ipv6_addrs), 1)
241 5a140b23 Vangelis Koukis
        return ipv6_addrs[0]["addr"]
242 5a140b23 Vangelis Koukis
243 bc14ba88 Vangelis Koukis
    def _connect_loginname(self, os):
244 bc14ba88 Vangelis Koukis
        """Return the login name for connections based on the server OS"""
245 1c636ad6 John Giannelos
        if os in ("Ubuntu", "Kubuntu", "Fedora"):
246 21bbbc9b Vangelis Koukis
            return "user"
247 1c636ad6 John Giannelos
        elif os in ("windows", "windows_alpha1"):
248 21bbbc9b Vangelis Koukis
            return "Administrator"
249 bc14ba88 Vangelis Koukis
        else:
250 21bbbc9b Vangelis Koukis
            return "root"
251 bc14ba88 Vangelis Koukis
252 bc14ba88 Vangelis Koukis
    def _verify_server_status(self, current_status, new_status):
253 bc14ba88 Vangelis Koukis
        """Verify a server has switched to a specified status"""
254 bc14ba88 Vangelis Koukis
        server = self.client.get_server_details(self.serverid)
255 21bbbc9b Vangelis Koukis
        if server["status"] not in (current_status, new_status):
256 21bbbc9b Vangelis Koukis
            return None  # Do not raise exception, return so the test fails
257 bc14ba88 Vangelis Koukis
        self.assertEquals(server["status"], new_status)
258 bc14ba88 Vangelis Koukis
259 bc14ba88 Vangelis Koukis
    def _get_connected_tcp_socket(self, family, host, port):
260 bc14ba88 Vangelis Koukis
        """Get a connected socket from the specified family to host:port"""
261 bc14ba88 Vangelis Koukis
        sock = None
262 bc14ba88 Vangelis Koukis
        for res in \
263 bc14ba88 Vangelis Koukis
            socket.getaddrinfo(host, port, family, socket.SOCK_STREAM, 0,
264 bc14ba88 Vangelis Koukis
                               socket.AI_PASSIVE):
265 bc14ba88 Vangelis Koukis
            af, socktype, proto, canonname, sa = res
266 bc14ba88 Vangelis Koukis
            try:
267 bc14ba88 Vangelis Koukis
                sock = socket.socket(af, socktype, proto)
268 bc14ba88 Vangelis Koukis
            except socket.error as msg:
269 bc14ba88 Vangelis Koukis
                sock = None
270 bc14ba88 Vangelis Koukis
                continue
271 bc14ba88 Vangelis Koukis
            try:
272 bc14ba88 Vangelis Koukis
                sock.connect(sa)
273 bc14ba88 Vangelis Koukis
            except socket.error as msg:
274 bc14ba88 Vangelis Koukis
                sock.close()
275 bc14ba88 Vangelis Koukis
                sock = None
276 bc14ba88 Vangelis Koukis
                continue
277 bc14ba88 Vangelis Koukis
        self.assertIsNotNone(sock)
278 bc14ba88 Vangelis Koukis
        return sock
279 bc14ba88 Vangelis Koukis
280 bc14ba88 Vangelis Koukis
    def _ping_once(self, ipv6, ip):
281 bc14ba88 Vangelis Koukis
        """Test server responds to a single IPv4 or IPv6 ping"""
282 bc14ba88 Vangelis Koukis
        cmd = "ping%s -c 2 -w 3 %s" % ("6" if ipv6 else "", ip)
283 bc14ba88 Vangelis Koukis
        ping = subprocess.Popen(cmd, shell=True,
284 bc14ba88 Vangelis Koukis
                                stdout=subprocess.PIPE, stderr=subprocess.PIPE)
285 bc14ba88 Vangelis Koukis
        (stdout, stderr) = ping.communicate()
286 bc14ba88 Vangelis Koukis
        ret = ping.wait()
287 bc14ba88 Vangelis Koukis
        self.assertEquals(ret, 0)
288 5a140b23 Vangelis Koukis
289 bc14ba88 Vangelis Koukis
    def _get_hostname_over_ssh(self, hostip, username, password):
290 bc14ba88 Vangelis Koukis
        ssh = paramiko.SSHClient()
291 bc14ba88 Vangelis Koukis
        ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
292 bc14ba88 Vangelis Koukis
        try:
293 bc14ba88 Vangelis Koukis
            ssh.connect(hostip, username=username, password=password)
294 bc14ba88 Vangelis Koukis
        except socket.error:
295 bc14ba88 Vangelis Koukis
            raise AssertionError
296 bc14ba88 Vangelis Koukis
        stdin, stdout, stderr = ssh.exec_command("hostname")
297 bc14ba88 Vangelis Koukis
        lines = stdout.readlines()
298 bc14ba88 Vangelis Koukis
        self.assertEqual(len(lines), 1)
299 4fdd25ab Vangelis Koukis
        return lines[0]
300 bc14ba88 Vangelis Koukis
301 bc14ba88 Vangelis Koukis
    def _try_until_timeout_expires(self, warn_timeout, fail_timeout,
302 bc14ba88 Vangelis Koukis
                                   opmsg, callable, *args, **kwargs):
303 bc14ba88 Vangelis Koukis
        if warn_timeout == fail_timeout:
304 5a140b23 Vangelis Koukis
            warn_timeout = fail_timeout + 1
305 5a140b23 Vangelis Koukis
        warn_tmout = time.time() + warn_timeout
306 5a140b23 Vangelis Koukis
        fail_tmout = time.time() + fail_timeout
307 5a140b23 Vangelis Koukis
        while True:
308 4fdd25ab Vangelis Koukis
            self.assertLess(time.time(), fail_tmout,
309 21bbbc9b Vangelis Koukis
                            "operation `%s' timed out" % opmsg)
310 5a140b23 Vangelis Koukis
            if time.time() > warn_tmout:
311 4fdd25ab Vangelis Koukis
                log.warning("Server %d: `%s' operation `%s' not done yet",
312 4fdd25ab Vangelis Koukis
                            self.serverid, self.servername, opmsg)
313 bc14ba88 Vangelis Koukis
            try:
314 4fdd25ab Vangelis Koukis
                log.info("%s... " % opmsg)
315 bc14ba88 Vangelis Koukis
                return callable(*args, **kwargs)
316 bc14ba88 Vangelis Koukis
            except AssertionError:
317 bc14ba88 Vangelis Koukis
                pass
318 5a140b23 Vangelis Koukis
            time.sleep(self.query_interval)
319 5a140b23 Vangelis Koukis
320 bc14ba88 Vangelis Koukis
    def _insist_on_tcp_connection(self, family, host, port):
321 21bbbc9b Vangelis Koukis
        familystr = {socket.AF_INET: "IPv4", socket.AF_INET6: "IPv6",
322 21bbbc9b Vangelis Koukis
                     socket.AF_UNSPEC: "Unspecified-IPv4/6"}
323 bc14ba88 Vangelis Koukis
        msg = "connect over %s to %s:%s" % \
324 bc14ba88 Vangelis Koukis
              (familystr.get(family, "Unknown"), host, port)
325 bc14ba88 Vangelis Koukis
        sock = self._try_until_timeout_expires(
326 bc14ba88 Vangelis Koukis
                self.action_timeout, self.action_timeout,
327 bc14ba88 Vangelis Koukis
                msg, self._get_connected_tcp_socket,
328 bc14ba88 Vangelis Koukis
                family, host, port)
329 bc14ba88 Vangelis Koukis
        return sock
330 bc14ba88 Vangelis Koukis
331 bc14ba88 Vangelis Koukis
    def _insist_on_status_transition(self, current_status, new_status,
332 bc14ba88 Vangelis Koukis
                                    fail_timeout, warn_timeout=None):
333 4fdd25ab Vangelis Koukis
        msg = "Server %d: `%s', waiting for %s -> %s" % \
334 4fdd25ab Vangelis Koukis
              (self.serverid, self.servername, current_status, new_status)
335 bc14ba88 Vangelis Koukis
        if warn_timeout is None:
336 bc14ba88 Vangelis Koukis
            warn_timeout = fail_timeout
337 bc14ba88 Vangelis Koukis
        self._try_until_timeout_expires(warn_timeout, fail_timeout,
338 bc14ba88 Vangelis Koukis
                                        msg, self._verify_server_status,
339 bc14ba88 Vangelis Koukis
                                        current_status, new_status)
340 21bbbc9b Vangelis Koukis
        # Ensure the status is actually the expected one
341 21bbbc9b Vangelis Koukis
        server = self.client.get_server_details(self.serverid)
342 21bbbc9b Vangelis Koukis
        self.assertEquals(server["status"], new_status)
343 bc14ba88 Vangelis Koukis
344 bc14ba88 Vangelis Koukis
    def _insist_on_ssh_hostname(self, hostip, username, password):
345 4fdd25ab Vangelis Koukis
        msg = "SSH to %s, as %s/%s" % (hostip, username, password)
346 bc14ba88 Vangelis Koukis
        hostname = self._try_until_timeout_expires(
347 bc14ba88 Vangelis Koukis
                self.action_timeout, self.action_timeout,
348 bc14ba88 Vangelis Koukis
                msg, self._get_hostname_over_ssh,
349 bc14ba88 Vangelis Koukis
                hostip, username, password)
350 bc14ba88 Vangelis Koukis
351 bc14ba88 Vangelis Koukis
        # The hostname must be of the form 'prefix-id'
352 bc14ba88 Vangelis Koukis
        self.assertTrue(hostname.endswith("-%d\n" % self.serverid))
353 5a140b23 Vangelis Koukis
354 5a140b23 Vangelis Koukis
    def _skipIf(self, condition, msg):
355 5a140b23 Vangelis Koukis
        if condition:
356 5a140b23 Vangelis Koukis
            self.skipTest(msg)
357 5a140b23 Vangelis Koukis
358 5a140b23 Vangelis Koukis
    def test_001_submit_create_server(self):
359 5a140b23 Vangelis Koukis
        """Test submit create server request"""
360 5a140b23 Vangelis Koukis
        server = self.client.create_server(self.servername, self.flavorid,
361 5a140b23 Vangelis Koukis
                                           self.imageid, self.personality)
362 5a140b23 Vangelis Koukis
        self.assertEqual(server["name"], self.servername)
363 5a140b23 Vangelis Koukis
        self.assertEqual(server["flavorRef"], self.flavorid)
364 5a140b23 Vangelis Koukis
        self.assertEqual(server["imageRef"], self.imageid)
365 5a140b23 Vangelis Koukis
        self.assertEqual(server["status"], "BUILD")
366 5a140b23 Vangelis Koukis
367 5a140b23 Vangelis Koukis
        # Update class attributes to reflect data on building server
368 5a140b23 Vangelis Koukis
        cls = type(self)
369 5a140b23 Vangelis Koukis
        cls.serverid = server["id"]
370 bc14ba88 Vangelis Koukis
        cls.username = None
371 5a140b23 Vangelis Koukis
        cls.passwd = server["adminPass"]
372 5a140b23 Vangelis Koukis
373 5a140b23 Vangelis Koukis
    def test_002a_server_is_building_in_list(self):
374 5a140b23 Vangelis Koukis
        """Test server is in BUILD state, in server list"""
375 5a140b23 Vangelis Koukis
        servers = self.client.list_servers(detail=True)
376 5a140b23 Vangelis Koukis
        servers = filter(lambda x: x["name"] == self.servername, servers)
377 5a140b23 Vangelis Koukis
        self.assertEqual(len(servers), 1)
378 5a140b23 Vangelis Koukis
        server = servers[0]
379 5a140b23 Vangelis Koukis
        self.assertEqual(server["name"], self.servername)
380 5a140b23 Vangelis Koukis
        self.assertEqual(server["flavorRef"], self.flavorid)
381 5a140b23 Vangelis Koukis
        self.assertEqual(server["imageRef"], self.imageid)
382 5a140b23 Vangelis Koukis
        self.assertEqual(server["status"], "BUILD")
383 5a140b23 Vangelis Koukis
384 5a140b23 Vangelis Koukis
    def test_002b_server_is_building_in_details(self):
385 5a140b23 Vangelis Koukis
        """Test server is in BUILD state, in details"""
386 5a140b23 Vangelis Koukis
        server = self.client.get_server_details(self.serverid)
387 5a140b23 Vangelis Koukis
        self.assertEqual(server["name"], self.servername)
388 5a140b23 Vangelis Koukis
        self.assertEqual(server["flavorRef"], self.flavorid)
389 5a140b23 Vangelis Koukis
        self.assertEqual(server["imageRef"], self.imageid)
390 5a140b23 Vangelis Koukis
        self.assertEqual(server["status"], "BUILD")
391 5a140b23 Vangelis Koukis
392 5a140b23 Vangelis Koukis
    def test_002c_set_server_metadata(self):
393 5a140b23 Vangelis Koukis
        image = self.client.get_image_details(self.imageid)
394 74193008 John Giannelos
        os = image["metadata"]["values"]["os"]
395 74193008 John Giannelos
        loginname = image["metadata"]["values"].get("users", None)
396 c1d11f96 John Giannelos
        self.client.update_server_metadata(self.serverid, OS=os)
397 bc14ba88 Vangelis Koukis
398 bc14ba88 Vangelis Koukis
        # Determine the username to use for future connections
399 bc14ba88 Vangelis Koukis
        # to this host
400 bc14ba88 Vangelis Koukis
        cls = type(self)
401 bc14ba88 Vangelis Koukis
        cls.username = loginname
402 bc14ba88 Vangelis Koukis
        if not cls.username:
403 bc14ba88 Vangelis Koukis
            cls.username = self._connect_loginname(os)
404 bc14ba88 Vangelis Koukis
        self.assertIsNotNone(cls.username)
405 5a140b23 Vangelis Koukis
406 5a140b23 Vangelis Koukis
    def test_002d_verify_server_metadata(self):
407 5a140b23 Vangelis Koukis
        """Test server metadata keys are set based on image metadata"""
408 5a140b23 Vangelis Koukis
        servermeta = self.client.get_server_metadata(self.serverid)
409 5a140b23 Vangelis Koukis
        imagemeta = self.client.get_image_metadata(self.imageid)
410 99d41650 John Giannelos
        self.assertEqual(servermeta["OS"], imagemeta["os"])
411 5a140b23 Vangelis Koukis
412 5a140b23 Vangelis Koukis
    def test_003_server_becomes_active(self):
413 5a140b23 Vangelis Koukis
        """Test server becomes ACTIVE"""
414 bc14ba88 Vangelis Koukis
        self._insist_on_status_transition("BUILD", "ACTIVE",
415 5a140b23 Vangelis Koukis
                                         self.build_fail, self.build_warning)
416 5a140b23 Vangelis Koukis
417 5a140b23 Vangelis Koukis
    def test_003a_get_server_oob_console(self):
418 bc14ba88 Vangelis Koukis
        """Test getting OOB server console over VNC
419 bc14ba88 Vangelis Koukis

420 bc14ba88 Vangelis Koukis
        Implementation of RFB protocol follows
421 bc14ba88 Vangelis Koukis
        http://www.realvnc.com/docs/rfbproto.pdf.
422 bc14ba88 Vangelis Koukis

423 bc14ba88 Vangelis Koukis
        """
424 74193008 John Giannelos
        
425 74193008 John Giannelos
        console = self.cyclades.get_server_console(self.serverid)
426 5a140b23 Vangelis Koukis
        self.assertEquals(console['type'], "vnc")
427 bc14ba88 Vangelis Koukis
        sock = self._insist_on_tcp_connection(socket.AF_UNSPEC,
428 5a140b23 Vangelis Koukis
                                        console["host"], console["port"])
429 bc14ba88 Vangelis Koukis
430 bc14ba88 Vangelis Koukis
        # Step 1. ProtocolVersion message (par. 6.1.1)
431 5a140b23 Vangelis Koukis
        version = sock.recv(1024)
432 bc14ba88 Vangelis Koukis
        self.assertEquals(version, 'RFB 003.008\n')
433 bc14ba88 Vangelis Koukis
        sock.send(version)
434 bc14ba88 Vangelis Koukis
435 bc14ba88 Vangelis Koukis
        # Step 2. Security (par 6.1.2): Only VNC Authentication supported
436 bc14ba88 Vangelis Koukis
        sec = sock.recv(1024)
437 bc14ba88 Vangelis Koukis
        self.assertEquals(list(sec), ['\x01', '\x02'])
438 bc14ba88 Vangelis Koukis
439 bc14ba88 Vangelis Koukis
        # Step 3. Request VNC Authentication (par 6.1.2)
440 bc14ba88 Vangelis Koukis
        sock.send('\x02')
441 bc14ba88 Vangelis Koukis
442 bc14ba88 Vangelis Koukis
        # Step 4. Receive Challenge (par 6.2.2)
443 bc14ba88 Vangelis Koukis
        challenge = sock.recv(1024)
444 bc14ba88 Vangelis Koukis
        self.assertEquals(len(challenge), 16)
445 bc14ba88 Vangelis Koukis
446 bc14ba88 Vangelis Koukis
        # Step 5. DES-Encrypt challenge, use password as key (par 6.2.2)
447 bc14ba88 Vangelis Koukis
        response = d3des_generate_response(
448 bc14ba88 Vangelis Koukis
            (console["password"] + '\0' * 8)[:8], challenge)
449 bc14ba88 Vangelis Koukis
        sock.send(response)
450 bc14ba88 Vangelis Koukis
451 bc14ba88 Vangelis Koukis
        # Step 6. SecurityResult (par 6.1.3)
452 bc14ba88 Vangelis Koukis
        result = sock.recv(4)
453 bc14ba88 Vangelis Koukis
        self.assertEquals(list(result), ['\x00', '\x00', '\x00', '\x00'])
454 5a140b23 Vangelis Koukis
        sock.close()
455 5a140b23 Vangelis Koukis
456 5a140b23 Vangelis Koukis
    def test_004_server_has_ipv4(self):
457 5a140b23 Vangelis Koukis
        """Test active server has a valid IPv4 address"""
458 5a140b23 Vangelis Koukis
        server = self.client.get_server_details(self.serverid)
459 5a140b23 Vangelis Koukis
        ipv4 = self._get_ipv4(server)
460 5a140b23 Vangelis Koukis
        self.assertEquals(IP(ipv4).version(), 4)
461 5a140b23 Vangelis Koukis
462 5a140b23 Vangelis Koukis
    def test_005_server_has_ipv6(self):
463 5a140b23 Vangelis Koukis
        """Test active server has a valid IPv6 address"""
464 5a140b23 Vangelis Koukis
        server = self.client.get_server_details(self.serverid)
465 5a140b23 Vangelis Koukis
        ipv6 = self._get_ipv6(server)
466 5a140b23 Vangelis Koukis
        self.assertEquals(IP(ipv6).version(), 6)
467 5a140b23 Vangelis Koukis
468 5a140b23 Vangelis Koukis
    def test_006_server_responds_to_ping_IPv4(self):
469 5a140b23 Vangelis Koukis
        """Test server responds to ping on IPv4 address"""
470 5a140b23 Vangelis Koukis
        server = self.client.get_server_details(self.serverid)
471 bc14ba88 Vangelis Koukis
        ip = self._get_ipv4(server)
472 bc14ba88 Vangelis Koukis
        self._try_until_timeout_expires(self.action_timeout,
473 bc14ba88 Vangelis Koukis
                                        self.action_timeout,
474 4fdd25ab Vangelis Koukis
                                        "PING IPv4 to %s" % ip,
475 4fdd25ab Vangelis Koukis
                                        self._ping_once,
476 bc14ba88 Vangelis Koukis
                                        False, ip)
477 5a140b23 Vangelis Koukis
478 5a140b23 Vangelis Koukis
    def test_007_server_responds_to_ping_IPv6(self):
479 5a140b23 Vangelis Koukis
        """Test server responds to ping on IPv6 address"""
480 5a140b23 Vangelis Koukis
        server = self.client.get_server_details(self.serverid)
481 bc14ba88 Vangelis Koukis
        ip = self._get_ipv6(server)
482 bc14ba88 Vangelis Koukis
        self._try_until_timeout_expires(self.action_timeout,
483 bc14ba88 Vangelis Koukis
                                        self.action_timeout,
484 4fdd25ab Vangelis Koukis
                                        "PING IPv6 to %s" % ip,
485 4fdd25ab Vangelis Koukis
                                        self._ping_once,
486 bc14ba88 Vangelis Koukis
                                        True, ip)
487 5a140b23 Vangelis Koukis
488 5a140b23 Vangelis Koukis
    def test_008_submit_shutdown_request(self):
489 5a140b23 Vangelis Koukis
        """Test submit request to shutdown server"""
490 74193008 John Giannelos
        self.cyclades.shutdown_server(self.serverid)
491 5a140b23 Vangelis Koukis
492 5a140b23 Vangelis Koukis
    def test_009_server_becomes_stopped(self):
493 5a140b23 Vangelis Koukis
        """Test server becomes STOPPED"""
494 bc14ba88 Vangelis Koukis
        self._insist_on_status_transition("ACTIVE", "STOPPED",
495 bc14ba88 Vangelis Koukis
                                         self.action_timeout,
496 5a140b23 Vangelis Koukis
                                         self.action_timeout)
497 5a140b23 Vangelis Koukis
498 5a140b23 Vangelis Koukis
    def test_010_submit_start_request(self):
499 5a140b23 Vangelis Koukis
        """Test submit start server request"""
500 74193008 John Giannelos
        self.cyclades.start_server(self.serverid)
501 5a140b23 Vangelis Koukis
502 5a140b23 Vangelis Koukis
    def test_011_server_becomes_active(self):
503 5a140b23 Vangelis Koukis
        """Test server becomes ACTIVE again"""
504 bc14ba88 Vangelis Koukis
        self._insist_on_status_transition("STOPPED", "ACTIVE",
505 bc14ba88 Vangelis Koukis
                                         self.action_timeout,
506 5a140b23 Vangelis Koukis
                                         self.action_timeout)
507 5a140b23 Vangelis Koukis
508 5a140b23 Vangelis Koukis
    def test_011a_server_responds_to_ping_IPv4(self):
509 5a140b23 Vangelis Koukis
        """Test server OS is actually up and running again"""
510 5a140b23 Vangelis Koukis
        self.test_006_server_responds_to_ping_IPv4()
511 5a140b23 Vangelis Koukis
512 5a140b23 Vangelis Koukis
    def test_012_ssh_to_server_IPv4(self):
513 5a140b23 Vangelis Koukis
        """Test SSH to server public IPv4 works, verify hostname"""
514 bc14ba88 Vangelis Koukis
        self._skipIf(self.is_windows, "only valid for Linux servers")
515 5a140b23 Vangelis Koukis
        server = self.client.get_server_details(self.serverid)
516 bc14ba88 Vangelis Koukis
        self._insist_on_ssh_hostname(self._get_ipv4(server),
517 bc14ba88 Vangelis Koukis
                                     self.username, self.passwd)
518 5a140b23 Vangelis Koukis
519 5a140b23 Vangelis Koukis
    def test_013_ssh_to_server_IPv6(self):
520 5a140b23 Vangelis Koukis
        """Test SSH to server public IPv6 works, verify hostname"""
521 bc14ba88 Vangelis Koukis
        self._skipIf(self.is_windows, "only valid for Linux servers")
522 5a140b23 Vangelis Koukis
        server = self.client.get_server_details(self.serverid)
523 bc14ba88 Vangelis Koukis
        self._insist_on_ssh_hostname(self._get_ipv6(server),
524 bc14ba88 Vangelis Koukis
                                     self.username, self.passwd)
525 5a140b23 Vangelis Koukis
526 5a140b23 Vangelis Koukis
    def test_014_rdp_to_server_IPv4(self):
527 5a140b23 Vangelis Koukis
        "Test RDP connection to server public IPv4 works"""
528 bc14ba88 Vangelis Koukis
        self._skipIf(not self.is_windows, "only valid for Windows servers")
529 5a140b23 Vangelis Koukis
        server = self.client.get_server_details(self.serverid)
530 5a140b23 Vangelis Koukis
        ipv4 = self._get_ipv4(server)
531 bc14ba88 Vangelis Koukis
        sock = _insist_on_tcp_connection(socket.AF_INET, ipv4, 3389)
532 5a140b23 Vangelis Koukis
533 5a140b23 Vangelis Koukis
        # No actual RDP processing done. We assume the RDP server is there
534 5a140b23 Vangelis Koukis
        # if the connection to the RDP port is successful.
535 cb1fa17c Vangelis Koukis
        # FIXME: Use rdesktop, analyze exit code? see manpage [costasd]
536 5a140b23 Vangelis Koukis
        sock.close()
537 5a140b23 Vangelis Koukis
538 5a140b23 Vangelis Koukis
    def test_015_rdp_to_server_IPv6(self):
539 5a140b23 Vangelis Koukis
        "Test RDP connection to server public IPv6 works"""
540 bc14ba88 Vangelis Koukis
        self._skipIf(not self.is_windows, "only valid for Windows servers")
541 5a140b23 Vangelis Koukis
        server = self.client.get_server_details(self.serverid)
542 5a140b23 Vangelis Koukis
        ipv6 = self._get_ipv6(server)
543 5a140b23 Vangelis Koukis
        sock = _get_tcp_connection(socket.AF_INET6, ipv6, 3389)
544 5a140b23 Vangelis Koukis
545 5a140b23 Vangelis Koukis
        # No actual RDP processing done. We assume the RDP server is there
546 5a140b23 Vangelis Koukis
        # if the connection to the RDP port is successful.
547 5a140b23 Vangelis Koukis
        sock.close()
548 5a140b23 Vangelis Koukis
549 5a140b23 Vangelis Koukis
    def test_016_personality_is_enforced(self):
550 5a140b23 Vangelis Koukis
        """Test file injection for personality enforcement"""
551 bc14ba88 Vangelis Koukis
        self._skipIf(self.is_windows, "only implemented for Linux servers")
552 5a140b23 Vangelis Koukis
        self.assertTrue(False, "test not implemented, will fail")
553 5a140b23 Vangelis Koukis
554 4fdd25ab Vangelis Koukis
    def test_017_submit_delete_request(self):
555 4fdd25ab Vangelis Koukis
        """Test submit request to delete server"""
556 4fdd25ab Vangelis Koukis
        self.client.delete_server(self.serverid)
557 4fdd25ab Vangelis Koukis
558 4fdd25ab Vangelis Koukis
    def test_018_server_becomes_deleted(self):
559 4fdd25ab Vangelis Koukis
        """Test server becomes DELETED"""
560 4fdd25ab Vangelis Koukis
        self._insist_on_status_transition("ACTIVE", "DELETED",
561 4fdd25ab Vangelis Koukis
                                         self.action_timeout,
562 4fdd25ab Vangelis Koukis
                                         self.action_timeout)
563 4fdd25ab Vangelis Koukis
564 4fdd25ab Vangelis Koukis
    def test_019_server_no_longer_in_server_list(self):
565 4fdd25ab Vangelis Koukis
        """Test server is no longer in server list"""
566 4fdd25ab Vangelis Koukis
        servers = self.client.list_servers()
567 21bbbc9b Vangelis Koukis
        self.assertNotIn(self.serverid, [s["id"] for s in servers])
568 21bbbc9b Vangelis Koukis
569 21bbbc9b Vangelis Koukis
570 9e4682b5 John Giannelos
class NetworkTestCase(unittest.TestCase):
571 e94a9d8c John Giannelos
    """ Testing networking in cyclades """
572 9e4682b5 John Giannelos
    @classmethod
573 e94a9d8c John Giannelos
    def setUpClass(cls):
574 e94a9d8c John Giannelos
        "Initialize kamaki, get list of current networks"
575 e94a9d8c John Giannelos
        conf = Config()
576 e94a9d8c John Giannelos
        conf.set('compute_token', TOKEN)
577 e94a9d8c John Giannelos
        cls.client = CycladesClient(conf)
578 9e4682b5 John Giannelos
        cls.compute = ComputeClient(conf)
579 9e4682b5 John Giannelos
580 9e4682b5 John Giannelos
        images = cls.compute.list_images(detail = True)
581 9e4682b5 John Giannelos
        flavors = cls.compute.list_flavors(detail = True)
582 9e4682b5 John Giannelos
        imageid = choice([im['id'] for im in images])
583 9e4682b5 John Giannelos
        flavorid = choice([f["id"] for f in flavors if f["disk"] >= 20])
584 9e4682b5 John Giannelos
585 9e4682b5 John Giannelos
        for image in images:
586 9e4682b5 John Giannelos
            if image['id'] == imageid:
587 9e4682b5 John Giannelos
                imagename = image['name']
588 e94a9d8c John Giannelos
589 9e4682b5 John Giannelos
        servername = "%s%s for %s" % (SNF_TEST_PREFIX, TEST_RUN_ID, imagename)
590 9e4682b5 John Giannelos
        is_windows = imagename.lower().find("windows") >= 0
591 9e4682b5 John Giannelos
        setupCase =  _spawn_server_test_case(imageid=str(imageid), flavorid=flavorid,
592 9e4682b5 John Giannelos
                                             imagename=imagename,
593 9e4682b5 John Giannelos
                                             personality=None,
594 9e4682b5 John Giannelos
                                             servername=servername,
595 9e4682b5 John Giannelos
                                             is_windows=is_windows,
596 9e4682b5 John Giannelos
                                             action_timeout=200,
597 9e4682b5 John Giannelos
                                             build_warning=1200,
598 9e4682b5 John Giannelos
                                             build_fail=500,
599 9e4682b5 John Giannelos
                                             query_interval=3)
600 9e4682b5 John Giannelos
601 9e4682b5 John Giannelos
        #Using already implemented tests for serverlist population
602 9e4682b5 John Giannelos
        suite = unittest.TestSuite()
603 9e4682b5 John Giannelos
        suite.addTest(setupCase('test_001_submit_create_server'))
604 9e4682b5 John Giannelos
        suite.addTest(setupCase('test_002a_server_is_building_in_list'))
605 9e4682b5 John Giannelos
        suite.addTest(setupCase('test_002b_server_is_building_in_details'))        
606 9e4682b5 John Giannelos
        suite.addTest(setupCase('test_003_server_becomes_active'))
607 9e4682b5 John Giannelos
        unittest.TextTestRunner(verbosity=2).run(suite)
608 e94a9d8c John Giannelos
609 9e4682b5 John Giannelos
    def test_001_create_network(self):
610 e94a9d8c John Giannelos
        """Test submit create network request"""
611 e94a9d8c John Giannelos
        name = SNF_TEST_PREFIX+TEST_RUN_ID
612 9e4682b5 John Giannelos
        network =  self.client.create_network(name)        
613 9e4682b5 John Giannelos
        previous_num = len(self.client.list_networks())
614 9e4682b5 John Giannelos
615 9e4682b5 John Giannelos
        #Test if right name is assigned
616 e94a9d8c John Giannelos
        self.assertEqual(network['name'], name)
617 e94a9d8c John Giannelos
        
618 9e4682b5 John Giannelos
        # Update class attributes
619 e94a9d8c John Giannelos
        cls = type(self)
620 e94a9d8c John Giannelos
        cls.networkid = network['id']
621 9e4682b5 John Giannelos
        networks = self.client.list_networks()
622 9e4682b5 John Giannelos
623 9e4682b5 John Giannelos
        #Test if new network is created
624 9e4682b5 John Giannelos
        self.assertTrue(len(networks) > previous_num)
625 9e4682b5 John Giannelos
        
626 e94a9d8c John Giannelos
    
627 9e4682b5 John Giannelos
    def test_002_connect_to_network(self):
628 e94a9d8c John Giannelos
        """Test VM to network connection"""
629 9e4682b5 John Giannelos
        servers = self.compute.list_servers()
630 9e4682b5 John Giannelos
        server = choice(servers)
631 9e4682b5 John Giannelos
        self.client.connect_server(server['id'], self.networkid)
632 9e4682b5 John Giannelos
        
633 9e4682b5 John Giannelos
        #Update class attributes
634 9e4682b5 John Giannelos
        cls = type(self)
635 9e4682b5 John Giannelos
        cls.serverid = server['id']
636 9e4682b5 John Giannelos
637 9e4682b5 John Giannelos
        connected = (self.client.get_network_details(self.networkid))
638 9e4682b5 John Giannelos
        connections = len(connected['servers']['values'])
639 9e4682b5 John Giannelos
        
640 9e4682b5 John Giannelos
        time.sleep(60)
641 9e4682b5 John Giannelos
642 9e4682b5 John Giannelos
        #FIXME: Insist on new connection
643 9e4682b5 John Giannelos
        self.assertTrue(connections>=1)
644 9e4682b5 John Giannelos
        
645 9e4682b5 John Giannelos
646 9e4682b5 John Giannelos
    def test_003_disconnect_from_network(self):
647 9e4682b5 John Giannelos
        prev_state = (self.client.get_network_details(self.networkid))
648 9e4682b5 John Giannelos
        prev_conn = len(prev_state['servers']['values'])
649 e94a9d8c John Giannelos
650 e94a9d8c John Giannelos
        self.client.disconnect_server(self.serverid, self.networkid)
651 9e4682b5 John Giannelos
        connected = (self.client.get_network_details(self.networkid))
652 9e4682b5 John Giannelos
        curr_conn = len(connected['servers']['values'])
653 9e4682b5 John Giannelos
654 9e4682b5 John Giannelos
        #FIXME: Insist on deleting
655 9e4682b5 John Giannelos
        self.assertTrue(curr_conn < prev_conn)
656 9e4682b5 John Giannelos
657 9e4682b5 John Giannelos
    def test_004_destroy_network(self):
658 e94a9d8c John Giannelos
        """Test submit delete network request"""
659 e94a9d8c John Giannelos
        self.client.delete_network(self.networkid)
660 9e4682b5 John Giannelos
        
661 9e4682b5 John Giannelos
        networks = self.client.list_networks()
662 9e4682b5 John Giannelos
        self.assertEqual(len(networks),1)
663 e94a9d8c John Giannelos
664 e94a9d8c John Giannelos
665 21bbbc9b Vangelis Koukis
class TestRunnerProcess(Process):
666 21bbbc9b Vangelis Koukis
    """A distinct process used to execute part of the tests in parallel"""
667 21bbbc9b Vangelis Koukis
    def __init__(self, **kw):
668 21bbbc9b Vangelis Koukis
        Process.__init__(self, **kw)
669 21bbbc9b Vangelis Koukis
        kwargs = kw["kwargs"]
670 21bbbc9b Vangelis Koukis
        self.testq = kwargs["testq"]
671 21bbbc9b Vangelis Koukis
        self.runner = kwargs["runner"]
672 21bbbc9b Vangelis Koukis
673 21bbbc9b Vangelis Koukis
    def run(self):
674 21bbbc9b Vangelis Koukis
        # Make sure this test runner process dies with the parent
675 21bbbc9b Vangelis Koukis
        # and is not left behind.
676 21bbbc9b Vangelis Koukis
        #
677 21bbbc9b Vangelis Koukis
        # WARNING: This uses the prctl(2) call and is
678 21bbbc9b Vangelis Koukis
        # Linux-specific.
679 21bbbc9b Vangelis Koukis
        prctl.set_pdeathsig(signal.SIGHUP)
680 21bbbc9b Vangelis Koukis
681 21bbbc9b Vangelis Koukis
        while True:
682 21bbbc9b Vangelis Koukis
            log.debug("I am process %d, GETting from queue is %s",
683 21bbbc9b Vangelis Koukis
                     os.getpid(), self.testq)
684 21bbbc9b Vangelis Koukis
            msg = self.testq.get()
685 21bbbc9b Vangelis Koukis
            log.debug("Dequeued msg: %s", msg)
686 21bbbc9b Vangelis Koukis
687 21bbbc9b Vangelis Koukis
            if msg == "TEST_RUNNER_TERMINATE":
688 21bbbc9b Vangelis Koukis
                raise SystemExit
689 21bbbc9b Vangelis Koukis
            elif issubclass(msg, unittest.TestCase):
690 21bbbc9b Vangelis Koukis
                # Assemble a TestSuite, and run it
691 21bbbc9b Vangelis Koukis
                suite = unittest.TestLoader().loadTestsFromTestCase(msg)
692 21bbbc9b Vangelis Koukis
                self.runner.run(suite)
693 21bbbc9b Vangelis Koukis
            else:
694 21bbbc9b Vangelis Koukis
                raise Exception("Cannot handle msg: %s" % msg)
695 21bbbc9b Vangelis Koukis
696 21bbbc9b Vangelis Koukis
697 99d41650 John Giannelos
698 21bbbc9b Vangelis Koukis
def _run_cases_in_parallel(cases, fanout=1, runner=None):
699 21bbbc9b Vangelis Koukis
    """Run instances of TestCase in parallel, in a number of distinct processes
700 21bbbc9b Vangelis Koukis

701 21bbbc9b Vangelis Koukis
    The cases iterable specifies the TestCases to be executed in parallel,
702 21bbbc9b Vangelis Koukis
    by test runners running in distinct processes.
703 21bbbc9b Vangelis Koukis
    The fanout parameter specifies the number of processes to spawn,
704 21bbbc9b Vangelis Koukis
    and defaults to 1.
705 21bbbc9b Vangelis Koukis
    The runner argument specifies the test runner class to use inside each
706 21bbbc9b Vangelis Koukis
    runner process.
707 21bbbc9b Vangelis Koukis

708 21bbbc9b Vangelis Koukis
    """
709 21bbbc9b Vangelis Koukis
    if runner is None:
710 00f87624 Vangelis Koukis
        runner = unittest.TextTestRunner(verbosity=2, failfast=True)
711 21bbbc9b Vangelis Koukis
712 21bbbc9b Vangelis Koukis
    # testq: The master process enqueues TestCase objects into this queue,
713 21bbbc9b Vangelis Koukis
    #        test runner processes pick them up for execution, in parallel.
714 21bbbc9b Vangelis Koukis
    testq = Queue()
715 21bbbc9b Vangelis Koukis
    runners = []
716 21bbbc9b Vangelis Koukis
    for i in xrange(0, fanout):
717 21bbbc9b Vangelis Koukis
        kwargs = dict(testq=testq, runner=runner)
718 21bbbc9b Vangelis Koukis
        runners.append(TestRunnerProcess(kwargs=kwargs))
719 21bbbc9b Vangelis Koukis
720 21bbbc9b Vangelis Koukis
    log.info("Spawning %d test runner processes", len(runners))
721 21bbbc9b Vangelis Koukis
    for p in runners:
722 21bbbc9b Vangelis Koukis
        p.start()
723 21bbbc9b Vangelis Koukis
    log.debug("Spawned %d test runners, PIDs are %s",
724 21bbbc9b Vangelis Koukis
              len(runners), [p.pid for p in runners])
725 21bbbc9b Vangelis Koukis
726 21bbbc9b Vangelis Koukis
    # Enqueue test cases
727 21bbbc9b Vangelis Koukis
    map(testq.put, cases)
728 21bbbc9b Vangelis Koukis
    map(testq.put, ["TEST_RUNNER_TERMINATE"] * len(runners))
729 21bbbc9b Vangelis Koukis
730 21bbbc9b Vangelis Koukis
    log.debug("Joining %d processes", len(runners))
731 21bbbc9b Vangelis Koukis
    for p in runners:
732 21bbbc9b Vangelis Koukis
        p.join()
733 21bbbc9b Vangelis Koukis
    log.debug("Done joining %d processes", len(runners))
734 4fdd25ab Vangelis Koukis
735 5a140b23 Vangelis Koukis
736 5a140b23 Vangelis Koukis
def _spawn_server_test_case(**kwargs):
737 5a140b23 Vangelis Koukis
    """Construct a new unit test case class from SpawnServerTestCase"""
738 5a140b23 Vangelis Koukis
739 c1d11f96 John Giannelos
    name = "SpawnServerTestCase_%s" % kwargs["imageid"]
740 5a140b23 Vangelis Koukis
    cls = type(name, (SpawnServerTestCase,), kwargs)
741 5a140b23 Vangelis Koukis
742 5a140b23 Vangelis Koukis
    # Patch extra parameters into test names by manipulating method docstrings
743 5a140b23 Vangelis Koukis
    for (mname, m) in \
744 5a140b23 Vangelis Koukis
        inspect.getmembers(cls, lambda x: inspect.ismethod(x)):
745 5a140b23 Vangelis Koukis
            if hasattr(m, __doc__):
746 5a140b23 Vangelis Koukis
                m.__func__.__doc__ = "[%s] %s" % (imagename, m.__doc__)
747 e72bcf60 Vangelis Koukis
748 e72bcf60 Vangelis Koukis
    # Make sure the class can be pickled, by listing it among
749 e72bcf60 Vangelis Koukis
    # the attributes of __main__. A PicklingError is raised otherwise.
750 e72bcf60 Vangelis Koukis
    setattr(__main__, name, cls)
751 5a140b23 Vangelis Koukis
    return cls
752 5a140b23 Vangelis Koukis
753 5a140b23 Vangelis Koukis
754 5a140b23 Vangelis Koukis
def cleanup_servers(delete_stale=False):
755 74193008 John Giannelos
756 74193008 John Giannelos
    conf = Config()
757 74193008 John Giannelos
    conf.set('compute_token', TOKEN)
758 74193008 John Giannelos
    c = ComputeClient(conf)
759 74193008 John Giannelos
760 5a140b23 Vangelis Koukis
    servers = c.list_servers()
761 5a140b23 Vangelis Koukis
    stale = [s for s in servers if s["name"].startswith(SNF_TEST_PREFIX)]
762 5a140b23 Vangelis Koukis
763 4fdd25ab Vangelis Koukis
    if len(stale) == 0:
764 4fdd25ab Vangelis Koukis
        return
765 4fdd25ab Vangelis Koukis
766 5a140b23 Vangelis Koukis
    print >> sys.stderr, "Found these stale servers from previous runs:"
767 5a140b23 Vangelis Koukis
    print "    " + \
768 21bbbc9b Vangelis Koukis
          "\n    ".join(["%d: %s" % (s["id"], s["name"]) for s in stale])
769 5a140b23 Vangelis Koukis
770 5a140b23 Vangelis Koukis
    if delete_stale:
771 5a140b23 Vangelis Koukis
        print >> sys.stderr, "Deleting %d stale servers:" % len(stale)
772 5a140b23 Vangelis Koukis
        for server in stale:
773 21bbbc9b Vangelis Koukis
            c.delete_server(server["id"])
774 5a140b23 Vangelis Koukis
        print >> sys.stderr, "    ...done"
775 5a140b23 Vangelis Koukis
    else:
776 5a140b23 Vangelis Koukis
        print >> sys.stderr, "Use --delete-stale to delete them."
777 5a140b23 Vangelis Koukis
778 5a140b23 Vangelis Koukis
779 5a140b23 Vangelis Koukis
def parse_arguments(args):
780 5a140b23 Vangelis Koukis
    from optparse import OptionParser
781 5a140b23 Vangelis Koukis
782 5a140b23 Vangelis Koukis
    kw = {}
783 5a140b23 Vangelis Koukis
    kw["usage"] = "%prog [options]"
784 5a140b23 Vangelis Koukis
    kw["description"] = \
785 5a140b23 Vangelis Koukis
        "%prog runs a number of test scenarios on a " \
786 5a140b23 Vangelis Koukis
        "Synnefo deployment."
787 5a140b23 Vangelis Koukis
788 5a140b23 Vangelis Koukis
    parser = OptionParser(**kw)
789 5a140b23 Vangelis Koukis
    parser.disable_interspersed_args()
790 21bbbc9b Vangelis Koukis
    parser.add_option("--api",
791 21bbbc9b Vangelis Koukis
                      action="store", type="string", dest="api",
792 21bbbc9b Vangelis Koukis
                      help="The API URI to use to reach the Synnefo API",
793 21bbbc9b Vangelis Koukis
                      default=DEFAULT_API)
794 21bbbc9b Vangelis Koukis
    parser.add_option("--token",
795 21bbbc9b Vangelis Koukis
                      action="store", type="string", dest="token",
796 38d247df Kostas Papadimitriou
                      help="The token to use for authentication to the API")
797 00f87624 Vangelis Koukis
    parser.add_option("--nofailfast",
798 00f87624 Vangelis Koukis
                      action="store_true", dest="nofailfast",
799 00f87624 Vangelis Koukis
                      help="Do not fail immediately if one of the tests " \
800 00f87624 Vangelis Koukis
                           "fails (EXPERIMENTAL)",
801 bc14ba88 Vangelis Koukis
                      default=False)
802 5a140b23 Vangelis Koukis
    parser.add_option("--action-timeout",
803 5a140b23 Vangelis Koukis
                      action="store", type="int", dest="action_timeout",
804 5a140b23 Vangelis Koukis
                      metavar="TIMEOUT",
805 5a140b23 Vangelis Koukis
                      help="Wait SECONDS seconds for a server action to " \
806 5a140b23 Vangelis Koukis
                           "complete, then the test is considered failed",
807 9e4682b5 John Giannelos
                      default=100)
808 5a140b23 Vangelis Koukis
    parser.add_option("--build-warning",
809 5a140b23 Vangelis Koukis
                      action="store", type="int", dest="build_warning",
810 5a140b23 Vangelis Koukis
                      metavar="TIMEOUT",
811 5a140b23 Vangelis Koukis
                      help="Warn if TIMEOUT seconds have passed and a " \
812 5a140b23 Vangelis Koukis
                           "build operation is still pending",
813 5a140b23 Vangelis Koukis
                      default=600)
814 5a140b23 Vangelis Koukis
    parser.add_option("--build-fail",
815 5a140b23 Vangelis Koukis
                      action="store", type="int", dest="build_fail",
816 5a140b23 Vangelis Koukis
                      metavar="BUILD_TIMEOUT",
817 5a140b23 Vangelis Koukis
                      help="Fail the test if TIMEOUT seconds have passed " \
818 5a140b23 Vangelis Koukis
                           "and a build operation is still incomplete",
819 5a140b23 Vangelis Koukis
                      default=900)
820 5a140b23 Vangelis Koukis
    parser.add_option("--query-interval",
821 5a140b23 Vangelis Koukis
                      action="store", type="int", dest="query_interval",
822 5a140b23 Vangelis Koukis
                      metavar="INTERVAL",
823 5a140b23 Vangelis Koukis
                      help="Query server status when requests are pending " \
824 5a140b23 Vangelis Koukis
                           "every INTERVAL seconds",
825 5a140b23 Vangelis Koukis
                      default=3)
826 21bbbc9b Vangelis Koukis
    parser.add_option("--fanout",
827 21bbbc9b Vangelis Koukis
                      action="store", type="int", dest="fanout",
828 5a140b23 Vangelis Koukis
                      metavar="COUNT",
829 21bbbc9b Vangelis Koukis
                      help="Spawn up to COUNT child processes to execute " \
830 21bbbc9b Vangelis Koukis
                           "in parallel, essentially have up to COUNT " \
831 00f87624 Vangelis Koukis
                           "server build requests outstanding (EXPERIMENTAL)",
832 5a140b23 Vangelis Koukis
                      default=1)
833 5a140b23 Vangelis Koukis
    parser.add_option("--force-flavor",
834 5a140b23 Vangelis Koukis
                      action="store", type="int", dest="force_flavorid",
835 5a140b23 Vangelis Koukis
                      metavar="FLAVOR ID",
836 5a140b23 Vangelis Koukis
                      help="Force all server creations to use the specified "\
837 5a140b23 Vangelis Koukis
                           "FLAVOR ID instead of a randomly chosen one, " \
838 5a140b23 Vangelis Koukis
                           "useful if disk space is scarce",
839 00f87624 Vangelis Koukis
                      default=None)
840 7f62a0b5 Vangelis Koukis
    parser.add_option("--image-id",
841 7f62a0b5 Vangelis Koukis
                      action="store", type="string", dest="force_imageid",
842 00f87624 Vangelis Koukis
                      metavar="IMAGE ID",
843 7f62a0b5 Vangelis Koukis
                      help="Test the specified image id, use 'all' to test " \
844 7f62a0b5 Vangelis Koukis
                           "all available images (mandatory argument)",
845 00f87624 Vangelis Koukis
                      default=None)
846 5a140b23 Vangelis Koukis
    parser.add_option("--show-stale",
847 5a140b23 Vangelis Koukis
                      action="store_true", dest="show_stale",
848 5a140b23 Vangelis Koukis
                      help="Show stale servers from previous runs, whose "\
849 21bbbc9b Vangelis Koukis
                           "name starts with `%s'" % SNF_TEST_PREFIX,
850 5a140b23 Vangelis Koukis
                      default=False)
851 5a140b23 Vangelis Koukis
    parser.add_option("--delete-stale",
852 5a140b23 Vangelis Koukis
                      action="store_true", dest="delete_stale",
853 5a140b23 Vangelis Koukis
                      help="Delete stale servers from previous runs, whose "\
854 21bbbc9b Vangelis Koukis
                           "name starts with `%s'" % SNF_TEST_PREFIX,
855 5a140b23 Vangelis Koukis
                      default=False)
856 5a140b23 Vangelis Koukis
857 5a140b23 Vangelis Koukis
    # FIXME: Change the default for build-fanout to 10
858 5a140b23 Vangelis Koukis
    # FIXME: Allow the user to specify a specific set of Images to test
859 5a140b23 Vangelis Koukis
860 5a140b23 Vangelis Koukis
    (opts, args) = parser.parse_args(args)
861 5a140b23 Vangelis Koukis
862 5a140b23 Vangelis Koukis
    # Verify arguments
863 5a140b23 Vangelis Koukis
    if opts.delete_stale:
864 5a140b23 Vangelis Koukis
        opts.show_stale = True
865 5a140b23 Vangelis Koukis
866 7f62a0b5 Vangelis Koukis
    if not opts.show_stale:
867 7f62a0b5 Vangelis Koukis
        if not opts.force_imageid:
868 7f62a0b5 Vangelis Koukis
            print >>sys.stderr, "The --image-id argument is mandatory."
869 7f62a0b5 Vangelis Koukis
            parser.print_help()
870 7f62a0b5 Vangelis Koukis
            sys.exit(1)
871 7f62a0b5 Vangelis Koukis
872 7f62a0b5 Vangelis Koukis
        if opts.force_imageid != 'all':
873 7f62a0b5 Vangelis Koukis
            try:
874 99d41650 John Giannelos
                opts.force_imageid = str(opts.force_imageid)
875 7f62a0b5 Vangelis Koukis
            except ValueError:
876 7f62a0b5 Vangelis Koukis
                print >>sys.stderr, "Invalid value specified for --image-id." \
877 e94a9d8c John Giannelos
                                    "Use a valid id, or `all'."
878 7f62a0b5 Vangelis Koukis
                sys.exit(1)
879 7f62a0b5 Vangelis Koukis
880 5a140b23 Vangelis Koukis
    return (opts, args)
881 5a140b23 Vangelis Koukis
882 5a140b23 Vangelis Koukis
883 5a140b23 Vangelis Koukis
def main():
884 5a140b23 Vangelis Koukis
    """Assemble test cases into a test suite, and run it
885 5a140b23 Vangelis Koukis

886 5a140b23 Vangelis Koukis
    IMPORTANT: Tests have dependencies and have to be run in the specified
887 5a140b23 Vangelis Koukis
    order inside a single test case. They communicate through attributes of the
888 21bbbc9b Vangelis Koukis
    corresponding TestCase class (shared fixtures). Distinct subclasses of
889 21bbbc9b Vangelis Koukis
    TestCase MAY SHARE NO DATA, since they are run in parallel, in distinct
890 21bbbc9b Vangelis Koukis
    test runner processes.
891 5a140b23 Vangelis Koukis

892 5a140b23 Vangelis Koukis
    """
893 5a140b23 Vangelis Koukis
    (opts, args) = parse_arguments(sys.argv[1:])
894 5a140b23 Vangelis Koukis
895 21bbbc9b Vangelis Koukis
    global API, TOKEN
896 21bbbc9b Vangelis Koukis
    API = opts.api
897 21bbbc9b Vangelis Koukis
    TOKEN = opts.token
898 21bbbc9b Vangelis Koukis
899 5a140b23 Vangelis Koukis
    # Cleanup stale servers from previous runs
900 5a140b23 Vangelis Koukis
    if opts.show_stale:
901 5a140b23 Vangelis Koukis
        cleanup_servers(delete_stale=opts.delete_stale)
902 5a140b23 Vangelis Koukis
        return 0
903 5a140b23 Vangelis Koukis
904 5a140b23 Vangelis Koukis
    # Initialize a kamaki instance, get flavors, images
905 74193008 John Giannelos
906 74193008 John Giannelos
    conf = Config()
907 74193008 John Giannelos
    conf.set('compute_token', TOKEN)
908 74193008 John Giannelos
    c = ComputeClient(conf)
909 74193008 John Giannelos
910 5a140b23 Vangelis Koukis
    DIMAGES = c.list_images(detail=True)
911 5a140b23 Vangelis Koukis
    DFLAVORS = c.list_flavors(detail=True)
912 5a140b23 Vangelis Koukis
913 21bbbc9b Vangelis Koukis
    # FIXME: logging, log, LOG PID, TEST_RUN_ID, arguments
914 5a140b23 Vangelis Koukis
    # Run them: FIXME: In parallel, FAILEARLY, catchbreak?
915 5a140b23 Vangelis Koukis
    #unittest.main(verbosity=2, catchbreak=True)
916 5a140b23 Vangelis Koukis
917 e94a9d8c John Giannelos
    if opts.force_imageid == 'all':
918 e94a9d8c John Giannelos
        test_images = DIMAGES
919 e94a9d8c John Giannelos
    else:
920 e94a9d8c John Giannelos
        test_images = filter(lambda x: x["id"] == opts.force_imageid, DIMAGES)
921 e94a9d8c John Giannelos
922 00f87624 Vangelis Koukis
    for image in test_images:
923 99d41650 John Giannelos
        imageid = str(image["id"])
924 99d41650 John Giannelos
        flavorid = choice([f["id"] for f in DFLAVORS if f["disk"] >= 20])
925 21bbbc9b Vangelis Koukis
        imagename = image["name"]
926 21bbbc9b Vangelis Koukis
        personality = None   # FIXME
927 21bbbc9b Vangelis Koukis
        servername = "%s%s for %s" % (SNF_TEST_PREFIX, TEST_RUN_ID, imagename)
928 21bbbc9b Vangelis Koukis
        is_windows = imagename.lower().find("windows") >= 0
929 9e4682b5 John Giannelos
        
930 e94a9d8c John Giannelos
        ServerTestCase = _spawn_server_test_case(imageid=imageid, flavorid=flavorid,
931 9e4682b5 John Giannelos
                                                 imagename=imagename,
932 9e4682b5 John Giannelos
                                                 personality=personality,
933 9e4682b5 John Giannelos
                                                 servername=servername,
934 9e4682b5 John Giannelos
                                                 is_windows=is_windows,
935 9e4682b5 John Giannelos
                                                 action_timeout=opts.action_timeout,
936 9e4682b5 John Giannelos
                                                 build_warning=opts.build_warning,
937 9e4682b5 John Giannelos
                                                 build_fail=opts.build_fail,
938 9e4682b5 John Giannelos
                                                 query_interval=opts.query_interval)
939 21bbbc9b Vangelis Koukis
940 99d41650 John Giannelos
941 e94a9d8c John Giannelos
    #Running all the testcases sequentially
942 9e4682b5 John Giannelos
    #seq_cases = [UnauthorizedTestCase, FlavorsTestCase, ImagesTestCase, ServerTestCase, NetworkTestCase]
943 9e4682b5 John Giannelos
944 9e4682b5 John Giannelos
    seq_cases = [NetworkTestCase]
945 99d41650 John Giannelos
    for case in seq_cases:
946 99d41650 John Giannelos
        suite = unittest.TestLoader().loadTestsFromTestCase(case)
947 99d41650 John Giannelos
        unittest.TextTestRunner(verbosity=2).run(suite)
948 e94a9d8c John Giannelos
        
949 99d41650 John Giannelos
    
950 99d41650 John Giannelos
951 99d41650 John Giannelos
    # # The Following cases run sequentially
952 99d41650 John Giannelos
    # seq_cases = [UnauthorizedTestCase, FlavorsTestCase, ImagesTestCase]
953 99d41650 John Giannelos
    # _run_cases_in_parallel(seq_cases, fanout=3, runner=runner)
954 99d41650 John Giannelos
955 99d41650 John Giannelos
    # # The following cases run in parallel
956 99d41650 John Giannelos
    # par_cases = []
957 99d41650 John Giannelos
958 99d41650 John Giannelos
    # if opts.force_imageid == 'all':
959 99d41650 John Giannelos
    #     test_images = DIMAGES
960 99d41650 John Giannelos
    # else:
961 99d41650 John Giannelos
    #     test_images = filter(lambda x: x["id"] == opts.force_imageid, DIMAGES)
962 99d41650 John Giannelos
963 99d41650 John Giannelos
    # for image in test_images:
964 99d41650 John Giannelos
    #     imageid = image["id"]
965 99d41650 John Giannelos
    #     imagename = image["name"]
966 99d41650 John Giannelos
    #     if opts.force_flavorid:
967 99d41650 John Giannelos
    #         flavorid = opts.force_flavorid
968 99d41650 John Giannelos
    #     else:
969 99d41650 John Giannelos
    #         flavorid = choice([f["id"] for f in DFLAVORS if f["disk"] >= 20])
970 99d41650 John Giannelos
    #     personality = None   # FIXME
971 99d41650 John Giannelos
    #     servername = "%s%s for %s" % (SNF_TEST_PREFIX, TEST_RUN_ID, imagename)
972 99d41650 John Giannelos
    #     is_windows = imagename.lower().find("windows") >= 0
973 99d41650 John Giannelos
    #     case = _spawn_server_test_case(imageid=str(imageid), flavorid=flavorid,
974 99d41650 John Giannelos
    #                                    imagename=imagename,
975 99d41650 John Giannelos
    #                                    personality=personality,
976 99d41650 John Giannelos
    #                                    servername=servername,
977 99d41650 John Giannelos
    #                                    is_windows=is_windows,
978 99d41650 John Giannelos
    #                                    action_timeout=opts.action_timeout,
979 99d41650 John Giannelos
    #                                    build_warning=opts.build_warning,
980 99d41650 John Giannelos
    #                                    build_fail=opts.build_fail,
981 99d41650 John Giannelos
    #                                    query_interval=opts.query_interval)
982 99d41650 John Giannelos
    #     par_cases.append(case)
983 99d41650 John Giannelos
984 99d41650 John Giannelos
    # _run_cases_in_parallel(par_cases, fanout=opts.fanout, runner=runner)
985 5a140b23 Vangelis Koukis
986 5a140b23 Vangelis Koukis
if __name__ == "__main__":
987 5a140b23 Vangelis Koukis
    sys.exit(main())