source: indico/indico/tests/runners.py @ 574b7d

burotelhello-world-walkthroughipv6v0.98-seriesv0.98.2v0.98.3v0.98b1v0.98b2v0.99v1.0v1.1
Last change on this file since 574b7d was 574b7d, checked in by Pedro Ferreira <jose.pedro.ferreira@…>, 3 years ago

[IMP] Test Framework: Several improvements

  • Parallel selenium grid tests are now possible;
  • Refactored I/O handling methods;
  • Changed selenium grid data structure;
  • Fixes plugin tests;
  • "Specify" and "HTML" options restructured;
  • Added some needed init.py;
  • Some more linting;
  • Added some selenium helpers;
  • Added Ajax debugging capability to Presentation;
  • Better file path computing functions (borrowed);
  • JSUnit and JSLint tests adapted;
  • Changed --full-output to --silent;
  • Property mode set to 100644
File size: 27.4 KB
Line 
1# -*- coding: utf-8 -*-
2##
3## $Id$
4##
5## This file is part of CDS Indico.
6## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 CERN.
7##
8## CDS Indico is free software; you can redistribute it and/or
9## modify it under the terms of the GNU General Public License as
10## published by the Free Software Foundation; either version 2 of the
11## License, or (at your option) any later version.
12##
13## CDS Indico is distributed in the hope that it will be useful, but
14## WITHOUT ANY WARRANTY; without even the implied warranty of
15## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16## General Public License for more details.
17##
18## You should have received a copy of the GNU General Public License
19## along with CDS Indico; if not, write to the Free Software Foundation, Inc.,
20## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
21
22"""
23This module defines the TestRunners that are included by default by indico.tests:
24
25 * UnitTestRunner
26 * FunctionalTestRunner
27 * GridTestRunner
28 * PylintTestRunner
29 * JSLintTestRunner
30 * JSUnitTestRunner
31
32"""
33
34# System modules
35import commands, os, socket, subprocess, tempfile, threading
36
37# Python stdlib
38import time, urllib2
39
40# Test modules
41import nose, figleaf, figleaf.annotate_html
42from selenium import selenium
43
44from indico.tests.config import TestConfig
45from indico.tests.base import BaseTestRunner, Option
46from indico.tests.util import openBrowser, relpathto
47
48__all__ = [
49    'UnitTestRunner',
50    'FunctionalTestRunner',
51    'GridTestRunner',
52    'PylintTestRunner',
53    'JSLintTestRunner',
54    'JSUnitTestRunner'
55    ]
56
57JSTEST_CFG_FILE = "builtConf.conf"
58
59class CoverageBaseTestOption(Option):
60    """
61    This class can be used in order to add an
62    optional code coverage analysis
63    """
64
65    def __init__(self, value):
66        Option.__init__(self, value)
67        self.coverageDir = None
68
69    def final_message(self, __):
70        """
71        just a short message
72        """
73        self._info("Code coverage report generated at "
74                   "%s/index.html\n" % self.coverageDir)
75
76    def shouldExecute(self):
77        return self.value
78
79
80class CoveragePythonTestOption(CoverageBaseTestOption):
81    """
82    Python Coverage Tests
83    """
84
85    def __init__(self, value):
86        CoverageBaseTestOption.__init__(self, value)
87
88    def pre_run(self, __):
89        """
90        starts figleaf
91        """
92
93        figleaf.start()
94
95    def post_run(self, runner):
96        """
97        stops figleaf and returns a report
98        """
99
100        figleaf.stop()
101        coverageOutput = figleaf.get_data().gather_files()
102        self.coverageDir = os.path.join(runner.setupDir, 'report', 'pycoverage')
103
104        # check if there's a dir first
105        if not os.path.exists(self.coverageDir):
106            os.mkdir(self.coverageDir)
107
108        figleaf.annotate_html.report_as_html(coverageOutput,
109                                             self.coverageDir, [], {})
110
111        # open a browser window with the report
112        openBrowser(runner.config.getBrowserPath(), os.path.join(
113            self.coverageDir, "index.html"))
114
115
116
117
118
119class UnitTestRunner(BaseTestRunner):
120    """
121    Python Unit Tests
122
123    Using nosetest
124    """
125
126    _runnerOptions = {'silent': Option,
127                      'coverage': CoveragePythonTestOption,
128                      'specify': Option}
129
130    def _run(self):
131        #coverage = CoverageTestRunner.getInstance()
132
133        #if coverage:
134        #    coverage.start()
135
136        #retrieving tests from tests folder
137        args = ['nose', '--nologcapture',  '--logging-clear-handlers', \
138                '--with-id', '-v', '-s']
139
140        specific = self.options.valueOf('specify')
141
142        if specific:
143            args.append("indico.tests.python.unit.%s" % specific)
144        else:
145            args.append(os.path.join(self.setupDir, 'python', 'unit'))
146            # retrieving tests from plugins folder
147            for folder in BaseTestRunner.walkThroughFolders(
148                os.path.join(self.setupDir, '..', 'MaKaC', 'plugins'),
149                "/tests/python/unit"):
150                args.append(folder)
151
152        result = nose.run(argv = args)
153
154        #if coverage:
155        #    coverage.stop()
156
157        return result
158
159    def walkThroughPluginsFolders(self):
160        """
161        Goes throught the plugin directories, and adds
162        existing unit test dirs
163        """
164        rootPluginsPath = os.path.join(self.setupDir,
165                                       '..',
166                                       'MaKaC',
167                                       'plugins')
168        foldersArray = []
169
170        for root, __, ___ in os.walk(rootPluginsPath):
171            if root.endswith("/tests/python/unit") > 0:
172                foldersArray.append(root)
173
174        return foldersArray
175
176
177class FunctionalTestRunner(BaseTestRunner):
178    """
179    Functional Tests
180
181    Using selenium
182    """
183
184    _runnerOptions = {'silent': Option,
185                      'record': Option,
186                      'specify': Option}
187
188
189    def __init__(self, **kwargs):
190        BaseTestRunner.__init__(self, **kwargs)
191        self.child = None
192
193    def _runSeleniumCycle(self):
194        """
195        Run selenium over the existing test suite (or a specific test)
196        """
197
198        try:
199            if not self._startSeleniumServer():
200                return ('[ERR] Could not start functional tests because selenium'
201                        ' server cannot be started.\n')
202
203            args = ['nose', '--nologcapture', '--logging-clear-handlers',
204                    '-v']
205
206            specific = self.options.valueOf('specify')
207
208            # if a particular test was specified
209            if specific:
210                args.append("indico.tests.python.functional.%s" % specific)
211            else:
212                args.append(os.path.join(self.setupDir, 'python', 'functional'))
213                # retrieving tests from plugins folder
214                for folder in BaseTestRunner.walkThroughFolders(
215                    os.path.join(self.setupDir, '..', 'MaKaC', 'plugins'),
216                    "/tests/python/functional"):
217                    args.append(folder)
218
219            result = nose.run(argv = args)
220
221        except Exception, e:
222            raise e
223        finally:
224            self._stopSeleniumServer()
225
226        return result
227
228    def _run(self):
229
230        if self.options.valueOf('record'):
231            raw_input("Press [ENTER] to finish recording... ")
232            result = False
233        else:
234            result = self._runSeleniumCycle()
235
236        return result
237
238    def walkThroughPluginsFolders(self):
239        """
240        Goes throught the plugin directories, and adds
241        existing functional test dirs
242        """
243        rootPluginsPath = os.path.join(self.setupDir, '..', 'MaKaC', 'plugins')
244        foldersArray = []
245
246        for root, __, ___ in os.walk(rootPluginsPath):
247            if root.endswith("/tests/python/functional") > 0:
248                foldersArray.append(root)
249
250        return foldersArray
251
252    def _startSeleniumServer(self):
253        """
254        starts the selenium server
255        """
256        started = True
257
258        self._info("Starting Selenium Server")
259
260        try:
261            self.child = subprocess.Popen(["java", "-jar",
262                                      os.path.join(self.setupDir,
263                                                   'python',
264                                                   'functional',
265                                                   TestConfig.getInstance().
266                                                   getSeleniumFilename())],
267                                      stdout=None)
268
269        except OSError, e:
270            return ("[ERR] Could not start selenium server - command \"java\""
271                    " needs to be in your PATH. (%s)\n" % e)
272        except KeyError:
273            return "[ERR] Please specify a SeleniumFilename in tests.conf\n"
274
275        self._info("Starting Selenium RC")
276
277        sel = selenium("localhost", 4444, "*firefox", "http://www.cern.ch/")
278        for i in range(5):
279            try:
280                #testing if the selenium server has started
281                time.sleep(1)
282                sel.start()
283                sel.stop()
284
285                #server has started
286                break
287            except socket.error:
288                print 'Selenium has not started yet. Attempt #%s\n' % (i+1)
289                time.sleep(5)
290        else:
291            started = False
292
293        return started
294
295    def _stopSeleniumServer(self):
296        """
297        stops the selenium server
298        """
299        self.child.kill()
300
301
302class GridEnvironmentRunner(threading.Thread):
303    """
304    Rspresents a specific grid environment (FF Linux, IE Windows, etc...)
305    """
306
307    def __init__(self, gridData, setupDir, resultEntry):
308        threading.Thread.__init__(self)
309        self.setupDir = setupDir
310        self.gridData = gridData
311        self.result = None
312        self.resultEntry = resultEntry
313
314    def run(self):
315
316        self.result = nose.run(argv=['nose', '--nologcapture', '--nocapture',
317                                     '--logging-clear-handlers', '-v',
318                                     os.path.join(self.setupDir, 'python',
319                                                  'functional')])
320
321        self.resultEntry['success'] = self.result
322
323    def stop(self):
324        """
325        Stop the GridEnvironmentRunner, by joining its thread
326        """
327
328        self.join()
329
330        if self.result:
331            return True
332        else:
333            return False
334
335    @classmethod
336    def getGridData(cls):
337        """
338        returns the data that is stored by the thread, if any
339        """
340
341        thread = threading.currentThread()
342
343        if hasattr(thread, 'gridData'):
344            return thread.gridData
345        else:
346            return None
347
348class GridTestRunner(BaseTestRunner):
349    """
350    Selenium Grid Tests
351    """
352
353    _runnerOptions = {'silent': Option,
354                      'parallel': Option,
355                      'specify': Option }
356
357    def __init__(self, **kwargs):
358
359        BaseTestRunner.__init__(self, **kwargs)
360
361        try:
362            testConf = TestConfig.getInstance()
363            self.hubEnv = testConf.getHubEnv()
364            self.configExists = True
365        except KeyError:
366            self.configExists = False
367
368        self.gridData = None
369        specifiedEnv = self.options.valueOf('specify')
370
371        if specifiedEnv:
372            self.hubEnv = [specifiedEnv]
373
374    def _runSerial(self, resultDict, testConf):
375        """
376        Run the tests one after the other
377        """
378
379        for envName in self.hubEnv:
380            envRunner = self._runEnv(envName, resultDict, testConf)
381            envRunner.stop()
382
383
384    def _runParallel(self, resultDict, testConf):
385        """
386        Run all the tests at the same time
387        """
388
389        # launch every environment
390        for envName in self.hubEnv:
391            self._runEnv(envName, resultDict, testConf)
392
393        # give it some time to start up
394        time.sleep(1)
395
396        # wait so that there are no more runner threads executing
397        while(len(list(thread for thread in threading.enumerate()
398                       if isinstance(thread, GridEnvironmentRunner))) > 0):
399            time.sleep(1)
400
401
402    def _runEnv(self, envName, resultDict, testConf):
403        """
404        Run a specific test environment, spawning a GridEnvironmentRunner
405        """
406        self._info("Starting env %s" % envName)
407
408        self.gridData = GridData(testConf.getHubURL(),
409                                 testConf.getHubPort(),
410                                 envName,
411                                 active = True)
412
413        resultEntry = resultDict[envName] = {}
414
415        envRunner = GridEnvironmentRunner(self.gridData, self.setupDir, resultEntry)
416        envRunner.start()
417
418        return envRunner
419
420
421    def _run(self):
422
423        resultDict = {}
424        result = True
425
426        if not self.configExists:
427            return "[ERR] Grid - Please specify hub configuration in tests.conf\n"
428
429        try:
430            testConf = TestConfig.getInstance()
431
432            # Ping server, just to know it is alive
433            urllib2.urlopen("http://%s:%s/heartbeat" % (testConf.getHubURL(),
434                                                        testConf.getHubPort()))
435
436            if self.options.valueOf('parallel'):
437                self._runParallel(resultDict, testConf)
438            else:
439                self._runSerial(resultDict, testConf)
440
441            for name, resultEntry in resultDict.iteritems():
442                if resultEntry['success']:
443                    resultStr = 'OK'
444                else:
445                    resultStr = 'FAIL'
446                    result = False
447                print "%s\t %s" % (name, resultStr)
448
449        except socket.error:
450            self._error("[ERR] Selenium Grid - Connection refused, check your "
451                        "hub's settings (%s:%s)" % \
452                        (testConf.getHubURL(), testConf.getHubPort()))
453            return False
454        except urllib2.URLError, e:
455            self._error("[ERR] Selenium Grid - Hub is probably down " \
456                        "(%s:%s) (%s)\n" % \
457                        (testConf.getHubURL(), testConf.getHubPort(), e))
458            return False
459        except Exception, e:
460            self._error(e)
461            return False
462
463        return result
464
465class GridData(object):
466    """
467    Provides informations for selenium grid, data are set from Class Grid
468    and are used by seleniumTestCase.py.
469    Because nosetest cannot forward the arguments to selenium grid.
470    """
471
472    def __init__(self, host, port, env, active = False):
473        self.active = active
474        self.host = host
475        self.port = port
476        self.env = env
477
478
479class HTMLOption(Option):
480    """
481    Represents the option that allows HTML reports to be generated
482    instead of console output
483    """
484
485    def __init__(self, value):
486
487        Option.__init__(self, value)
488        self.tmpFile = None
489
490    def prepare_outstream(self, runner):
491        """
492        Forward the output to either a file or the process output
493        """
494
495        if self.value:
496            __, filePath = tempfile.mkstemp()
497            self.tmpFile = open(filePath, 'w+b')
498            runner.outStream = self.tmpFile
499        else:
500            # for regular text, just use a pipe
501            runner.outStream = subprocess.PIPE
502
503    def write_report(self, runner, fileName, content):
504        """
505        Open the browser or write an actual report, depending on the state
506        of the option
507        """
508        if self.value:
509            self.tmpFile.close()
510            # open a browser window with the report
511            openBrowser(runner.config.getBrowserPath(), self.tmpFile.name)
512        else:
513            # for non-html output, use the normal mechanisms
514            runner.writeNormalReport(fileName, content)
515
516
517class PylintTestRunner(BaseTestRunner):
518    """
519    Pylint
520    """
521
522    _runnerOptions = {'silent': Option,
523                      'html': HTMLOption}
524
525    def __init__(self, **kwargs):
526
527        BaseTestRunner.__init__(self, **kwargs)
528        self.outStream = None
529
530    def _run(self):
531
532        fileList = self.config.getPylintFiles()
533
534        try:
535            # while we have MaKaC, we have to keep this extra path
536            extraPath = os.path.join(self.setupDir, '..')
537            os.environ['PYTHONPATH'] = "%s:%s" % (extraPath,
538                                                  os.environ.get('PYTHONPATH',''))
539
540            # Prepare the args for Pylint
541            args = ["pylint", "--rcfile=%s" %
542                    os.path.join(self.setupDir,
543                                 'python',
544                                 'pylint',
545                                 'pylint.conf')
546                    ] + fileList
547
548            if self.options.valueOf('html'):
549                args += ['-f', 'html']
550
551            # will set self.outStream
552            self._callOptions('prepare_outstream')
553
554            pylintProcess = subprocess.Popen(
555                args,
556                stdout = self.outStream,
557                stderr = subprocess.PIPE)
558
559            # for regular aoutput, redirect the out pipe to stdout
560            if not self.options.valueOf('html'):
561                self._redirectPipeToStdout(pylintProcess.stdout)
562
563            # stderr always goes to the same place
564            self._redirectPipeToStdout(pylintProcess.stderr)
565
566            # wait pylint to finish
567            pylintProcess.wait()
568
569        except OSError, e:
570            self._error("[ERR] Could not start Source Analysis - "
571                        "command \"pylint\" needs to be in your PATH. (%s)\n" % e)
572            return False
573
574        return True
575
576    def _writeReport(self, fileName, content):
577
578        # overloaded just to handle the case of HTML reports
579        self._callOptions('write_report', fileName, content)
580
581    def writeNormalReport(self, fileName, content):
582        """
583        Just call the parent report writing method
584        (used from HTMLOption)
585        """
586        BaseTestRunner._writeReport(self, fileName, content)
587
588
589class CoverageJSTestOption(CoverageBaseTestOption):
590    """
591    Python Coverage Tests
592    """
593
594    def __init__(self, value):
595        CoverageBaseTestOption.__init__(self, value)
596
597    def post_run(self, runner):
598        """
599        Creates a coverage report in HTML
600        """
601
602        #generate html for coverage
603
604        reportPath = os.path.join(runner.setupDir, 'report', 'jscoverage')
605        genOutput = commands.getstatusoutput(
606            "genhtml -o %s %s" % (reportPath,
607                                  os.path.join(reportPath,
608                                               '%s-coverage.dat' %
609                                               JSTEST_CFG_FILE)))
610
611        self.coverageDir = reportPath
612
613        if genOutput[1].find("genhtml") > -1:
614            BaseTestRunner._error("JS Unit Tests - html coverage "
615                                  "generation failed, genhtml needs to be "
616                                  "in your PATH. (%s)\n" % genOutput[1])
617        else:
618            BaseTestRunner._info("JS Coverage - report generated\n")
619            # open a browser window with the report
620            openBrowser(runner.config.getBrowserPath(), os.path.join(
621                reportPath, "index.html"))
622
623
624class JSUnitTestRunner(BaseTestRunner):
625    """
626    JS Unit Tests
627
628    Based on JSUnit
629    """
630
631    _runnerOptions = {'silent': Option,
632                      'coverage': CoverageJSTestOption,
633                      'specify': Option}
634
635    def __init__(self, **kwargs):
636        BaseTestRunner.__init__(self, **kwargs)
637        self.coverage = self.options.valueOf('coverage')
638        self.specify = self.options.valueOf('specify')
639
640    def _run(self):
641
642        #conf file used at run time
643
644        try:
645            #Starting js-test-driver server
646            server = subprocess.Popen(["java", "-jar",
647                                       os.path.join(self.setupDir,
648                                                    'javascript',
649                                                    'unit',
650                                                    TestConfig.getInstance().
651                                                    getJSUnitFilename()),
652                                        "--port",
653                                        "9876",
654                                        "--browser",
655                                        "firefox"],
656                                        stdout=subprocess.PIPE,
657                                        stderr=subprocess.PIPE)
658            time.sleep(2)
659
660            #constructing conf file depending on installed plugins and
661            #coverage activation
662
663            success = self.buildConfFile(JSTEST_CFG_FILE, self.coverage)
664
665            if success != "":
666                self._error(success)
667                return False
668
669            #switching directory to run the tests
670            os.chdir(os.path.join(self.setupDir, 'javascript', 'unit'))
671
672            #check if server is ready
673            for i in range(5):
674                jsDryRun = commands.getstatusoutput(("java -jar "
675                                             "%s"
676                                             " --config "
677                                             "%s"
678                                             " --tests Fake.dryRun") %\
679                                             (TestConfig.getInstance().
680                                              getJSUnitFilename(),
681                                              JSTEST_CFG_FILE))
682                if jsDryRun[1].startswith("No browsers were captured"):
683                    print ("Js-test-driver server has not started yet. "
684                           "Attempt #%s\n") % (i+1)
685                    time.sleep(5)
686                else:
687                    #server is ready
688                    break
689            else:
690                return ('[ERR] Could not start js unit tests because '
691                        'js-test-driver server cannot be started.\n')
692
693            #setting tests to run
694            toTest = ""
695            if self.specify:
696                toTest = self.specify
697            else:
698                toTest = "all"
699
700            command = ("java -jar %s "
701                            "--config %s "
702                            "--verbose "
703                            "--tests %s ") % \
704                            (TestConfig.getInstance().getJSUnitFilename(),
705                             JSTEST_CFG_FILE,
706                             toTest)
707
708            if self.coverage:
709                # path relative to the jar file
710                command += "--testOutput %s" % \
711                           os.path.join('..', '..', 'report', 'jscoverage')
712
713            #running tests
714            jsTest = commands.getoutput(command)
715
716            print jsTest
717
718            #delete built conf file
719            os.unlink(JSTEST_CFG_FILE)
720
721            #restoring directory
722            os.chdir(self.setupDir)
723
724        except OSError, e:
725            return ("[ERR] Could not start js-test-driver server - command "
726                    "\"java\" needs to be in your PATH. (%s)\n" % e)
727        except KeyError:
728            return "[ERR] Please specify a JSUnitFilename in tests.conf\n"
729
730        #stopping the server
731        server.kill()
732        return True
733
734    def buildConfFile(self, confFilePath, coverage):
735        """
736        Builds a driver config file
737        """
738        confTemplateDir = os.path.join(self.setupDir,
739                                        'javascript',
740                                        'unit')
741        confTemplatePath = os.path.join(confTemplateDir, 'confTemplate.conf')
742
743        absoluteTestsDir = os.path.join(self.setupDir,
744                                           "javascript",
745                                           "unit",
746                                           "tests")
747
748        absolutePluginDir = os.path.join(self.setupDir,
749                                            "..",
750                                            "..",
751                                            "indico",
752                                            "MaKaC",
753                                            "plugins")
754
755        try:
756            #lines needed to activate coverage plugin
757            coverageConf = """\nplugin:
758  - name: \"coverage\"
759    jar: \"plugins/%s\"
760    module: \"com.google.jstestdriver.coverage.CoverageModule\"""" % \
761        TestConfig.getInstance().getJSCoverageFilename()
762        except KeyError:
763            return "Please, specify a JSCoverageFilename in tests.conf\n"
764
765
766        try:
767            #retrieve and store the template file
768            f = open(confTemplatePath)
769            confTemplate = f.read()
770            f.close()
771
772            #adding tests files from tests folder
773            for root, __, files in os.walk(absoluteTestsDir):
774                for name in files:
775                    if name.endswith(".js"):
776                        absoluteFilePath = os.path.join(root, name)
777                        relativeFilePath = relpathto(confTemplateDir,
778                                                     absoluteFilePath)
779
780                        confTemplate += "\n  - %s" % os.path.join(relativeFilePath)
781
782
783            #adding plugins test files
784            for root, __, files in os.walk(absolutePluginDir):
785                for name in files:
786                    if name.endswith(".js") and \
787                                          root.find("/tests/javascript/unit") > 0:
788                        absoluteFilePath = os.path.join(root, name)
789                        relativeFilePath = relpathto(confTemplateDir,
790                                                     absoluteFilePath)
791
792                        confTemplate += "\n  - %s" % os.path.join('..',
793                                                                  '..',
794                                                                  relativeFilePath)
795
796            #addind coverage if necessary
797            if coverage:
798                confTemplate += coverageConf
799
800            #writing the complete configuration in a file
801            confFile = open(os.path.join(self.setupDir, 'javascript', 'unit',
802                                         confFilePath), 'w')
803            confFile.write(confTemplate)
804            confFile.close()
805
806            return ""
807        except IOError, e:
808            return "JS Unit Tests - Could not open a file. (%s)" % e
809
810class JSLintTestRunner(BaseTestRunner):
811    """
812    JSLint
813    """
814
815    def _run(self):
816
817        # Folders which are not going to be scanned.
818        # Files are going to be find recursively in the other folders
819        import sets
820        blackList = sets.Set(['pack', 'Loader.js', 'Common', 'i18n'])
821
822        #checking if rhino is accessible
823        statusOutput = commands.getstatusoutput("rhino -?")
824        if statusOutput[1].find("rhino: not found") > -1:
825            return ("[ERR] Could not start JS Source Analysis - command "
826                    "\"rhino\" needs to be in your PATH. (%s)\n" % statusOutput[1])
827
828        #constructing a list of folders to scan
829        folderNames = []
830
831        indicoDir = os.path.join(self.setupDir, '..', '..', 'indico')
832
833        fileList  = os.listdir(os.path.join(indicoDir,
834                                            'htdocs',
835                                            'js',
836                                            'indico'))
837        for name in fileList:
838            if not (name in blackList):
839                folderNames.append(name)
840
841        #Scanning Indico core
842        for folderName in folderNames:
843            self.runJSLint(
844                os.path.join(indicoDir, 'htdocs', 'js', 'indico'),
845                folderName)
846
847        #Scanning plugins js files
848        return self.runJSLint(
849            os.path.join(indicoDir, 'MaKaC', 'plugins'))
850
851
852    def runJSLint(self, path, folderRestriction=''):
853        """
854        runs the actual JSLint command
855        """
856
857        for root, __, files in os.walk(os.path.join(self.setupDir,
858                                                    path,
859                                                    folderRestriction)):
860            for name in files:
861                if name.endswith(".js"):
862                    filename = os.path.join(root, name)
863                    self._info("Scanning %s" % filename)
864                    output = commands.getstatusoutput("rhino %s %s" %
865                                                      (os.path.join(
866                                                                self.setupDir,
867                                                                'javascript',
868                                                                'jslint',
869                                                                'jslint.js'),
870                                                       filename))
871                    print output[1]
872
873                    if output[0] != 0:
874                        return False
875        return True
876
Note: See TracBrowser for help on using the repository browser.