Hello community,
here is the log from the commit of package python-salt-testing for openSUSE:Factory checked in at 2013-11-12 15:22:48
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-salt-testing (Old)
and /work/SRC/openSUSE:Factory/.python-salt-testing.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-salt-testing"
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-salt-testing/python-salt-testing.changes 2013-10-25 11:31:14.000000000 +0200
+++ /work/SRC/openSUSE:Factory/.python-salt-testing.new/python-salt-testing.changes 2013-11-12 15:22:49.000000000 +0100
@@ -1,0 +2,12 @@
+Tue Nov 12 06:54:27 UTC 2013 - aboe76@gmail.com
+
+- Updated to version 0.5.3
+- Dropped HTML unit test reports support which was
+ a requirement for EPEL, I think...
+- Added support to run the tests suite within a Docker container
+ (as long as it's properly configured on the user's system)
+- Added a minimal string format checker for PyLint, it basicaly
+ reject any string which calls .format and it has format holders
+ but they are not indexed, ie 'Foo {}'.format(bar)
+
+-------------------------------------------------------------------
Old:
----
SaltTesting-0.5.2.tar.gz
New:
----
SaltTesting-0.5.3.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-salt-testing.spec ++++++
--- /var/tmp/diff_new_pack.jmG49E/_old 2013-11-12 15:22:49.000000000 +0100
+++ /var/tmp/diff_new_pack.jmG49E/_new 2013-11-12 15:22:49.000000000 +0100
@@ -17,7 +17,7 @@
Name: python-salt-testing
-Version: 0.5.2
+Version: 0.5.3
Release: 0
Summary: Testing tools needed in the several Salt Stack projects
License: Apache-2.0
++++++ SaltTesting-0.5.2.tar.gz -> SaltTesting-0.5.3.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/SaltTesting-0.5.2/AUTHORS.rst new/SaltTesting-0.5.3/AUTHORS.rst
--- old/SaltTesting-0.5.2/AUTHORS.rst 2013-10-24 12:57:42.000000000 +0200
+++ new/SaltTesting-0.5.3/AUTHORS.rst 2013-11-12 06:14:36.000000000 +0100
@@ -7,6 +7,7 @@
========================== ===================== ============================
Name Nick Email
========================== ===================== ============================
+Erik Johnson terminalmage erik@saltstack.com
Henrik Holmboe holmboe
Niels Abspoel aboe76
Pedro Algarvio s0undt3ch pedro@algarvio.me
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/SaltTesting-0.5.2/PKG-INFO new/SaltTesting-0.5.3/PKG-INFO
--- old/SaltTesting-0.5.2/PKG-INFO 2013-10-24 13:02:48.000000000 +0200
+++ new/SaltTesting-0.5.3/PKG-INFO 2013-11-12 06:22:43.000000000 +0100
@@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: SaltTesting
-Version: 0.5.2
+Version: 0.5.3
Summary: Required testing tools needed in the several Salt Stack projects.
Home-page: http://saltstack.org
Author: Pedro Algarvio
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/SaltTesting-0.5.2/SaltTesting.egg-info/PKG-INFO new/SaltTesting-0.5.3/SaltTesting.egg-info/PKG-INFO
--- old/SaltTesting-0.5.2/SaltTesting.egg-info/PKG-INFO 2013-10-24 13:02:44.000000000 +0200
+++ new/SaltTesting-0.5.3/SaltTesting.egg-info/PKG-INFO 2013-11-12 06:22:26.000000000 +0100
@@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: SaltTesting
-Version: 0.5.2
+Version: 0.5.3
Summary: Required testing tools needed in the several Salt Stack projects.
Home-page: http://saltstack.org
Author: Pedro Algarvio
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/SaltTesting-0.5.2/SaltTesting.egg-info/SOURCES.txt new/SaltTesting-0.5.3/SaltTesting.egg-info/SOURCES.txt
--- old/SaltTesting-0.5.2/SaltTesting.egg-info/SOURCES.txt 2013-10-24 13:02:44.000000000 +0200
+++ new/SaltTesting-0.5.3/SaltTesting.egg-info/SOURCES.txt 2013-11-12 06:22:26.000000000 +0100
@@ -14,7 +14,6 @@
salttesting/mock.py
salttesting/unit.py
salttesting/version.py
-salttesting/ext/HTMLTestRunner.py
salttesting/ext/__init__.py
salttesting/ext/console.py
salttesting/ext/os_data.py
@@ -22,4 +21,6 @@
salttesting/parser/cover.py
salttesting/pylintplugins/__init__.py
salttesting/pylintplugins/pep263.py
-salttesting/pylintplugins/pep8.py
\ No newline at end of file
+salttesting/pylintplugins/pep8.py
+salttesting/pylintplugins/string_format.py
+salttesting/pylintplugins/strings.py
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/SaltTesting-0.5.2/salttesting/ext/HTMLTestRunner.py new/SaltTesting-0.5.3/salttesting/ext/HTMLTestRunner.py
--- old/SaltTesting-0.5.2/salttesting/ext/HTMLTestRunner.py 2013-10-24 12:57:42.000000000 +0200
+++ new/SaltTesting-0.5.3/salttesting/ext/HTMLTestRunner.py 1970-01-01 01:00:00.000000000 +0100
@@ -1,833 +0,0 @@
-"""
-A TestRunner for use with the Python unit testing framework. It
-generates a HTML report to show the result at a glance.
-
-The simplest way to use this is to invoke its main method. E.g.
-
- import unittest
- import HTMLTestRunner
-
- ... define your tests ...
-
- if __name__ == '__main__':
- HTMLTestRunner.main()
-
-
-For more customization options, instantiates a HTMLTestRunner object.
-HTMLTestRunner is a counterpart to unittest's TextTestRunner. E.g.
-
- # output to a file
- fp = file('my_report.html', 'wb')
- runner = HTMLTestRunner.HTMLTestRunner(
- stream=fp,
- title='My unit test',
- description='This demonstrates the report output by HTMLTestRunner.'
- )
-
- # Use an external stylesheet.
- # See the Template_mixin class for more customizable options
- runner.STYLESHEET_TMPL = '<link rel="stylesheet" href="my_stylesheet.css" type="text/css">'
-
- # run the test
- runner.run(my_test_suite)
-
-
-------------------------------------------------------------------------
-Copyright (c) 2004-2007, Wai Yip Tung
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-
-* Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
-* Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-* Neither the name Wai Yip Tung nor the names of its contributors may be
- used to endorse or promote products derived from this software without
- specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
-TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
-PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
-OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-"""
-
-# URL: http://tungwaiyip.info/software/HTMLTestRunner.html
-
-__author__ = "Wai Yip Tung"
-__version__ = "0.8.2"
-
-
-"""
-Change History
-
-Version 0.8.2
-* Show output inline instead of popup window (Viorel Lupu).
-
-Version in 0.8.1
-* Validated XHTML (Wolfgang Borgert).
-* Added description of test classes and test cases.
-
-Version in 0.8.0
-* Define Template_mixin class for customization.
-* Workaround a IE 6 bug that it does not treat <script> block as CDATA.
-
-Version in 0.7.1
-* Back port to Python 2.3 (Frank Horowitz).
-* Fix missing scroll bars in detail log (Podi).
-"""
-
-# TODO: color stderr
-# TODO: simplify javascript using ,ore than 1 class in the class attribute?
-
-import datetime
-import StringIO
-import sys
-import unittest
-from xml.sax import saxutils
-
-
-# ------------------------------------------------------------------------
-# The redirectors below are used to capture output during testing. Output
-# sent to sys.stdout and sys.stderr are automatically captured. However
-# in some cases sys.stdout is already cached before HTMLTestRunner is
-# invoked (e.g. calling logging.basicConfig). In order to capture those
-# output, use the redirectors for the cached stream.
-#
-# e.g.
-# >>> logging.basicConfig(stream=HTMLTestRunner.stdout_redirector)
-# >>>
-
-class OutputRedirector(object):
- """ Wrapper to redirect stdout or stderr """
- def __init__(self, fp):
- self.fp = fp
-
- def write(self, s):
- self.fp.write(s)
-
- def writelines(self, lines):
- self.fp.writelines(lines)
-
- def flush(self):
- self.fp.flush()
-
-stdout_redirector = OutputRedirector(sys.stdout)
-stderr_redirector = OutputRedirector(sys.stderr)
-
-
-
-# ----------------------------------------------------------------------
-# Template
-
-class Template_mixin(object):
- """
- Define a HTML template for report customerization and generation.
-
- Overall structure of an HTML report
-
- HTML
- +------------------------+
- |<html> |
- | <head> |
- | |
- | STYLESHEET |
- | +----------------+ |
- | | | |
- | +----------------+ |
- | |
- | </head> |
- | |
- | <body> |
- | |
- | HEADING |
- | +----------------+ |
- | | | |
- | +----------------+ |
- | |
- | REPORT |
- | +----------------+ |
- | | | |
- | +----------------+ |
- | |
- | ENDING |
- | +----------------+ |
- | | | |
- | +----------------+ |
- | |
- | </body> |
- |</html> |
- +------------------------+
- """
-
- STATUS = {
- 0: 'pass',
- 1: 'fail',
- 2: 'error',
- 3: 'skip',
- }
-
- DEFAULT_TITLE = 'Unit Test Report'
- DEFAULT_DESCRIPTION = ''
-
- # ------------------------------------------------------------------------
- # HTML Template
-
- HTML_TMPL = r"""<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
- <title>%(title)s</title>
- <meta name="generator" content="%(generator)s"/>
- <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
- %(stylesheet)s
-</head>
-<body>
-<script language="javascript" type="text/javascript"></script>
-
-%(heading)s
-%(report)s
-%(ending)s
-
-</body>
-</html>
-"""
- # variables: (title, generator, stylesheet, heading, report, ending)
-
-
- # ------------------------------------------------------------------------
- # Stylesheet
- #
- # alternatively use a <link> for external style sheet, e.g.
- # <link rel="stylesheet" href="$url" type="text/css">
-
- STYLESHEET_TMPL = """
-<style type="text/css" media="screen">
-body { font-family: verdana, arial, helvetica, sans-serif; font-size: 80%; }
-table { font-size: 100%; }
-pre { }
-
-/* -- heading ---------------------------------------------------------------------- */
-h1 {
- font-size: 16pt;
- color: gray;
-}
-.heading {
- margin-top: 0ex;
- margin-bottom: 1ex;
-}
-
-.heading .attribute {
- margin-top: 1ex;
- margin-bottom: 0;
-}
-
-.heading .description {
- margin-top: 4ex;
- margin-bottom: 6ex;
-}
-
-/* -- css div popup ------------------------------------------------------------------------ */
-a.popup_link {
-}
-
-a.popup_link:hover {
- color: red;
-}
-
-.popup_window {
- display: none;
- position: relative;
- left: 0px;
- top: 0px;
- /*border: solid #627173 1px; */
- padding: 10px;
- background-color: #E6E6D6;
- font-family: "Lucida Console", "Courier New", Courier, monospace;
- text-align: left;
- font-size: 8pt;
- width: 500px;
-}
-
-}
-/* -- report ------------------------------------------------------------------------ */
-#show_detail_line {
- margin-top: 3ex;
- margin-bottom: 1ex;
-}
-#result_table {
- width: 80%;
- border-collapse: collapse;
- border: 1px solid #777;
-}
-#header_row {
- font-weight: bold;
- color: white;
- background-color: #777;
-}
-#result_table td {
- border: 1px solid #777;
- padding: 2px;
-}
-#total_row { font-weight: bold; }
-.passClass { background-color: #6c6; }
-.failClass { background-color: #c60; }
-.errorClass { background-color: #c00; }
-.skipClass { background-color: #4BA9D1; }
-.passCase { color: #6c6; }
-.skiptCase { font-style: italic; }
-.failCase { color: #c60; font-weight: bold; }
-.errorCase { color: #c00; font-weight: bold; }
-.hiddenRow { display: none; }
-.testcase { margin-left: 2em; }
-
-
-/* -- ending ---------------------------------------------------------------------- */
-#ending {
-}
-
-</style>
-"""
-
-
-
- # ------------------------------------------------------------------------
- # Heading
- #
-
- HEADING_TMPL = """<div class='heading'>
-<h1>%(title)s</h1>
-%(parameters)s
-<p class='description'>%(description)s</p>
-</div>
-
-""" # variables: (title, parameters, description)
-
- HEADING_ATTRIBUTE_TMPL = """<p class='attribute'><strong>%(name)s:</strong> %(value)s</p>
-""" # variables: (name, value)
-
-
-
- # ------------------------------------------------------------------------
- # Report
- #
-
- REPORT_TMPL = """
-<p id='show_detail_line'>Show
-<a href='javascript:showCase(0)'>Summary</a>
-<a href='javascript:showCase(1)'>Failed</a>
-<a href='javascript:showCase(2)'>All</a>
-</p>
-<table id='result_table'>
-<colgroup>
-<col align='left' />
-<col align='right' />
-<col align='right' />
-<col align='right' />
-<col align='right' />
-<col align='right' />
-</colgroup>
-<tr id='header_row'>
- <td>Test Group/Test case</td>
- <td>Count</td>
- <td>Pass</td>
- <td>Skip</td>
- <td>Fail</td>
- <td>Error</td>
- <td>View</td>
-</tr>
-%(test_list)s
-<tr id='total_row'>
- <td>Total</td>
- <td>%(count)s</td>
- <td>%(Pass)s</td>
- <td>%(skip)s</td>
- <td>%(fail)s</td>
- <td>%(error)s</td>
- <td> </td>
-</tr>
-</table>
-""" # variables: (test_list, count, Pass, fail, error)
-
- REPORT_CLASS_TMPL = r"""
-<tr class='%(style)s'>
- <td>%(desc)s</td>
- <td>%(count)s</td>
- <td>%(Pass)s</td>
- <td>%(skip)s</td>
- <td>%(fail)s</td>
- <td>%(error)s</td>
- <td><a href="javascript:showClassDetail('%(cid)s',%(count)s)">Detail</a></td>
-</tr>
-""" # variables: (style, desc, count, Pass, fail, error, cid)
-
-
- REPORT_TEST_WITH_OUTPUT_TMPL = r"""
-<tr id='%(tid)s' class='%(Class)s'>
- <td class='%(style)s'><div class='testcase'>%(desc)s</div></td>
- <td colspan='5' align='center'>
-
- <!--css div popup start-->
- <a class="popup_link" onfocus='this.blur();' href="javascript:showTestDetail('div_%(tid)s')" >
- %(status)s</a>
-
- <div id='div_%(tid)s' class="popup_window">
- <div style='text-align: right; color:red;cursor:pointer'>
- <a onfocus='this.blur();' onclick="document.getElementById('div_%(tid)s').style.display = 'none' " >
- [x]</a>
- </div>
- <pre>
- %(script)s
- </pre>
- </div>
- <!--css div popup end-->
-
- </td>
-</tr>
-""" # variables: (tid, Class, style, desc, status)
-
-
- REPORT_TEST_NO_OUTPUT_TMPL = r"""
-<tr id='%(tid)s' class='%(Class)s'>
- <td class='%(style)s'><div class='testcase'>%(desc)s</div></td>
- <td colspan='5' align='center'>%(status)s</td>
-</tr>
-""" # variables: (tid, Class, style, desc, status)
-
-
- REPORT_TEST_OUTPUT_TMPL = r"""
-%(id)s: %(output)s
-""" # variables: (id, output)
-
-
-
- # ------------------------------------------------------------------------
- # ENDING
- #
-
- ENDING_TMPL = """<div id='ending'> </div>"""
-
-# -------------------- The end of the Template class -------------------
-
-
-TestResult = unittest.TestResult
-
-class _TestResult(TestResult):
- # note: _TestResult is a pure representation of results.
- # It lacks the output and reporting ability compares to unittest._TextTestResult.
-
- def __init__(self, verbosity=1):
- TestResult.__init__(self)
- self.stdout0 = None
- self.stderr0 = None
- self.skip_count = 0
- self.success_count = 0
- self.failure_count = 0
- self.error_count = 0
- self.verbosity = verbosity
-
- # result is a list of result in 4 tuple
- # (
- # result code (0: success; 1: fail; 2: error),
- # TestCase object,
- # Test output (byte string),
- # stack trace,
- # )
- self.result = []
-
-
- def startTest(self, test):
- TestResult.startTest(self, test)
- # just one buffer for both stdout and stderr
- self.outputBuffer = StringIO.StringIO()
- stdout_redirector.fp = self.outputBuffer
- stderr_redirector.fp = self.outputBuffer
- self.stdout0 = sys.stdout
- self.stderr0 = sys.stderr
- sys.stdout = stdout_redirector
- sys.stderr = stderr_redirector
-
-
- def complete_output(self):
- """
- Disconnect output redirection and return buffer.
- Safe to call multiple times.
- """
- if self.stdout0:
- sys.stdout = self.stdout0
- sys.stderr = self.stderr0
- self.stdout0 = None
- self.stderr0 = None
- return self.outputBuffer.getvalue()
-
-
- def stopTest(self, test):
- # Usually one of addSuccess, addError or addFailure would have been called.
- # But there are some path in unittest that would bypass this.
- # We must disconnect stdout in stopTest(), which is guaranteed to be called.
- self.complete_output()
-
-
- def addSuccess(self, test):
- self.success_count += 1
- TestResult.addSuccess(self, test)
- output = self.complete_output()
- self.result.append((0, test, output, ''))
- if self.verbosity > 1:
- sys.stderr.write('ok ')
- sys.stderr.write(str(test))
- sys.stderr.write('\n')
- else:
- sys.stderr.write('.')
-
- def addError(self, test, err):
- self.error_count += 1
- TestResult.addError(self, test, err)
- _, _exc_str = self.errors[-1]
- output = self.complete_output()
- self.result.append((2, test, output, _exc_str))
- if self.verbosity > 1:
- sys.stderr.write('E ')
- sys.stderr.write(str(test))
- sys.stderr.write('\n')
- else:
- sys.stderr.write('E')
-
- def addFailure(self, test, err):
- self.failure_count += 1
- TestResult.addFailure(self, test, err)
- _, _exc_str = self.failures[-1]
- output = self.complete_output()
- self.result.append((1, test, output, _exc_str))
- if self.verbosity > 1:
- sys.stderr.write('F ')
- sys.stderr.write(str(test))
- sys.stderr.write('\n')
- else:
- sys.stderr.write('F')
-
- def addSkip(self, test, reason):
- self.skip_count += 1
- TestResult.addSkip(self, test, reason)
- output = self.complete_output()
- self.result.append((3, test, output, reason))
- if self.verbosity > 1:
- sys.stderr.write('S ')
- sys.stderr.write(str(test))
- sys.stderr.write('\n')
- else:
- sys.stderr.write('S')
-
-
-class HTMLTestRunner(Template_mixin):
- """
- """
- def __init__(self, stream=sys.stdout, verbosity=1, title=None, description=None):
- self.stream = stream
- self.verbosity = verbosity
- if title is None:
- self.title = self.DEFAULT_TITLE
- else:
- self.title = title
- if description is None:
- self.description = self.DEFAULT_DESCRIPTION
- else:
- self.description = description
-
- self.startTime = datetime.datetime.now()
-
-
- def run(self, test):
- "Run the given test case or test suite."
- result = _TestResult(self.verbosity)
- test(result)
- self.stopTime = datetime.datetime.now()
- self.generateReport(test, result)
- print >>sys.stderr, '\nTime Elapsed: %s' % (self.stopTime-self.startTime)
- return result
-
-
- def sortResult(self, result_list):
- # unittest does not seems to run in any particular order.
- # Here at least we want to group them together by class.
- rmap = {}
- classes = []
- for n,t,o,e in result_list:
- cls = t.__class__
- if not rmap.has_key(cls):
- rmap[cls] = []
- classes.append(cls)
- rmap[cls].append((n,t,o,e))
- r = [(cls, rmap[cls]) for cls in classes]
- return r
-
-
- def getReportAttributes(self, result):
- """
- Return report attributes as a list of (name, value).
- Override this to add custom attributes.
- """
- startTime = str(self.startTime)[:19]
- duration = str(self.stopTime - self.startTime)
- status = []
- if result.success_count:
- status.append('Pass %s' % result.success_count)
- if result.skip_count:
- status.append('Skip %s' % result.skip_count)
- if result.failure_count:
- status.append('Failure %s' % result.failure_count)
- if result.error_count:
- status.append('Error %s' % result.error_count)
- if status:
- status = ' '.join(status)
- else:
- status = 'none'
- return [
- ('Start Time', startTime),
- ('Duration', duration),
- ('Status', status),
- ]
-
-
- def generateReport(self, test, result):
- report_attrs = self.getReportAttributes(result)
- generator = 'HTMLTestRunner %s' % __version__
- stylesheet = self._generate_stylesheet()
- heading = self._generate_heading(report_attrs)
- report = self._generate_report(result)
- ending = self._generate_ending()
- output = self.HTML_TMPL % dict(
- title = saxutils.escape(self.title),
- generator = generator,
- stylesheet = stylesheet,
- heading = heading,
- report = report,
- ending = ending,
- )
- self.stream.write(output.encode('utf8'))
-
-
- def _generate_stylesheet(self):
- return self.STYLESHEET_TMPL
-
-
- def _generate_heading(self, report_attrs):
- a_lines = []
- for name, value in report_attrs:
- line = self.HEADING_ATTRIBUTE_TMPL % dict(
- name = saxutils.escape(name),
- value = saxutils.escape(value),
- )
- a_lines.append(line)
- heading = self.HEADING_TMPL % dict(
- title = saxutils.escape(self.title),
- parameters = ''.join(a_lines),
- description = saxutils.escape(self.description),
- )
- return heading
-
-
- def _generate_report(self, result):
- rows = []
- sortedResult = self.sortResult(result.result)
- for cid, (cls, cls_results) in enumerate(sortedResult):
- # subtotal for a class
- np = nf = ne = ns = 0
- for n,t,o,e in cls_results:
- if n == 0:
- np += 1
- elif n == 1:
- nf += 1
- elif n == 3:
- ns += 1
- else:
- ne += 1
-
- # format class description
- if cls.__module__ == "__main__":
- name = cls.__name__
- else:
- name = "%s.%s" % (cls.__module__, cls.__name__)
- doc = cls.__doc__ and cls.__doc__.split("\n")[0] or ""
- desc = doc and '%s: %s' % (name, doc) or name
-
- row = self.REPORT_CLASS_TMPL % dict(
- style = (ne > 0 and 'errorClass') or \
- (nf > 0 and 'failClass') or \
- (ns > 0 and 'skipClass') or 'passClass',
- desc = desc,
- count = np+nf+ne+ns,
- Pass = np,
- fail = nf,
- error = ne,
- skip = ns,
- cid = 'c%s' % (cid+1),
- )
- rows.append(row)
-
- for tid, (n,t,o,e) in enumerate(cls_results):
- self._generate_report_test(rows, cid, tid, n, t, o, e)
-
- report = self.REPORT_TMPL % dict(
- test_list = ''.join(rows),
- count = str(result.success_count+result.failure_count+result.error_count),
- Pass = str(result.success_count),
- skip = str(result.skip_count),
- fail = str(result.failure_count),
- error = str(result.error_count),
- )
- return report
-
-
- def _generate_report_test(self, rows, cid, tid, n, t, o, e):
- # e.g. 'pt1.1', 'ft1.1', etc
- has_output = bool(o or e)
- tid = (
- (n == 0 and 'p') or
- (n == 3 and 's') or
- 'f'
- ) + 't%s.%s' % (cid+1,tid+1)
- name = t.id().split('.')[-1]
- doc = t.shortDescription() or ""
- desc = doc and ('%s: %s' % (name, doc)) or name
- tmpl = has_output and self.REPORT_TEST_WITH_OUTPUT_TMPL or self.REPORT_TEST_NO_OUTPUT_TMPL
-
- # o and e should be byte string because they are collected from stdout and stderr?
- if isinstance(o,str):
- # TODO: some problem with 'string_escape': it escape \n and mess up formating
- # uo = unicode(o.encode('string_escape'))
- uo = o.decode('latin-1')
- else:
- uo = o
- if isinstance(e,str):
- # TODO: some problem with 'string_escape': it escape \n and mess up formating
- # ue = unicode(e.encode('string_escape'))
- ue = e.decode('latin-1')
- else:
- ue = e
-
- script = self.REPORT_TEST_OUTPUT_TMPL % dict(
- id = tid,
- output = saxutils.escape(uo+ue),
- )
-
- row = tmpl % dict(
- tid = tid,
- Class = (n == 0 and 'hiddenRow' or 'none'),
- style = (n == 2 and 'errorCase') or \
- (n == 1 and 'failCase') or \
- (n == 3 and 'skipCase')
- or 'none',
- desc = desc,
- script = script,
- status = self.STATUS[n],
- )
- rows.append(row)
- if not has_output:
- return
-
- def _generate_ending(self):
- return self.ENDING_TMPL
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/SaltTesting-0.5.2/salttesting/parser/__init__.py new/SaltTesting-0.5.3/salttesting/parser/__init__.py
--- old/SaltTesting-0.5.2/salttesting/parser/__init__.py 2013-10-24 12:57:42.000000000 +0200
+++ new/SaltTesting-0.5.3/salttesting/parser/__init__.py 2013-11-12 06:14:36.000000000 +0100
@@ -12,13 +12,16 @@
import os
import sys
+import time
+import signal
import shutil
import logging
import optparse
import tempfile
+import subprocess
+import warnings
from salttesting import TestLoader, TextTestRunner
-from salttesting.ext.HTMLTestRunner import HTMLTestRunner
try:
from salttesting.ext import console
width, height = console.getTerminalSize()
@@ -56,9 +59,21 @@
class SaltTestingParser(optparse.OptionParser):
+ support_docker_execution = False
support_destructive_tests_selection = False
+ source_code_basedir = None
def __init__(self, testsuite_directory, *args, **kwargs):
+ if kwargs.pop('html_output_from_env', None) is not None or \
+ kwargs.pop('html_output_dir', None) is not None:
+ warnings.warn(
+ 'The unit tests HTML support was removed from {0}. Please '
+ 'stop passing \'html_output_dir\' or \'html_output_from_env\' '
+ 'as arguments to {0}'.format(self.__class__.__name__),
+ category=DeprecationWarning,
+ stacklevel=2
+ )
+
# Get XML output settings
xml_output_dir_env_var = kwargs.pop(
'xml_output_from_env',
@@ -72,19 +87,6 @@
)
)
- # Get HTML output settings
- html_output_dir_env_var = kwargs.pop(
- 'html_output_from_env',
- 'HTML_TESTS_OUTPUT_DIR'
- )
- html_output_dir = kwargs.pop('html_output_dir', None)
- self.html_output_dir = os.environ.get(
- html_output_dir_env_var,
- html_output_dir or os.path.join(
- tempfile.gettempdir(), 'html-tests-output'
- )
- )
-
# Get the desired logfile to use while running tests
self.tests_logfile = kwargs.pop('tests_logfile', None)
@@ -106,12 +108,20 @@
'or removing users from your system for example. '
'Default: %default')
)
+
+ if self.support_docker_execution is True:
+ self.test_selection_group.add_option(
+ '--docked',
+ default=None,
+ help='Run the tests suite in the chosen Docker container'
+ )
+
self.test_selection_group.add_option(
'-n',
'--name',
dest='name',
action='append',
- default=[],
+ default=None,
help=('Specific test name to run. A named test is the module path '
'relative to the tests directory')
)
@@ -139,15 +149,6 @@
self.xml_output_dir
)
)
- if self.html_output_dir:
- self.output_options_group.add_option(
- '--html-out',
- default=False,
- action='store_true',
- help='HTML test runner output(Output directory: {0})'.format(
- self.html_output_dir
- )
- )
self.output_options_group.add_option(
'--no-report',
default=False,
@@ -183,6 +184,23 @@
)
self.pre_execution_cleanup()
self._validate_options()
+
+ if self.support_docker_execution and self.options.docked is not None:
+ if self.source_code_basedir is None:
+ raise RuntimeError(
+ 'You need to define the \'source_code_basedir\' attribute '
+ 'in {0!r}.'.format(self.__class__.__name__)
+ )
+ # No more processing should be done. We'll exit with the return
+ # code we get from the docker container execution
+ self.exit(self.run_suite_in_docker())
+
+ print('Current Directory: {0}'.format(os.getcwd()))
+ print_header(
+ 'Test suite is running under PID {0}'.format(os.getpid()),
+ bottom=False
+ )
+
self._setup_logging()
return (self.options, self.args)
@@ -209,14 +227,6 @@
'at {0!r}'.format(self.xml_output_dir)
)
- if self.html_output_dir is not None and self.options.html_out:
- if not os.path.isdir(self.html_output_dir):
- os.makedirs(self.html_output_dir)
- print(
- 'Generated unit test HTML reports will be stored '
- 'at {0!r}'.format(self.html_output_dir)
- )
-
self.validate_options()
if self.support_destructive_tests_selection:
@@ -224,12 +234,6 @@
# destructive tests should be executed or not.
os.environ['DESTRUCTIVE_TESTS'] = str(self.options.run_destructive)
- print('Current Directory: {0}'.format(os.getcwd()))
- print_header(
- 'Test suite is running under PID {0}'.format(os.getpid()),
- bottom=False
- )
-
def validate_options(self):
'''
Validate the provided options. Override this method to run your own
@@ -293,7 +297,7 @@
method.
'''
if self.options.clean is True:
- for path in (self.xml_output_dir, self.html_output_dir):
+ for path in (self.xml_output_dir,):
if path is None:
continue
if os.path.isdir(path):
@@ -320,20 +324,6 @@
verbosity=self.options.verbosity
).run(tests)
self.testsuite_results.append((header, runner))
- elif self.options.html_out:
- runner = HTMLTestRunner(
- stream=open(
- os.path.join(
- self.html_output_dir, 'report_{0}.html'.format(
- header.replace(' ', '_')
- )
- ),
- 'w'
- ),
- verbosity=self.options.verbosity,
- title=header,
- ).run(tests)
- self.testsuite_results.append((header, runner))
else:
runner = TextTestRunner(
stream=sys.stdout,
@@ -449,6 +439,107 @@
)
self.exit(exit_code)
+ def run_suite_in_docker(self):
+ '''
+ Run the tests suite in a Docker container
+ '''
+ # Let's start the Docker container and run the tests suite there
+ if '/' not in self.options.docked:
+ container = 'salttest/{0}'.format(self.options.docked)
+ else:
+ container = self.options.docked
+
+ calling_args = ['/salt-source/tests/runtests.py']
+ for option in self._get_all_options():
+ if option.dest is None:
+ # For example --version
+ continue
+
+ if option.dest in ('docked', 'verbosity'):
+ # We don't need to pass the --docked argument inside the docker
+ # container, and verbose will be handled bellow
+ continue
+
+ default = self.defaults.get(option.dest)
+ value = getattr(self.options, option.dest, default)
+
+ if default == value:
+ # This is the default value, no need to pass the option to the
+ # parser
+ continue
+
+ if option.action.startswith('store_'):
+ calling_args.append(option.get_opt_string())
+
+ elif option.action == 'append':
+ for val in (value is not None and value or default):
+ calling_args.extend(
+ [option.get_opt_string(), str(val)]
+ )
+ elif option.action == 'count':
+ calling_args.extend(
+ [option.get_opt_string()] * value
+ )
+ else:
+ calling_args.extend(
+ [option.get_opt_string(),
+ str(value is not None and value or default)]
+ )
+
+ if not self.options.run_destructive:
+ calling_args.append('--run-destructive')
+
+ if self.options.verbosity > 1:
+ calling_args.append(
+ '-{0}'.format('v' * (self.options.verbosity - 1))
+ )
+
+ print_header(
+ 'Running the tests suite under the {0!r} docker container'.format(
+ container
+ )
+ )
+ call = subprocess.Popen(
+ ['docker',
+ 'run',
+ '-v',
+ '{0}:/salt-source'.format(self.source_code_basedir),
+ '-w',
+ '/salt-source',
+ container,
+ ] + calling_args,
+ env=os.environ.copy(),
+ close_fds=True,
+ )
+
+ signalled = terminating = exiting = False
+
+ while True:
+ try:
+ time.sleep(0.15)
+ if exiting:
+ break
+ elif terminating and not exiting:
+ exiting = True
+ call.kill()
+ break
+ elif signalled and not terminating:
+ terminating = True
+ call.terminate()
+ else:
+ call.poll()
+ if call.returncode is not None:
+ # Finshed
+ break
+ except KeyboardInterrupt:
+ print('Caught CTRL-C, exiting...')
+ signalled = True
+ call.send_signal(signal.SIGINT)
+
+ call.wait()
+
+ self.exit(call.returncode)
+
class SaltTestcaseParser(SaltTestingParser):
'''
@@ -461,8 +552,6 @@
self.option_groups.remove(self.test_selection_group)
if self.has_option('--xml-out'):
self.remove_option('--xml-out')
- if self.has_option('--html-out'):
- self.remove_option('--html-out')
def get_prog_name(self):
return '{0} {1}'.format(sys.executable.split(os.sep)[-1], sys.argv[0])
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/SaltTesting-0.5.2/salttesting/parser/cover.py new/SaltTesting-0.5.3/salttesting/parser/cover.py
--- old/SaltTesting-0.5.2/salttesting/parser/cover.py 2013-10-24 12:57:42.000000000 +0200
+++ new/SaltTesting-0.5.3/salttesting/parser/cover.py 2013-11-12 06:14:36.000000000 +0100
@@ -16,6 +16,7 @@
import sys
import json
import shutil
+import warnings
# Import salt testing libs
from salttesting.parser import SaltTestingParser
@@ -74,6 +75,16 @@
Code coverage aware testing option parser
'''
def __init__(self, *args, **kwargs):
+ if kwargs.pop('html_output_from_env', None) is not None or \
+ kwargs.pop('html_output_dir', None) is not None:
+ warnings.warn(
+ 'The unit tests HTML support was removed from {0}. Please '
+ 'stop passing \'html_output_dir\' or \'html_output_from_env\' '
+ 'as arguments to {0}'.format(self.__class__.__name__),
+ category=DeprecationWarning,
+ stacklevel=2
+ )
+
SaltTestingParser.__init__(self, *args, **kwargs)
self.code_coverage = None
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/SaltTesting-0.5.2/salttesting/pylintplugins/pep8.py new/SaltTesting-0.5.3/salttesting/pylintplugins/pep8.py
--- old/SaltTesting-0.5.2/salttesting/pylintplugins/pep8.py 2013-10-24 12:57:42.000000000 +0200
+++ new/SaltTesting-0.5.3/salttesting/pylintplugins/pep8.py 2013-11-12 06:14:36.000000000 +0100
@@ -19,24 +19,34 @@
from pylint.checkers import BaseChecker
# Import PEP8 libs
-from pep8 import StyleGuide, BaseReport
+try:
+ from pep8 import StyleGuide, BaseReport
+ HAS_PEP8 = True
+except ImportError:
+ HAS_PEP8 = False
+ import logging
+ logging.getLogger(__name__).warning(
+ 'No pep8 library could be imported. No PEP8 check\'s will be done'
+ )
+
_PROCESSED_NODES = {}
-class PyLintPEP8Reporter(BaseReport):
- def __init__(self, options):
- super(PyLintPEP8Reporter, self).__init__(options)
- self.locations = []
-
- def error(self, line_number, offset, text, check):
- code = super(PyLintPEP8Reporter, self).error(
- line_number, offset, text, check
- )
- if code:
- # E123, at least, is not reporting it's code in the above call,
- # don't want to bother about that now
- self.locations.append((code, line_number))
+if HAS_PEP8 is True:
+ class PyLintPEP8Reporter(BaseReport):
+ def __init__(self, options):
+ super(PyLintPEP8Reporter, self).__init__(options)
+ self.locations = []
+
+ def error(self, line_number, offset, text, check):
+ code = super(PyLintPEP8Reporter, self).error(
+ line_number, offset, text, check
+ )
+ if code:
+ # E123, at least, is not reporting it's code in the above call,
+ # don't want to bother about that now
+ self.locations.append((code, line_number))
class _PEP8BaseChecker(BaseChecker):
@@ -303,6 +313,9 @@
'''
required method to auto register this checker
'''
+ if HAS_PEP8 is False:
+ return
+
linter.register_checker(PEP8Indentation(linter))
linter.register_checker(PEP8Whitespace(linter))
linter.register_checker(PEP8BlankLine(linter))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/SaltTesting-0.5.2/salttesting/pylintplugins/string_format.py new/SaltTesting-0.5.3/salttesting/pylintplugins/string_format.py
--- old/SaltTesting-0.5.2/salttesting/pylintplugins/string_format.py 1970-01-01 01:00:00.000000000 +0100
+++ new/SaltTesting-0.5.3/salttesting/pylintplugins/string_format.py 2013-11-11 01:23:52.000000000 +0100
@@ -0,0 +1,157 @@
+# Copyright (c) 2009-2010 Arista Networks, Inc. - James Lingard
+# Copyright (c) 2004-2010 LOGILAB S.A. (Paris, FRANCE).
+# http://www.logilab.fr/ -- mailto:contact@logilab.fr
+# This program is free software; you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free Software
+# Foundation; either version 2 of the License, or (at your option) any later
+# version.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+
+"""Checker for string formatting operations.
+"""
+
+import string
+from logilab import astng
+from pylint.interfaces import IASTNGChecker
+from pylint.checkers import BaseChecker
+from pylint.checkers import utils
+
+
+MSGS = {
+ 'E1300': ("Unsupported format character %r (%#02x) at index %d",
+ "Used when a unsupported format character is used in a format\
+ string."),
+ 'E1301': ("Format string ends in middle of conversion specifier",
+ "Used when a format string terminates before the end of a \
+ conversion specifier."),
+ 'E1302': ("Mixing named and unnamed conversion specifiers in format string",
+ "Used when a format string contains both named (e.g. '%(foo)d') \
+ and unnamed (e.g. '%d') conversion specifiers. This is also \
+ used when a named conversion specifier contains * for the \
+ minimum field width and/or precision."),
+ 'E1303': ("Expected mapping for format string, not %s",
+ "Used when a format string that uses named conversion specifiers \
+ is used with an argument that is not a mapping."),
+ 'W1300': ("Format string dictionary key should be a string, not %s",
+ "Used when a format string that uses named conversion specifiers \
+ is used with a dictionary whose keys are not all strings."),
+ 'W1301': ("Unused key %r in format string dictionary",
+ "Used when a format string that uses named conversion specifiers \
+ is used with a dictionary that conWtains keys not required by the \
+ format string."),
+ 'E1304': ("Missing key %r in format string dictionary",
+ "Used when a format string that uses named conversion specifiers \
+ is used with a dictionary that doesn't contain all the keys \
+ required by the format string."),
+ 'E1305': ("Too many arguments for format string",
+ "Used when a format string that uses unnamed conversion \
+ specifiers is given too few arguments."),
+ 'E1306': ("Not enough arguments for format string",
+ "Used when a format string that uses unnamed conversion \
+ specifiers is given too many arguments"),
+ }
+
+OTHER_NODES = (astng.Const, astng.List, astng.Backquote,
+ astng.Lambda, astng.Function,
+ astng.ListComp, astng.SetComp, astng.GenExpr)
+
+class StringFormatChecker(BaseChecker):
+ """Checks string formatting operations to ensure that the format string
+ is valid and the arguments match the format string.
+ """
+
+ __implements__ = (IASTNGChecker,)
+ name = 'string_format'
+ msgs = MSGS
+
+ def visit_binop(self, node):
+ if node.op != '%':
+ return
+ left = node.left
+ args = node.right
+
+ if not (isinstance(left, astng.Const)
+ and isinstance(left.value, basestring)):
+ return
+ format_string = left.value
+ try:
+ required_keys, required_num_args = \
+ utils.parse_format_string(format_string)
+ except utils.UnsupportedFormatCharacter, e:
+ c = format_string[e.index]
+ self.add_message('E1300', node=node, args=(c, ord(c), e.index))
+ return
+ except utils.IncompleteFormatString:
+ self.add_message('E1301', node=node)
+ return
+ if required_keys and required_num_args:
+ # The format string uses both named and unnamed format
+ # specifiers.
+ self.add_message('E1302', node=node)
+ elif required_keys:
+ # The format string uses only named format specifiers.
+ # Check that the RHS of the % operator is a mapping object
+ # that contains precisely the set of keys required by the
+ # format string.
+ if isinstance(args, astng.Dict):
+ keys = set()
+ unknown_keys = False
+ for k, v in args.items:
+ if isinstance(k, astng.Const):
+ key = k.value
+ if isinstance(key, basestring):
+ keys.add(key)
+ else:
+ self.add_message('W1300', node=node, args=key)
+ else:
+ # One of the keys was something other than a
+ # constant. Since we can't tell what it is,
+ # supress checks for missing keys in the
+ # dictionary.
+ unknown_keys = True
+ if not unknown_keys:
+ for key in required_keys:
+ if key not in keys:
+ self.add_message('E1304', node=node, args=key)
+ for key in keys:
+ if key not in required_keys:
+ self.add_message('W1301', node=node, args=key)
+ elif isinstance(args, OTHER_NODES + (astng.Tuple,)):
+ type_name = type(args).__name__
+ self.add_message('E1303', node=node, args=type_name)
+ # else:
+ # The RHS of the format specifier is a name or
+ # expression. It may be a mapping object, so
+ # there's nothing we can check.
+ else:
+ # The format string uses only unnamed format specifiers.
+ # Check that the number of arguments passed to the RHS of
+ # the % operator matches the number required by the format
+ # string.
+ if isinstance(args, astng.Tuple):
+ num_args = len(args.elts)
+ elif isinstance(args, OTHER_NODES + (astng.Dict, astng.DictComp)):
+ num_args = 1
+ else:
+ # The RHS of the format specifier is a name or
+ # expression. It could be a tuple of unknown size, so
+ # there's nothing we can check.
+ num_args = None
+ if num_args is not None:
+ if num_args > required_num_args:
+ self.add_message('E1305', node=node)
+ elif num_args < required_num_args:
+ self.add_message('E1306', node=node)
+
+
+def register(linter):
+ """required method to auto register this checker """
+ linter.register_checker(StringFormatChecker(linter))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/SaltTesting-0.5.2/salttesting/pylintplugins/strings.py new/SaltTesting-0.5.3/salttesting/pylintplugins/strings.py
--- old/SaltTesting-0.5.2/salttesting/pylintplugins/strings.py 1970-01-01 01:00:00.000000000 +0100
+++ new/SaltTesting-0.5.3/salttesting/pylintplugins/strings.py 2013-11-12 06:14:36.000000000 +0100
@@ -0,0 +1,94 @@
+# -*- coding: utf-8 -*-
+'''
+ :codeauthor: :email:`Pedro Algarvio (pedro@algarvio.me)`
+ :copyright: © 2013 by the SaltStack Team, see AUTHORS for more details.
+ :license: Apache 2.0, see LICENSE for more details.
+
+
+ salttesting.pylintplugins.strings
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ Extended String Formatting Checkers
+'''
+
+import sys
+from logilab import astng
+from pylint.checkers import utils
+from pylint.checkers import BaseChecker
+from pylint.checkers.utils import check_messages
+from pylint.interfaces import IASTNGChecker
+
+
+MSGS = {
+ 'W1320': ('String format call with un-indexed curly braces: %r',
+ 'un-indexed-curly-braces-warning',
+ 'Under python 2.6 the curly braces on a \'string.format()\' '
+ 'call MUST be indexed.'),
+ 'E1320': ('String format call with un-indexed curly braces: %r',
+ 'un-indexed-curly-braces-error',
+ 'Under python 2.6 the curly braces on a \'string.format()\' '
+ 'call MUST be indexed.')
+}
+
+
+class StringCurlyBracesFormatIndexChecker(BaseChecker):
+
+ __implements__ = (IASTNGChecker,)
+
+ name = 'string'
+ msgs = MSGS
+ priority = -1
+
+ options = (('un-indexed-curly-braces-always-error',
+ {'default': 1, 'type': 'yn', 'metavar': '