source: indico/indico/tests/core.py @ f397bb

hello-world-walkthroughipv6v0.98-seriesv0.98.2v0.98.3v0.99v1.0v1.1
Last change on this file since f397bb was f397bb, checked in by Pedro Ferreira <jose.pedro.ferreira@…>, 13 months ago

[IMP] Make fake SMTPd choose a free port

  • Property mode set to 100644
File size: 8.3 KB
Line 
1# -*- coding: utf-8 -*-
2##
3## This file is part of CDS Indico.
4## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 CERN.
5##
6## CDS Indico is free software; you can redistribute it and/or
7## modify it under the terms of the GNU General Public License as
8## published by the Free Software Foundation; either version 2 of the
9## License, or (at your option) any later version.
10##
11## CDS Indico is distributed in the hope that it will be useful, but
12## WITHOUT ANY WARRANTY; without even the implied warranty of
13## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14## General Public License for more details.
15##
16## You should have received a copy of the GNU General Public License
17## along with CDS Indico; if not, write to the Free Software Foundation, Inc.,
18## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
19
20# pylint: disable-msg=W0401
21
22"""
23This is the very core of indico.tests
24Here is defined the TestManager class, that provides a single point of access
25to the outside world.
26"""
27
28# System modules
29import os, sys, shutil, signal, commands, tempfile, pkg_resources
30
31# Database
32import transaction
33from MaKaC.common.db import DBMgr
34
35# Indico
36import indico
37from indico.util.console import colored
38from indico.tests.config import TestConfig
39from indico.tests.base import TestOptionException, FakeMailThread
40from indico.tests.runners import *
41
42# Indico legacy
43from MaKaC.common.Configuration import Config
44
45
46TEST_RUNNERS = {'unit': UnitTestRunner,
47                'functional': FunctionalTestRunner,
48                'pylint': PylintTestRunner,
49                'jsunit': JSUnitTestRunner,
50                'jslint': JSLintTestRunner}
51
52
53class TestManager(object):
54    """
55    Main class, the heart of the test API.
56    Launches all the tests according to the parameters that are passed
57    """
58
59    __instance = None
60
61    def __init__(self):
62        """
63        Initializes the object
64        """
65        self.dbmgr = None
66        self.zeoServer = None
67        self.tempDirs = {}
68        self.dbFolder = None
69
70    @staticmethod
71    def _title(text):
72        """
73        Prints an title
74        """
75        print colored("-- " + str(text), 'yellow', attrs=['bold'])
76
77    @staticmethod
78    def _info(message):
79        """
80        Prints an info message
81        """
82        print colored("-- " + str(message), 'cyan')
83
84    @staticmethod
85    def _error(message):
86        """
87        Prints an info message
88        """
89        print colored("-- " + str(message), 'red')
90
91    @staticmethod
92    def _debug(message):
93        """
94        Prints an info message
95        """
96        print colored("-- " + str(message), 'grey')
97
98    def main(self, testsToRun, options):
99        """
100        Runs the main test cycle, iterating over all the TestRunners available
101
102         * testsToRun - a list of strings specifying which tests to run
103         * options - test options (such as verbosity...)
104        """
105        result = False
106        killself = options.pop('killself', False)
107
108        TestManager._title("Starting test framework\n")
109
110        # the SMTP server will choose a free port
111        smtpAddr = self._startSMTPServer()
112        self._setFakeConfig({
113                "SmtpServer": smtpAddr
114                })
115        self._startManageDB()
116
117        try:
118            for test in testsToRun:
119                if test in TEST_RUNNERS:
120                    try:
121                        result = TEST_RUNNERS[test](**options).run()
122                    except TestOptionException, e:
123                        TestManager._error(e)
124                else:
125                    print colored("[ERR] Test set '%s' does not exist. "
126                                  "It has to be added in the TEST_RUNNERS variable\n",
127                                  'red') % test
128        finally:
129            # whatever happens, clean this mess up
130            self._stopManageDB(killself)
131            self._stopSMTPServer()
132
133        if killself:
134            # Forcefully kill ourselves. This avoids waiting for the db to shutdown (SLOW)
135            self._info('Committing suicide to avoid waiting for slow database shutdown')
136            os.kill(os.getpid(), 9)
137
138        if result:
139            return 0
140        else:
141            return -1
142
143    def _setFakeConfig(self, custom):
144        """
145        Sets a fake configuration for the current process, using a temporary directory
146        """
147        config = Config.getInstance()
148        test_config = TestConfig.getInstance()
149
150        temp = tempfile.mkdtemp(prefix="indico_")
151        self._info('Using %s as temporary dir' % temp)
152
153        os.mkdir(os.path.join(temp, 'log'))
154        os.mkdir(os.path.join(temp, 'archive'))
155
156        indicoDist = pkg_resources.get_distribution('indico')
157        htdocsDir = indicoDist.get_resource_filename('indico', 'indico/htdocs')
158        etcDir = indicoDist.get_resource_filename('indico', 'etc')
159
160        # minimal defaults
161        defaults = {
162            'BaseURL': 'http://{0}:{1}'.format(test_config.getWebServerHost(),
163                                               test_config.getWebServerPort()),
164            'BaseSecureURL': '',
165            'UseXSendFile': False,
166            'AuthenticatorList': ['Local'],
167            'SmtpServer': ('localhost', 58025),
168            'SmtpUseTLS': 'no',
169            'DBConnectionParams': ('localhost', TestConfig.getInstance().getFakeDBPort()),
170            'LogDir': os.path.join(temp, 'log'),
171            'XMLCacheDir': os.path.join(temp, 'cache'),
172            'HtdocsDir': htdocsDir,
173            'ArchiveDir': os.path.join(temp, 'archive'),
174            'UploadedFilesTempDir': os.path.join(temp, 'tmp'),
175            'ConfigurationDir': etcDir
176            }
177
178        defaults.update(custom)
179
180        # set defaults
181        config.reset(defaults)
182
183        Config.setInstance(config)
184        self._cfg = config
185
186        # re-configure logging and template generator, so that paths are updated
187        from MaKaC.common import TemplateExec
188        from MaKaC.common.logger import Logger
189        TemplateExec.mako = TemplateExec._define_lookup()
190        Logger.reset()
191
192
193################## Start of DB Managing functions ##################
194    def _startManageDB(self):
195        port = TestConfig.getInstance().getFakeDBPort()
196
197        self._info("Starting fake DB in port %s" % port)
198        self._startFakeDB('localhost', port)
199
200    def _stopManageDB(self, killself=False):
201        """
202        Stops the temporary DB
203        """
204        self._stopFakeDB(killself)
205
206    def _startFakeDB(self, zeoHost, zeoPort):
207        """
208        Starts a temporary DB in a different port
209        """
210
211        print colored("-- Starting a test DB", "cyan")
212
213        self._createNewDBFile()
214        self.zeoServer = TestManager._createDBServer(
215            os.path.join(self.dbFolder, "Data.fs"),
216            zeoHost, zeoPort)
217
218    def _stopFakeDB(self, killself=False):
219        """
220        Stops the temporary DB
221        """
222
223        print colored("-- Stopping test DB", "cyan")
224
225        try:
226            self.zeoServer.shutdown(killself)
227            self._removeDBFile()
228        except OSError, e:
229            print ("Problem terminating ZEO Server: " + str(e))
230
231    def _createNewDBFile(self):
232        """
233        Creates a new DB file for a temporary DB
234        """
235        from ZODB import FileStorage, DB
236        savedDir = os.getcwd()
237        self.dbFolder = tempfile.mkdtemp()
238        os.chdir(self.dbFolder)
239
240        storage = FileStorage.FileStorage("Data.fs")
241        db = DB(storage)
242        connection = db.open()
243
244        transaction.commit()
245
246        connection.close()
247        db.close()
248        storage.close()
249        os.chdir(savedDir)
250
251    def _removeDBFile(self):
252        """
253        Removes the files of the temporary DB
254        """
255        shutil.rmtree(self.dbFolder)
256
257    @classmethod
258    def _startSMTPServer(cls):
259        cls._smtpd = FakeMailThread(('localhost', 0))
260        cls._smtpd.start()
261        addr = cls._smtpd.get_addr()
262        cls._info("Started fake SMTP server at %s:%s" % addr)
263        return addr
264
265    @classmethod
266    def _stopSMTPServer(cls):
267        cls._smtpd.close()
268
269    @staticmethod
270    def _createDBServer(dbFile, host, port):
271        """
272        Creates a fake DB server for testing
273        """
274
275        # run a DB in a child process
276        from indico.tests.util import TestZEOServer
277        server = TestZEOServer(port, dbFile, hostname = host)
278        server.daemon = True
279        server.start()
280        return server
281
282################## End of DB Managing functions ##################
Note: See TracBrowser for help on using the repository browser.