Commit 29c930bb by Jon Maron

python scripts

parent 86fe0801
...@@ -95,6 +95,30 @@ ...@@ -95,6 +95,30 @@
<MaxPermGen>512m</MaxPermGen> <MaxPermGen>512m</MaxPermGen>
</properties> </properties>
<profiles>
<profile>
<id>Windows</id>
<activation>
<os><family>windows</family></os>
</activation>
<properties>
<!--executable.python>python</executable.python-->
<python.path.l>${project.basedir}\src\bin;${project.basedir}\src\test\python\scripts;${project.basedir}\src\test\mock</python.path.l>
</properties>
</profile>
<profile>
<id>Linux</id>
<activation>
<os><family>!windows</family></os>
</activation>
<properties>
<!--executable.python>${project.basedir}/../slider-agent/src/test/python/python-wrap</executable.python-->
<python.path.l>${project.basedir}/src/bin:${project.basedir}/src/test/mock:${project.basedir}/src/test/python/scripts</python.path.l>
</properties>
</profile>
</profiles>
<modules> <modules>
<module>typesystem</module> <module>typesystem</module>
<module>client</module> <module>client</module>
...@@ -896,6 +920,8 @@ ...@@ -896,6 +920,8 @@
<exclude>**/.project</exclude> <exclude>**/.project</exclude>
<exclude>**/.settings/**</exclude> <exclude>**/.settings/**</exclude>
<exclude>**/test-output/**</exclude> <exclude>**/test-output/**</exclude>
<exclude>**/mock/**</exclude>
<exclude>**/data/**</exclude>
<exclude>**/data.txt</exclude> <exclude>**/data.txt</exclude>
<exclude>**/maven-eclipse.xml</exclude> <exclude>**/maven-eclipse.xml</exclude>
<exclude>**/.externalToolBuilders/**</exclude> <exclude>**/.externalToolBuilders/**</exclude>
...@@ -958,6 +984,33 @@ ...@@ -958,6 +984,33 @@
<groupId>org.codehaus.mojo</groupId> <groupId>org.codehaus.mojo</groupId>
<artifactId>javancss-maven-plugin</artifactId> <artifactId>javancss-maven-plugin</artifactId>
</plugin> </plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.2.1</version>
<inherited>false</inherited>
<executions>
<execution>
<configuration>
<executable>python</executable>
<workingDirectory>src/test/python</workingDirectory>
<arguments>
<argument>unitTests.py</argument>
</arguments>
<environmentVariables>
<PYTHONPATH>${python.path.l}</PYTHONPATH>
</environmentVariables>
</configuration>
<id>python-test</id>
<phase>test</phase>
<goals>
<goal>exec</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins> </plugins>
</build> </build>
</project> </project>
#!/usr/bin/env python
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import os
import sys
import metadata_config as mc
DEFAULT_JVM_OPTS="-Xmx1024m"
def main():
metadata_home = mc.metadataDir()
confdir = mc.dirMustExist(mc.confDir(metadata_home))
logdir = mc.dirMustExist(mc.logDir(metadata_home))
mc.executeEnvSh(confdir)
jvm_opts_list = []
default_jvm_opts = DEFAULT_JVM_OPTS
metadata_jvm_opts = os.environ.get(mc.METADATA_OPTS, default_jvm_opts)
jvm_opts_list.extend(metadata_jvm_opts.split())
#expand web app dir
web_app_dir = mc.webAppDir(metadata_home)
mc.expandWebApp(metadata_home)
p = os.pathsep
metadata_classpath = confdir + p \
+ os.path.join(web_app_dir, "metadata", "WEB-INF", "classes" ) + p \
+ os.path.join(web_app_dir, "metadata", "WEB-INF", "lib", "*" ) + p \
+ os.path.join(metadata_home, "libext", "*")
process = mc.java("org.apache.hadoop.metadata.util.CredentialProviderUtility", sys.argv[1:], metadata_classpath, jvm_opts_list)
process.wait()
if __name__ == '__main__':
try:
returncode = main()
except Exception as e:
print "Exception: %s " % str(e)
returncode = -1
sys.exit(returncode)
#!/usr/bin/env python
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import getpass
import os
import platform
import subprocess
from threading import Thread
import sys
import time
import errno
LIB = "lib"
CONF = "conf"
LOG="logs"
WEBAPP="server" + os.sep + "webapp"
DATA="data"
ENV_KEYS = ["JAVA_HOME", "METADATA_OPTS", "METADATA_LOG_DIR", "METADATA_CONF", "METADATACPPATH", "METADATA_DATA_DIR", "METADATA_HOME_DIR", "METADATA_EXPANDED_WEBAPP_DIR"]
METADATA_CONF = "METADATA_CONF"
METADATA_LOG = "METADATA_LOG_DIR"
METADATA_WEBAPP = "METADATA_EXPANDED_WEBAPP_DIR"
METADATA_OPTS = "METADATA_OPTS"
METADATA_DATA = "METADATA_DATA_DIR"
METADATA_HOME = "METADATA_HOME_DIR"
IS_WINDOWS = platform.system() == "Windows"
ON_POSIX = 'posix' in sys.builtin_module_names
DEBUG = False
def scriptDir():
"""
get the script path
"""
return os.path.dirname(os.path.realpath(__file__))
def metadataDir():
home = os.path.dirname(scriptDir())
return os.environ.get(METADATA_HOME, home)
def libDir(dir) :
return os.path.join(dir, LIB)
def confDir(dir):
localconf = os.path.join(dir, CONF)
return os.environ.get(METADATA_CONF, localconf)
def logDir(dir):
localLog = os.path.join(dir, LOG)
return os.environ.get(METADATA_LOG, localLog)
def dataDir(dir):
data = os.path.join(dir, DATA)
return os.environ.get(METADATA_DATA, data)
def webAppDir(dir):
webapp = os.path.join(dir, WEBAPP)
return os.environ.get(METADATA_WEBAPP, webapp)
def expandWebApp(dir):
webappDir = webAppDir(dir)
webAppMetadataDir = os.path.join(webappDir, "metadata")
d = os.sep
if not os.path.exists(os.path.join(webAppMetadataDir, "WEB-INF")):
try:
os.makedirs(webAppMetadataDir)
except OSError, e:
if e.errno != errno.EEXIST:
raise e
pass
os.chdir(webAppMetadataDir)
jar(os.path.join(metadataDir(), "server", "webapp", "metadata.war"))
def dirMustExist(dirname):
if not os.path.exists(dirname):
os.mkdir(dirname)
return dirname
def executeEnvSh(confDir):
envscript = '%s/metadata-env.sh' % confDir
if not IS_WINDOWS and os.path.exists(envscript):
envCmd = 'source %s && env' % envscript
command = ['bash', '-c', envCmd]
proc = subprocess.Popen(command, stdout = subprocess.PIPE)
for line in proc.stdout:
(key, _, value) = line.strip().partition("=")
if key in ENV_KEYS:
os.environ[key] = value
proc.communicate()
def java(classname, args, classpath, jvm_opts_list):
if os.environ["JAVA_HOME"] is not None and os.environ["JAVA_HOME"]:
prg = os.path.join(os.environ["JAVA_HOME"], "bin", "java")
else:
prg = which("java")
commandline = [prg]
commandline.extend(jvm_opts_list)
commandline.append("-classpath")
commandline.append(classpath)
commandline.append(classname)
commandline.extend(args)
return runProcess(commandline)
def jar(path):
if os.environ["JAVA_HOME"] is not None and os.environ["JAVA_HOME"]:
prg = os.path.join(os.environ["JAVA_HOME"], "bin", "jar")
else:
prg = which("jar")
commandline = [prg]
commandline.append("-xf")
commandline.append(path)
return runProcess(commandline)
def is_exe(fpath):
return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
def which(program):
fpath, fname = os.path.split(program)
if fpath:
if is_exe(program):
return program
else:
for path in os.environ["PATH"].split(os.pathsep):
path = path.strip('"')
exe_file = os.path.join(path, program)
if is_exe(exe_file):
return exe_file
return None
def runProcess(commandline):
"""
Run a process
:param commandline: command line
:return:the return code
"""
global finished
debug ("Executing : %s" % commandline)
return subprocess.Popen(commandline)
# exe = subprocess.Popen(commandline,
# stdin=subprocess.PIPE,
# stdout=subprocess.PIPE,
# stderr=subprocess.PIPE,
# shell=False,
# bufsize=1,
# close_fds=ON_POSIX)
#
# t = Thread(target=print_output, args=("stdout", exe.stdout, False))
# t.daemon = True
# t.start()
# t2 = Thread(target=print_output, args=("stderr", exe.stderr, True))
# t2.daemon = True
# t2.start()
# t3 = Thread(target=read_input, args=("stdin", exe))
# t3.daemon = True
# t3.start()
#
# debug("Waiting for completion")
# while exe.poll() is None:
# # process is running; grab output and echo every line
# time.sleep(1)
# debug("completed with exit code : %d" % exe.returncode)
# finished = True
# t.join()
# t2.join()
# t3.join()
# return exe.returncode
def print_output(name, src, toStdErr):
"""
Relay the output stream to stdout line by line
:param name:
:param src: source stream
:param toStdErr: flag set if stderr is to be the dest
:return:
"""
global needPassword
debug ("starting printer for %s" % name )
line = ""
while not finished:
(line, done) = read(src, line)
if done:
out(toStdErr, line + "\n")
flush(toStdErr)
if line.find("Enter password for") >= 0:
needPassword = True
line = ""
out(toStdErr, line)
# closedown: read remainder of stream
c = src.read(1)
while c!="" :
c = c.decode('utf-8')
out(toStdErr, c)
if c == "\n":
flush(toStdErr)
c = src.read(1)
flush(toStdErr)
src.close()
def read_input(name, exe):
"""
Read input from stdin and send to process
:param name:
:param process: process to send input to
:return:
"""
global needPassword
debug ("starting reader for %s" % name )
while not finished:
if needPassword:
needPassword = False
if sys.stdin.isatty():
cred = getpass.getpass()
else:
cred = sys.stdin.readline().rstrip()
exe.stdin.write(cred + "\n")
def debug(text):
if DEBUG: print '[DEBUG] ' + text
def error(text):
print '[ERROR] ' + text
sys.stdout.flush()
def info(text):
print text
sys.stdout.flush()
def out(toStdErr, text) :
"""
Write to one of the system output channels.
This action does not add newlines. If you want that: write them yourself
:param toStdErr: flag set if stderr is to be the dest
:param text: text to write.
:return:
"""
if toStdErr:
sys.stderr.write(text)
else:
sys.stdout.write(text)
def flush(toStdErr) :
"""
Flush the output stream
:param toStdErr: flag set if stderr is to be the dest
:return:
"""
if toStdErr:
sys.stderr.flush()
else:
sys.stdout.flush()
def read(pipe, line):
"""
read a char, append to the listing if there is a char that is not \n
:param pipe: pipe to read from
:param line: line being built up
:return: (the potentially updated line, flag indicating newline reached)
"""
c = pipe.read(1)
if c != "":
o = c.decode('utf-8')
if o != '\n':
line += o
return line, False
else:
return line, True
else:
return line, False
def writePid(metadata_pid_file, process):
f = open(metadata_pid_file, 'w')
f.write(str(process.pid))
f.close()
#!/usr/bin/env python
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import os
import sys
import metadata_config as mc
METADATA_LOG_OPTS="-Dmetadata.log.dir=%s"
METADATA_COMMAND_OPTS="-Dmetadata.home=%s"
DEFAULT_JVM_OPTS="-Xmx1024m"
def main():
metadata_home = mc.metadataDir()
confdir = mc.dirMustExist(mc.confDir(metadata_home))
logdir = mc.dirMustExist(mc.logDir(metadata_home))
mc.executeEnvSh(confdir)
#create sys property for conf dirs
jvm_opts_list = (METADATA_LOG_OPTS % logdir).split()
cmd_opts = (METADATA_COMMAND_OPTS % metadata_home)
jvm_opts_list.extend(cmd_opts.split())
default_jvm_opts = DEFAULT_JVM_OPTS
metadata_jvm_opts = os.environ.get(mc.METADATA_OPTS, default_jvm_opts)
jvm_opts_list.extend(metadata_jvm_opts.split())
#expand web app dir
web_app_dir = mc.webAppDir(metadata_home)
mc.expandWebApp(metadata_home)
p = os.pathsep
metadata_classpath = confdir + p \
+ os.path.join(web_app_dir, "metadata", "WEB-INF", "classes" ) + p \
+ os.path.join(web_app_dir, "metadata", "WEB-INF", "lib", "*" ) + p \
+ os.path.join(metadata_home, "libext", "*")
metadata_pid_file = os.path.join(logdir, "metadata.pid")
if os.path.isfile(metadata_pid_file):
print "%s already exists, exiting" % metadata_pid_file
sys.exit()
args = ["-app", os.path.join(web_app_dir, "metadata")]
args.extend(sys.argv[1:])
process = mc.java("org.apache.hadoop.metadata.Main", args, metadata_classpath, jvm_opts_list)
mc.writePid(metadata_pid_file, process)
print "Metadata Server started!!!\n"
if __name__ == '__main__':
try:
returncode = main()
except Exception as e:
print "Exception: %s " % str(e)
returncode = -1
sys.exit(returncode)
#!/usr/bin/env python
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import os
from signal import SIGTERM
import sys
import metadata_config as mc
def main():
metadata_home = mc.metadataDir()
confdir = mc.dirMustExist(mc.confDir(metadata_home))
piddir = mc.dirMustExist(mc.logDir(metadata_home))
mc.executeEnvSh(confdir)
metadata_pid_file = os.path.join(piddir, "metadata.pid")
try:
pf = file(metadata_pid_file, 'r')
pid = int(pf.read().strip())
pf.close()
except:
pid = None
if not pid:
sys.stderr.write("No process ID file found. Server not running?\n")
return
os.kill(pid, SIGTERM)
# assuming kill worked since process check on windows is more involved...
if os.path.exists(metadata_pid_file):
os.remove(metadata_pid_file)
if __name__ == '__main__':
try:
returncode = main()
except Exception as e:
print "Exception: %s " % str(e)
returncode = -1
sys.exit(returncode)
#!/usr/bin/env python
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import os
import sys
import metadata_config as mc
METADATA_LOG_OPTS="-Dmetadata.log.dir=%s"
METADATA_COMMAND_OPTS="-Dmetadata.home=%s"
DEFAULT_JVM_OPTS="-Xmx1024m"
def main():
metadata_home = mc.metadataDir()
confdir = mc.dirMustExist(mc.confDir(metadata_home))
logdir = mc.dirMustExist(mc.logDir(metadata_home))
mc.executeEnvSh(confdir)
#create sys property for conf dirs
jvm_opts_list = (METADATA_LOG_OPTS % logdir).split()
cmd_opts = (METADATA_COMMAND_OPTS % metadata_home)
jvm_opts_list.extend(cmd_opts.split())
default_jvm_opts = DEFAULT_JVM_OPTS
metadata_jvm_opts = os.environ.get(mc.METADATA_OPTS, default_jvm_opts)
jvm_opts_list.extend(metadata_jvm_opts.split())
#expand web app dir
web_app_dir = mc.webAppDir(metadata_home)
mc.expandWebApp(metadata_home)
p = os.pathsep
metadata_classpath = confdir + p \
+ os.path.join(web_app_dir, "metadata", "WEB-INF", "classes" ) + p \
+ os.path.join(web_app_dir, "metadata", "WEB-INF", "lib", "*" ) + p \
+ os.path.join(metadata_home, "libext", "*")
process = mc.java("org.apache.hadoop.metadata.examples.QuickStart", sys.argv[1:], metadata_classpath, jvm_opts_list)
process.wait()
print "Example data added to Metadata Server!!!\n"
if __name__ == '__main__':
try:
returncode = main()
except Exception as e:
print "Exception: %s " % str(e)
returncode = -1
sys.exit(returncode)
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd"> xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
<formats> <formats>
<format>tar.gz</format> <format>tar.gz</format>
<format>zip</format>
</formats> </formats>
<id>bin</id> <id>bin</id>
<baseDirectory>metadata-${project.version}</baseDirectory> <baseDirectory>metadata-${project.version}</baseDirectory>
......
Copyright (c) 2003-2012, Michael Foord
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.
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.
include LICENSE.txt tox.ini tests/*.py
recursive-include docs *.txt *.py *.png *.css *.html *.js
mock is a library for testing in Python. It allows you to replace parts of
your system under test with mock objects and make assertions about how they
have been used.
mock is now part of the Python standard library, available as `unittest.mock
<http://docs.python.org/py3k/library/unittest.mock.html#module-unittest.mock>`_
in Python 3.3 onwards.
mock provides a core `MagicMock` class removing the need to create a host of
stubs throughout your test suite. After performing an action, you can make
assertions about which methods / attributes were used and arguments they were
called with. You can also specify return values and set needed attributes in
the normal way.
mock is tested on Python versions 2.5-2.7 and Python 3. mock is also tested
with the latest versions of Jython and pypy.
The mock module also provides utility functions / objects to assist with
testing, particularly monkey patching.
* `PDF documentation for 1.0.1
<http://www.voidspace.org.uk/downloads/mock-1.0.1.pdf>`_
* `mock on google code (repository and issue tracker)
<http://code.google.com/p/mock/>`_
* `mock documentation
<http://www.voidspace.org.uk/python/mock/>`_
* `mock on PyPI <http://pypi.python.org/pypi/mock/>`_
* `Mailing list (testing-in-python@lists.idyll.org)
<http://lists.idyll.org/listinfo/testing-in-python>`_
Mock is very easy to use and is designed for use with
`unittest <http://pypi.python.org/pypi/unittest2>`_. Mock is based on
the 'action -> assertion' pattern instead of 'record -> replay' used by many
mocking frameworks. See the `mock documentation`_ for full details.
Mock objects create all attributes and methods as you access them and store
details of how they have been used. You can configure them, to specify return
values or limit what attributes are available, and then make assertions about
how they have been used::
>>> from mock import Mock
>>> real = ProductionClass()
>>> real.method = Mock(return_value=3)
>>> real.method(3, 4, 5, key='value')
3
>>> real.method.assert_called_with(3, 4, 5, key='value')
`side_effect` allows you to perform side effects, return different values or
raise an exception when a mock is called::
>>> mock = Mock(side_effect=KeyError('foo'))
>>> mock()
Traceback (most recent call last):
...
KeyError: 'foo'
>>> values = {'a': 1, 'b': 2, 'c': 3}
>>> def side_effect(arg):
... return values[arg]
...
>>> mock.side_effect = side_effect
>>> mock('a'), mock('b'), mock('c')
(3, 2, 1)
>>> mock.side_effect = [5, 4, 3, 2, 1]
>>> mock(), mock(), mock()
(5, 4, 3)
Mock has many other ways you can configure it and control its behaviour. For
example the `spec` argument configures the mock to take its specification from
another object. Attempting to access attributes or methods on the mock that
don't exist on the spec will fail with an `AttributeError`.
The `patch` decorator / context manager makes it easy to mock classes or
objects in a module under test. The object you specify will be replaced with a
mock (or other object) during the test and restored when the test ends::
>>> from mock import patch
>>> @patch('test_module.ClassName1')
... @patch('test_module.ClassName2')
... def test(MockClass2, MockClass1):
... test_module.ClassName1()
... test_module.ClassName2()
... assert MockClass1.called
... assert MockClass2.called
...
>>> test()
.. note::
When you nest patch decorators the mocks are passed in to the decorated
function in the same order they applied (the normal *python* order that
decorators are applied). This means from the bottom up, so in the example
above the mock for `test_module.ClassName2` is passed in first.
With `patch` it matters that you patch objects in the namespace where they
are looked up. This is normally straightforward, but for a quick guide
read `where to patch
<http://www.voidspace.org.uk/python/mock/patch.html#where-to-patch>`_.
As well as a decorator `patch` can be used as a context manager in a with
statement::
>>> with patch.object(ProductionClass, 'method') as mock_method:
... mock_method.return_value = None
... real = ProductionClass()
... real.method(1, 2, 3)
...
>>> mock_method.assert_called_once_with(1, 2, 3)
There is also `patch.dict` for setting values in a dictionary just during the
scope of a test and restoring the dictionary to its original state when the
test ends::
>>> foo = {'key': 'value'}
>>> original = foo.copy()
>>> with patch.dict(foo, {'newkey': 'newvalue'}, clear=True):
... assert foo == {'newkey': 'newvalue'}
...
>>> assert foo == original
Mock supports the mocking of Python magic methods. The easiest way of
using magic methods is with the `MagicMock` class. It allows you to do
things like::
>>> from mock import MagicMock
>>> mock = MagicMock()
>>> mock.__str__.return_value = 'foobarbaz'
>>> str(mock)
'foobarbaz'
>>> mock.__str__.assert_called_once_with()
Mock allows you to assign functions (or other Mock instances) to magic methods
and they will be called appropriately. The MagicMock class is just a Mock
variant that has all of the magic methods pre-created for you (well - all the
useful ones anyway).
The following is an example of using magic methods with the ordinary Mock
class::
>>> from mock import Mock
>>> mock = Mock()
>>> mock.__str__ = Mock(return_value = 'wheeeeee')
>>> str(mock)
'wheeeeee'
For ensuring that the mock objects your tests use have the same api as the
objects they are replacing, you can use "auto-speccing". Auto-speccing can
be done through the `autospec` argument to patch, or the `create_autospec`
function. Auto-speccing creates mock objects that have the same attributes
and methods as the objects they are replacing, and any functions and methods
(including constructors) have the same call signature as the real object.
This ensures that your mocks will fail in the same way as your production
code if they are used incorrectly::
>>> from mock import create_autospec
>>> def function(a, b, c):
... pass
...
>>> mock_function = create_autospec(function, return_value='fishy')
>>> mock_function(1, 2, 3)
'fishy'
>>> mock_function.assert_called_once_with(1, 2, 3)
>>> mock_function('wrong arguments')
Traceback (most recent call last):
...
TypeError: <lambda>() takes exactly 3 arguments (1 given)
`create_autospec` can also be used on classes, where it copies the signature of
the `__init__` method, and on callable objects where it copies the signature of
the `__call__` method.
The distribution contains tests and documentation. The tests require
`unittest2 <http://pypi.python.org/pypi/unittest2>`_ to run on Python 2.5, 2.6
or 3.1. For Python 2.7 and 3.2 they can be run with
`python -m unittest discover`.
Docs from the in-development version of `mock` can be found at
`mock.readthedocs.org <http://mock.readthedocs.org>`_.
__author__ = 'Michael Foord'
# -*- coding: utf-8 -*-
#
# Mock documentation build configuration file, created by
# sphinx-quickstart on Mon Nov 17 18:12:00 2008.
#
# This file is execfile()d with the current directory set to its containing dir.
#
# The contents of this file are pickled, so don't put values in the namespace
# that aren't pickleable (module imports are okay, they're removed automatically).
#
# All configuration values have a default value; values that are commented out
# serve to show the default value.
import sys, os
sys.path.insert(0, os.path.abspath('..'))
from mock import __version__
# If your extensions are in another directory, add it here. If the directory
# is relative to the documentation root, use os.path.abspath to make it
# absolute, like shown here.
#sys.path.append(os.path.abspath('some/directory'))
# General configuration
# ---------------------
# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ['sphinx.ext.doctest']
doctest_global_setup = """
import os
import sys
import mock
from mock import * # yeah, I know :-/
import unittest2
import __main__
if os.getcwd() not in sys.path:
sys.path.append(os.getcwd())
# keep a reference to __main__
sys.modules['__main'] = __main__
class ProxyModule(object):
def __init__(self):
self.__dict__ = globals()
sys.modules['__main__'] = ProxyModule()
"""
doctest_global_cleanup = """
sys.modules['__main__'] = sys.modules['__main']
"""
html_theme = 'nature'
html_theme_options = {}
# Add any paths that contain templates here, relative to this directory.
#templates_path = ['_templates']
# The suffix of source filenames.
source_suffix = '.txt'
# The master toctree document.
master_doc = 'index'
# General substitutions.
project = u'Mock'
copyright = u'2007-2012, Michael Foord & the mock team'
# The default replacements for |version| and |release|, also used in various
# other places throughout the built documents.
#
# The short X.Y version.
version = __version__[:3]
# The full version, including alpha/beta/rc tags.
release = __version__
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
# Else, today_fmt is used as the format for a strftime call.
today_fmt = '%B %d, %Y'
# List of documents that shouldn't be included in the build.
#unused_docs = []
# List of directories, relative to source directories, that shouldn't be searched
# for source files.
exclude_trees = []
# The reST default role (used for this markup: `text`) to use for all documents.
#default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
add_module_names = False
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'friendly'
# Options for HTML output
# -----------------------
# The style sheet to use for HTML and HTML Help pages. A file of that name
# must exist either in Sphinx' static/ path, or in one of the custom paths
# given in html_static_path.
#html_style = 'adctheme.css'
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
#html_title = None
# A shorter title for the navigation bar. Default is the same as html_title.
#html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
#html_logo = None
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
#html_favicon = None
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
#html_static_path = ['_static']
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
#html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
#html_additional_pages = {}
# If false, no module index is generated.
html_use_modindex = False
# If false, no index is generated.
#html_use_index = True
# If true, the index is split into individual pages for each letter.
#html_split_index = False
# If true, the reST sources are included in the HTML build as _sources/<name>.
#html_copy_source = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
#html_use_opensearch = ''
# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = ''
# Output file base name for HTML help builder.
htmlhelp_basename = 'Mockdoc'
# Options for LaTeX output
# ------------------------
# The paper size ('letter' or 'a4').
#latex_paper_size = 'letter'
# The font size ('10pt', '11pt' or '12pt').
latex_font_size = '12pt'
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, document class [howto/manual]).
latex_documents = [
('index', 'Mock.tex', u'Mock Documentation',
u'Michael Foord', 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
#latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#latex_use_parts = False
# Additional stuff for the LaTeX preamble.
#latex_preamble = ''
# Documents to append as an appendix to all manuals.
#latex_appendices = []
# If false, no module index is generated.
latex_use_modindex = False
\ No newline at end of file
.. currentmodule:: mock
.. _magic-methods:
Mocking Magic Methods
=====================
.. currentmodule:: mock
:class:`Mock` supports mocking `magic methods
<http://www.ironpythoninaction.com/magic-methods.html>`_. This allows mock
objects to replace containers or other objects that implement Python
protocols.
Because magic methods are looked up differently from normal methods [#]_, this
support has been specially implemented. This means that only specific magic
methods are supported. The supported list includes *almost* all of them. If
there are any missing that you need please let us know!
You mock magic methods by setting the method you are interested in to a function
or a mock instance. If you are using a function then it *must* take ``self`` as
the first argument [#]_.
.. doctest::
>>> def __str__(self):
... return 'fooble'
...
>>> mock = Mock()
>>> mock.__str__ = __str__
>>> str(mock)
'fooble'
>>> mock = Mock()
>>> mock.__str__ = Mock()
>>> mock.__str__.return_value = 'fooble'
>>> str(mock)
'fooble'
>>> mock = Mock()
>>> mock.__iter__ = Mock(return_value=iter([]))
>>> list(mock)
[]
One use case for this is for mocking objects used as context managers in a
`with` statement:
.. doctest::
>>> mock = Mock()
>>> mock.__enter__ = Mock(return_value='foo')
>>> mock.__exit__ = Mock(return_value=False)
>>> with mock as m:
... assert m == 'foo'
...
>>> mock.__enter__.assert_called_with()
>>> mock.__exit__.assert_called_with(None, None, None)
Calls to magic methods do not appear in :attr:`~Mock.method_calls`, but they
are recorded in :attr:`~Mock.mock_calls`.
.. note::
If you use the `spec` keyword argument to create a mock then attempting to
set a magic method that isn't in the spec will raise an `AttributeError`.
The full list of supported magic methods is:
* ``__hash__``, ``__sizeof__``, ``__repr__`` and ``__str__``
* ``__dir__``, ``__format__`` and ``__subclasses__``
* ``__floor__``, ``__trunc__`` and ``__ceil__``
* Comparisons: ``__cmp__``, ``__lt__``, ``__gt__``, ``__le__``, ``__ge__``,
``__eq__`` and ``__ne__``
* Container methods: ``__getitem__``, ``__setitem__``, ``__delitem__``,
``__contains__``, ``__len__``, ``__iter__``, ``__getslice__``,
``__setslice__``, ``__reversed__`` and ``__missing__``
* Context manager: ``__enter__`` and ``__exit__``
* Unary numeric methods: ``__neg__``, ``__pos__`` and ``__invert__``
* The numeric methods (including right hand and in-place variants):
``__add__``, ``__sub__``, ``__mul__``, ``__div__``,
``__floordiv__``, ``__mod__``, ``__divmod__``, ``__lshift__``,
``__rshift__``, ``__and__``, ``__xor__``, ``__or__``, and ``__pow__``
* Numeric conversion methods: ``__complex__``, ``__int__``, ``__float__``,
``__index__`` and ``__coerce__``
* Descriptor methods: ``__get__``, ``__set__`` and ``__delete__``
* Pickling: ``__reduce__``, ``__reduce_ex__``, ``__getinitargs__``,
``__getnewargs__``, ``__getstate__`` and ``__setstate__``
The following methods are supported in Python 2 but don't exist in Python 3:
* ``__unicode__``, ``__long__``, ``__oct__``, ``__hex__`` and ``__nonzero__``
* ``__truediv__`` and ``__rtruediv__``
The following methods are supported in Python 3 but don't exist in Python 2:
* ``__bool__`` and ``__next__``
The following methods exist but are *not* supported as they are either in use by
mock, can't be set dynamically, or can cause problems:
* ``__getattr__``, ``__setattr__``, ``__init__`` and ``__new__``
* ``__prepare__``, ``__instancecheck__``, ``__subclasscheck__``, ``__del__``
Magic Mock
==========
There are two `MagicMock` variants: `MagicMock` and `NonCallableMagicMock`.
.. class:: MagicMock(*args, **kw)
``MagicMock`` is a subclass of :class:`Mock` with default implementations
of most of the magic methods. You can use ``MagicMock`` without having to
configure the magic methods yourself.
The constructor parameters have the same meaning as for :class:`Mock`.
If you use the `spec` or `spec_set` arguments then *only* magic methods
that exist in the spec will be created.
.. class:: NonCallableMagicMock(*args, **kw)
A non-callable version of `MagicMock`.
The constructor parameters have the same meaning as for
:class:`MagicMock`, with the exception of `return_value` and
`side_effect` which have no meaning on a non-callable mock.
The magic methods are setup with `MagicMock` objects, so you can configure them
and use them in the usual way:
.. doctest::
>>> mock = MagicMock()
>>> mock[3] = 'fish'
>>> mock.__setitem__.assert_called_with(3, 'fish')
>>> mock.__getitem__.return_value = 'result'
>>> mock[2]
'result'
By default many of the protocol methods are required to return objects of a
specific type. These methods are preconfigured with a default return value, so
that they can be used without you having to do anything if you aren't interested
in the return value. You can still *set* the return value manually if you want
to change the default.
Methods and their defaults:
* ``__lt__``: NotImplemented
* ``__gt__``: NotImplemented
* ``__le__``: NotImplemented
* ``__ge__``: NotImplemented
* ``__int__`` : 1
* ``__contains__`` : False
* ``__len__`` : 1
* ``__iter__`` : iter([])
* ``__exit__`` : False
* ``__complex__`` : 1j
* ``__float__`` : 1.0
* ``__bool__`` : True
* ``__nonzero__`` : True
* ``__oct__`` : '1'
* ``__hex__`` : '0x1'
* ``__long__`` : long(1)
* ``__index__`` : 1
* ``__hash__`` : default hash for the mock
* ``__str__`` : default str for the mock
* ``__unicode__`` : default unicode for the mock
* ``__sizeof__``: default sizeof for the mock
For example:
.. doctest::
>>> mock = MagicMock()
>>> int(mock)
1
>>> len(mock)
0
>>> hex(mock)
'0x1'
>>> list(mock)
[]
>>> object() in mock
False
The two equality method, `__eq__` and `__ne__`, are special (changed in
0.7.2). They do the default equality comparison on identity, using a side
effect, unless you change their return value to return something else:
.. doctest::
>>> MagicMock() == 3
False
>>> MagicMock() != 3
True
>>> mock = MagicMock()
>>> mock.__eq__.return_value = True
>>> mock == 3
True
In `0.8` the `__iter__` also gained special handling implemented with a
side effect. The return value of `MagicMock.__iter__` can be any iterable
object and isn't required to be an iterator:
.. doctest::
>>> mock = MagicMock()
>>> mock.__iter__.return_value = ['a', 'b', 'c']
>>> list(mock)
['a', 'b', 'c']
>>> list(mock)
['a', 'b', 'c']
If the return value *is* an iterator, then iterating over it once will consume
it and subsequent iterations will result in an empty list:
.. doctest::
>>> mock.__iter__.return_value = iter(['a', 'b', 'c'])
>>> list(mock)
['a', 'b', 'c']
>>> list(mock)
[]
``MagicMock`` has all of the supported magic methods configured except for some
of the obscure and obsolete ones. You can still set these up if you want.
Magic methods that are supported but not setup by default in ``MagicMock`` are:
* ``__cmp__``
* ``__getslice__`` and ``__setslice__``
* ``__coerce__``
* ``__subclasses__``
* ``__dir__``
* ``__format__``
* ``__get__``, ``__set__`` and ``__delete__``
* ``__reversed__`` and ``__missing__``
* ``__reduce__``, ``__reduce_ex__``, ``__getinitargs__``, ``__getnewargs__``,
``__getstate__`` and ``__setstate__``
* ``__getformat__`` and ``__setformat__``
------------
.. [#] Magic methods *should* be looked up on the class rather than the
instance. Different versions of Python are inconsistent about applying this
rule. The supported protocol methods should work with all supported versions
of Python.
.. [#] The function is basically hooked up to the class, but each ``Mock``
instance is kept isolated from the others.
==========
Sentinel
==========
.. currentmodule:: mock
.. testsetup::
class ProductionClass(object):
def something(self):
return self.method()
class Test(unittest2.TestCase):
def testSomething(self):
pass
self = Test('testSomething')
.. data:: sentinel
The ``sentinel`` object provides a convenient way of providing unique
objects for your tests.
Attributes are created on demand when you access them by name. Accessing
the same attribute will always return the same object. The objects
returned have a sensible repr so that test failure messages are readable.
.. data:: DEFAULT
The `DEFAULT` object is a pre-created sentinel (actually
`sentinel.DEFAULT`). It can be used by :attr:`~Mock.side_effect`
functions to indicate that the normal return value should be used.
Sentinel Example
================
Sometimes when testing you need to test that a specific object is passed as an
argument to another method, or returned. It can be common to create named
sentinel objects to test this. `sentinel` provides a convenient way of
creating and testing the identity of objects like this.
In this example we monkey patch `method` to return
`sentinel.some_object`:
.. doctest::
>>> real = ProductionClass()
>>> real.method = Mock(name="method")
>>> real.method.return_value = sentinel.some_object
>>> result = real.method()
>>> assert result is sentinel.some_object
>>> sentinel.some_object
sentinel.some_object
# merged into mock.py in Mock 0.7
#!wing
#!version=4.0
##################################################################
# Wing IDE project file #
##################################################################
[project attributes]
proj.directory-list = [{'dirloc': loc('.'),
'excludes': [u'latex',
u'.hg',
u'.tox',
u'dist',
u'htmlcov',
u'extendmock.py',
u'__pycache__',
u'html',
u'build',
u'mock.egg-info',
u'tests/__pycache__',
u'.hgignore',
u'.hgtags'],
'filter': '*',
'include_hidden': 0,
'recursive': 1,
'watch_for_changes': 1}]
proj.file-type = 'shared'
testing.auto-test-file-specs = ('test*.py',)
[build_sphinx]
source-dir=docs
build-dir=html
[sdist]
force-manifest = 1
#! /usr/bin/env python
# Copyright (C) 2007-2012 Michael Foord & the mock team
# E-mail: fuzzyman AT voidspace DOT org DOT uk
# http://www.voidspace.org.uk/python/mock/
import os
from src.test.mock.mock import __version__
NAME = 'mock'
MODULES = ['mock']
DESCRIPTION = 'A Python Mocking and Patching Library for Testing'
URL = "http://www.voidspace.org.uk/python/mock/"
readme = os.path.join(os.path.dirname(__file__), 'README.txt')
LONG_DESCRIPTION = open(readme).read()
CLASSIFIERS = [
'Development Status :: 5 - Production/Stable',
'Environment :: Console',
'Intended Audience :: Developers',
'License :: OSI Approved :: BSD License',
'Programming Language :: Python',
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 2.5',
'Programming Language :: Python :: 2.6',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3.1',
'Programming Language :: Python :: 3.2',
'Programming Language :: Python :: 3.3',
'Programming Language :: Python :: Implementation :: CPython',
'Programming Language :: Python :: Implementation :: PyPy',
'Programming Language :: Python :: Implementation :: Jython',
'Operating System :: OS Independent',
'Topic :: Software Development :: Libraries',
'Topic :: Software Development :: Libraries :: Python Modules',
'Topic :: Software Development :: Testing',
]
AUTHOR = 'Michael Foord'
AUTHOR_EMAIL = 'michael@voidspace.org.uk'
KEYWORDS = ("testing test mock mocking unittest patching "
"stubs fakes doubles").split(' ')
params = dict(
name=NAME,
version=__version__,
py_modules=MODULES,
# metadata for upload to PyPI
author=AUTHOR,
author_email=AUTHOR_EMAIL,
description=DESCRIPTION,
long_description=LONG_DESCRIPTION,
keywords=KEYWORDS,
url=URL,
classifiers=CLASSIFIERS,
)
try:
from setuptools import setup
except ImportError:
from distutils.core import setup
else:
params['tests_require'] = ['unittest2']
params['test_suite'] = 'unittest2.collector'
setup(**params)
# Copyright (C) 2007-2012 Michael Foord & the mock team
# E-mail: fuzzyman AT voidspace DOT org DOT uk
# http://www.voidspace.org.uk/python/mock/
# Copyright (C) 2007-2012 Michael Foord & the mock team
# E-mail: fuzzyman AT voidspace DOT org DOT uk
# http://www.voidspace.org.uk/python/mock/
from __future__ import with_statement
from tests.support import unittest2, is_instance
from mock import MagicMock, Mock, patch, sentinel, mock_open, call
from tests.support_with import catch_warnings, nested
something = sentinel.Something
something_else = sentinel.SomethingElse
class WithTest(unittest2.TestCase):
def test_with_statement(self):
with patch('tests._testwith.something', sentinel.Something2):
self.assertEqual(something, sentinel.Something2, "unpatched")
self.assertEqual(something, sentinel.Something)
def test_with_statement_exception(self):
try:
with patch('tests._testwith.something', sentinel.Something2):
self.assertEqual(something, sentinel.Something2, "unpatched")
raise Exception('pow')
except Exception:
pass
else:
self.fail("patch swallowed exception")
self.assertEqual(something, sentinel.Something)
def test_with_statement_as(self):
with patch('tests._testwith.something') as mock_something:
self.assertEqual(something, mock_something, "unpatched")
self.assertTrue(is_instance(mock_something, MagicMock),
"patching wrong type")
self.assertEqual(something, sentinel.Something)
def test_patch_object_with_statement(self):
class Foo(object):
something = 'foo'
original = Foo.something
with patch.object(Foo, 'something'):
self.assertNotEqual(Foo.something, original, "unpatched")
self.assertEqual(Foo.something, original)
def test_with_statement_nested(self):
with catch_warnings(record=True):
# nested is deprecated in Python 2.7
with nested(patch('tests._testwith.something'),
patch('tests._testwith.something_else')) as (mock_something, mock_something_else):
self.assertEqual(something, mock_something, "unpatched")
self.assertEqual(something_else, mock_something_else,
"unpatched")
self.assertEqual(something, sentinel.Something)
self.assertEqual(something_else, sentinel.SomethingElse)
def test_with_statement_specified(self):
with patch('tests._testwith.something', sentinel.Patched) as mock_something:
self.assertEqual(something, mock_something, "unpatched")
self.assertEqual(mock_something, sentinel.Patched, "wrong patch")
self.assertEqual(something, sentinel.Something)
def testContextManagerMocking(self):
mock = Mock()
mock.__enter__ = Mock()
mock.__exit__ = Mock()
mock.__exit__.return_value = False
with mock as m:
self.assertEqual(m, mock.__enter__.return_value)
mock.__enter__.assert_called_with()
mock.__exit__.assert_called_with(None, None, None)
def test_context_manager_with_magic_mock(self):
mock = MagicMock()
with self.assertRaises(TypeError):
with mock:
'foo' + 3
mock.__enter__.assert_called_with()
self.assertTrue(mock.__exit__.called)
def test_with_statement_same_attribute(self):
with patch('tests._testwith.something', sentinel.Patched) as mock_something:
self.assertEqual(something, mock_something, "unpatched")
with patch('tests._testwith.something') as mock_again:
self.assertEqual(something, mock_again, "unpatched")
self.assertEqual(something, mock_something,
"restored with wrong instance")
self.assertEqual(something, sentinel.Something, "not restored")
def test_with_statement_imbricated(self):
with patch('tests._testwith.something') as mock_something:
self.assertEqual(something, mock_something, "unpatched")
with patch('tests._testwith.something_else') as mock_something_else:
self.assertEqual(something_else, mock_something_else,
"unpatched")
self.assertEqual(something, sentinel.Something)
self.assertEqual(something_else, sentinel.SomethingElse)
def test_dict_context_manager(self):
foo = {}
with patch.dict(foo, {'a': 'b'}):
self.assertEqual(foo, {'a': 'b'})
self.assertEqual(foo, {})
with self.assertRaises(NameError):
with patch.dict(foo, {'a': 'b'}):
self.assertEqual(foo, {'a': 'b'})
raise NameError('Konrad')
self.assertEqual(foo, {})
class TestMockOpen(unittest2.TestCase):
def test_mock_open(self):
mock = mock_open()
with patch('%s.open' % __name__, mock, create=True) as patched:
self.assertIs(patched, mock)
open('foo')
mock.assert_called_once_with('foo')
def test_mock_open_context_manager(self):
mock = mock_open()
handle = mock.return_value
with patch('%s.open' % __name__, mock, create=True):
with open('foo') as f:
f.read()
expected_calls = [call('foo'), call().__enter__(), call().read(),
call().__exit__(None, None, None)]
self.assertEqual(mock.mock_calls, expected_calls)
self.assertIs(f, handle)
def test_explicit_mock(self):
mock = MagicMock()
mock_open(mock)
with patch('%s.open' % __name__, mock, create=True) as patched:
self.assertIs(patched, mock)
open('foo')
mock.assert_called_once_with('foo')
def test_read_data(self):
mock = mock_open(read_data='foo')
with patch('%s.open' % __name__, mock, create=True):
h = open('bar')
result = h.read()
self.assertEqual(result, 'foo')
if __name__ == '__main__':
unittest2.main()
import sys
info = sys.version_info
if info[:3] >= (3, 2, 0):
# for Python 3.2 ordinary unittest is fine
import unittest as unittest2
else:
import unittest2
try:
callable = callable
except NameError:
def callable(obj):
return hasattr(obj, '__call__')
inPy3k = sys.version_info[0] == 3
with_available = sys.version_info[:2] >= (2, 5)
def is_instance(obj, klass):
"""Version of is_instance that doesn't access __class__"""
return issubclass(type(obj), klass)
class SomeClass(object):
class_attribute = None
def wibble(self):
pass
class X(object):
pass
try:
next = next
except NameError:
def next(obj):
return obj.next()
from __future__ import with_statement
import sys
__all__ = ['nested', 'catch_warnings', 'examine_warnings']
try:
from contextlib import nested
except ImportError:
from contextlib import contextmanager
@contextmanager
def nested(*managers):
exits = []
vars = []
exc = (None, None, None)
try:
for mgr in managers:
exit = mgr.__exit__
enter = mgr.__enter__
vars.append(enter())
exits.append(exit)
yield vars
except:
exc = sys.exc_info()
finally:
while exits:
exit = exits.pop()
try:
if exit(*exc):
exc = (None, None, None)
except:
exc = sys.exc_info()
if exc != (None, None, None):
raise exc[1]
# copied from Python 2.6
try:
from warnings import catch_warnings
except ImportError:
class catch_warnings(object):
def __init__(self, record=False, module=None):
self._record = record
self._module = sys.modules['warnings']
self._entered = False
def __repr__(self):
args = []
if self._record:
args.append("record=True")
name = type(self).__name__
return "%s(%s)" % (name, ", ".join(args))
def __enter__(self):
if self._entered:
raise RuntimeError("Cannot enter %r twice" % self)
self._entered = True
self._filters = self._module.filters
self._module.filters = self._filters[:]
self._showwarning = self._module.showwarning
if self._record:
log = []
def showwarning(*args, **kwargs):
log.append(WarningMessage(*args, **kwargs))
self._module.showwarning = showwarning
return log
else:
return None
def __exit__(self, *exc_info):
if not self._entered:
raise RuntimeError("Cannot exit %r without entering first" % self)
self._module.filters = self._filters
self._module.showwarning = self._showwarning
class WarningMessage(object):
_WARNING_DETAILS = ("message", "category", "filename", "lineno", "file",
"line")
def __init__(self, message, category, filename, lineno, file=None,
line=None):
local_values = locals()
for attr in self._WARNING_DETAILS:
setattr(self, attr, local_values[attr])
self._category_name = None
if category.__name__:
self._category_name = category.__name__
def examine_warnings(func):
def wrapper():
with catch_warnings(record=True) as ws:
func(ws)
return wrapper
# Copyright (C) 2007-2012 Michael Foord & the mock team
# E-mail: fuzzyman AT voidspace DOT org DOT uk
# http://www.voidspace.org.uk/python/mock/
from tests.support import is_instance, unittest2, X, SomeClass
from mock import (
Mock, MagicMock, NonCallableMagicMock,
NonCallableMock, patch, create_autospec,
CallableMixin
)
class TestCallable(unittest2.TestCase):
def assertNotCallable(self, mock):
self.assertTrue(is_instance(mock, NonCallableMagicMock))
self.assertFalse(is_instance(mock, CallableMixin))
def test_non_callable(self):
for mock in NonCallableMagicMock(), NonCallableMock():
self.assertRaises(TypeError, mock)
self.assertFalse(hasattr(mock, '__call__'))
self.assertIn(mock.__class__.__name__, repr(mock))
def test_heirarchy(self):
self.assertTrue(issubclass(MagicMock, Mock))
self.assertTrue(issubclass(NonCallableMagicMock, NonCallableMock))
def test_attributes(self):
one = NonCallableMock()
self.assertTrue(issubclass(type(one.one), Mock))
two = NonCallableMagicMock()
self.assertTrue(issubclass(type(two.two), MagicMock))
def test_subclasses(self):
class MockSub(Mock):
pass
one = MockSub()
self.assertTrue(issubclass(type(one.one), MockSub))
class MagicSub(MagicMock):
pass
two = MagicSub()
self.assertTrue(issubclass(type(two.two), MagicSub))
def test_patch_spec(self):
patcher = patch('%s.X' % __name__, spec=True)
mock = patcher.start()
self.addCleanup(patcher.stop)
instance = mock()
mock.assert_called_once_with()
self.assertNotCallable(instance)
self.assertRaises(TypeError, instance)
def test_patch_spec_set(self):
patcher = patch('%s.X' % __name__, spec_set=True)
mock = patcher.start()
self.addCleanup(patcher.stop)
instance = mock()
mock.assert_called_once_with()
self.assertNotCallable(instance)
self.assertRaises(TypeError, instance)
def test_patch_spec_instance(self):
patcher = patch('%s.X' % __name__, spec=X())
mock = patcher.start()
self.addCleanup(patcher.stop)
self.assertNotCallable(mock)
self.assertRaises(TypeError, mock)
def test_patch_spec_set_instance(self):
patcher = patch('%s.X' % __name__, spec_set=X())
mock = patcher.start()
self.addCleanup(patcher.stop)
self.assertNotCallable(mock)
self.assertRaises(TypeError, mock)
def test_patch_spec_callable_class(self):
class CallableX(X):
def __call__(self):
pass
class Sub(CallableX):
pass
class Multi(SomeClass, Sub):
pass
class OldStyle:
def __call__(self):
pass
class OldStyleSub(OldStyle):
pass
for arg in 'spec', 'spec_set':
for Klass in CallableX, Sub, Multi, OldStyle, OldStyleSub:
patcher = patch('%s.X' % __name__, **{arg: Klass})
mock = patcher.start()
try:
instance = mock()
mock.assert_called_once_with()
self.assertTrue(is_instance(instance, MagicMock))
# inherited spec
self.assertRaises(AttributeError, getattr, instance,
'foobarbaz')
result = instance()
# instance is callable, result has no spec
instance.assert_called_once_with()
result(3, 2, 1)
result.assert_called_once_with(3, 2, 1)
result.foo(3, 2, 1)
result.foo.assert_called_once_with(3, 2, 1)
finally:
patcher.stop()
def test_create_autopsec(self):
mock = create_autospec(X)
instance = mock()
self.assertRaises(TypeError, instance)
mock = create_autospec(X())
self.assertRaises(TypeError, mock)
def test_create_autospec_instance(self):
mock = create_autospec(SomeClass, instance=True)
self.assertRaises(TypeError, mock)
mock.wibble()
mock.wibble.assert_called_once_with()
self.assertRaises(TypeError, mock.wibble, 'some', 'args')
# Copyright (C) 2007-2012 Michael Foord & the mock team
# E-mail: fuzzyman AT voidspace DOT org DOT uk
# http://www.voidspace.org.uk/python/mock/
from tests.support import unittest2
from mock import sentinel, DEFAULT
class SentinelTest(unittest2.TestCase):
def testSentinels(self):
self.assertEqual(sentinel.whatever, sentinel.whatever,
'sentinel not stored')
self.assertNotEqual(sentinel.whatever, sentinel.whateverelse,
'sentinel should be unique')
def testSentinelName(self):
self.assertEqual(str(sentinel.whatever), 'sentinel.whatever',
'sentinel name incorrect')
def testDEFAULT(self):
self.assertTrue(DEFAULT is sentinel.DEFAULT)
def testBases(self):
# If this doesn't raise an AttributeError then help(mock) is broken
self.assertRaises(AttributeError, lambda: sentinel.__bases__)
if __name__ == '__main__':
unittest2.main()
import sys
if sys.version_info[:2] >= (2, 5):
from tests._testwith import *
else:
from tests.support import unittest2
class TestWith(unittest2.TestCase):
@unittest2.skip('tests using with statement skipped on Python 2.4')
def testWith(self):
pass
if __name__ == '__main__':
unittest2.main()
[tox]
envlist = py25,py26,py27,py31,pypy,py32,py33,jython
[testenv]
deps=unittest2
commands={envbindir}/unit2 discover []
[testenv:py26]
commands=
{envbindir}/unit2 discover []
{envbindir}/sphinx-build -E -b doctest docs html
{envbindir}/sphinx-build -E docs html
deps =
unittest2
sphinx
[testenv:py27]
commands=
{envbindir}/unit2 discover []
{envbindir}/sphinx-build -E -b doctest docs html
deps =
unittest2
sphinx
[testenv:py31]
deps =
unittest2py3k
[testenv:py32]
commands=
{envbindir}/python -m unittest discover []
deps =
[testenv:py33]
commands=
{envbindir}/python -m unittest discover []
deps =
# note for jython. Execute in tests directory:
# rm `find . -name '*$py.class'`
\ No newline at end of file
[unittest]
plugins =
unittest2.plugins.debugger
unittest2.plugins.checker
unittest2.plugins.doctestloader
unittest2.plugins.matchregexp
unittest2.plugins.moduleloading
unittest2.plugins.testcoverage
unittest2.plugins.growl
unittest2.plugins.filtertests
unittest2.plugins.junitxml
unittest2.plugins.timed
unittest2.plugins.counttests
unittest2.plugins.logchannels
excluded-plugins =
# 0, 1 or 2 (default is 1)
# quiet, normal or verbose
# can be overriden at command line
verbosity = normal
# true or false
# even if false can be switched on at command line
catch =
buffer =
failfast =
[matchregexp]
always-on = False
full-path = True
[debugger]
always-on = False
errors-only = True
[coverage]
always-on = False
config =
report-html = False
# only used if report-html is false
annotate = False
# defaults to './htmlcov/'
html-directory =
# if unset will output to console
text-file =
branch = False
timid = False
cover-pylib = False
exclude-lines =
# Have to re-enable the standard pragma
pragma: no cover
# Don't complain about missing debug-only code:
def __repr__
if self\.debug
# Don't complain if tests don't hit defensive assertion code:
raise AssertionError
raise NotImplementedError
# Don't complain if non-runnable code isn't run:
if 0:
if __name__ == .__main__.
ignore-errors = False
modules =
[growl]
always-on = False
[doctest]
always-on = False
[module-loading]
always-on = False
[checker]
always-on = False
pep8 = False
pyflakes = True
[junit-xml]
always-on = False
path = junit.xml
[timed]
always-on = True
threshold = 0.01
[count]
always-on = True
enhanced = False
#!/usr/bin/env python
'''
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
'''
import sys
from mock import patch
import unittest
import logging
import metadata_config as mc
import metadata_start as metadata
import platform
IS_WINDOWS = platform.system() == "Windows"
logger = logging.getLogger()
class TestMetadata(unittest.TestCase):
@patch.object(mc,"writePid")
@patch.object(mc, "executeEnvSh")
@patch.object(mc,"metadataDir")
@patch.object(mc, "expandWebApp")
@patch("os.path.exists")
@patch.object(mc, "java")
def test_main(self, java_mock, exists_mock, expandWebApp_mock, metadataDir_mock, executeEnvSh_mock, writePid_mock):
sys.argv = []
exists_mock.return_value = True
expandWebApp_mock.return_value = "webapp"
metadataDir_mock.return_value = "metadata_home"
metadata.main()
self.assertTrue(java_mock.called)
if IS_WINDOWS:
java_mock.assert_called_with(
'org.apache.hadoop.metadata.Main',
['-app', 'metadata_home/server/webapp/metadata'],
'metadata_home/conf:metadata_home/server/webapp/metadata/WEB-INF/classes:metadata_home/server/webapp/metadata/WEB-INF/lib\\*:metadata_home/libext\\*',
['-Dmetadata.log.dir=metadata_home/logs', '-Dmetadata.home=metadata_home', '-Xmx1024m'])
else:
java_mock.assert_called_with(
'org.apache.hadoop.metadata.Main',
['-app', 'metadata_home/server/webapp/metadata'],
'metadata_home/conf:metadata_home/server/webapp/metadata/WEB-INF/classes:metadata_home/server/webapp/metadata/WEB-INF/lib/*:metadata_home/libext/*',
['-Dmetadata.log.dir=metadata_home/logs', '-Dmetadata.home=metadata_home', '-Xmx1024m'])
pass
if __name__ == "__main__":
logging.basicConfig(format='%(asctime)s %(message)s', level=logging.DEBUG)
unittest.main()
\ No newline at end of file
#!/usr/bin/env python
"""
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""
import unittest
from os.path import isdir
import logging
import os
import sys
LOG_FILE_NAME='tests.log'
SELECTED_PREFIX = "_"
PY_EXT='.py'
ignoredDirs = ["mock"]
class TestAgent(unittest.TestSuite):
def run(self, result, debug=False):
run = unittest.TestSuite.run
run(self, result)
return result
def parent_dir(path):
if isdir(path):
if path.endswith(os.sep):
path = os.path.dirname(path)
parent = os.path.dirname(path)
else:
parent = os.path.dirname(os.path.dirname(path))
return parent
def all_tests_suite():
root_dir = os.getcwd()
files_list = []
for directory in os.listdir(root_dir):
if os.path.isdir(directory) and not directory in ignoredDirs:
files_list += os.listdir(root_dir + os.sep + directory)
## temporarily deleting to add more predictability
## shuffle(files_list)
files_list.sort()
tests_list = []
logger.info('------------------------TESTS LIST:-------------------------------------')
# If test with special name exists, run only this test
selected_test = None
for file_name in files_list:
if file_name.endswith(PY_EXT) and not file_name == __file__ and file_name.startswith(SELECTED_PREFIX):
logger.info("Running only selected test " + str(file_name))
selected_test = file_name
if selected_test is not None:
tests_list.append(selected_test.replace(PY_EXT, ''))
else:
for file_name in files_list:
if file_name.endswith(PY_EXT) and not file_name == __file__:
replaced = file_name.replace(PY_EXT, '')
logger.info(replaced)
tests_list.append(replaced)
logger.info('------------------------------------------------------------------------')
suite = unittest.TestLoader().loadTestsFromNames(tests_list)
return TestAgent([suite])
def main():
logger.info('------------------------------------------------------------------------')
logger.info('PYTHON SCRIPT TESTS')
logger.info('------------------------------------------------------------------------')
runner = unittest.TextTestRunner(verbosity=2, stream=sys.stdout)
suite = all_tests_suite()
status = runner.run(suite).wasSuccessful()
if not status:
logger.error('-----------------------------------------------------------------------')
logger.error('Python unit tests failed')
logger.error('Find detailed logs in ' + path)
logger.error('-----------------------------------------------------------------------')
exit(1)
else:
logger.info('------------------------------------------------------------------------')
logger.info('Python unit tests finished succesfully')
logger.info('------------------------------------------------------------------------')
if __name__ == '__main__':
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) + os.sep + 'main' + os.sep + 'python')
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) + os.sep + 'main' + os.sep + 'python' + os.sep + 'agent')
logger = logging.getLogger()
logger.setLevel(logging.INFO)
formatter = logging.Formatter("[%(levelname)s] %(message)s")
src_dir = os.getcwd()
target_dir = parent_dir(parent_dir(parent_dir(src_dir))) + os.sep + 'target'
if not os.path.exists(target_dir):
os.mkdir(target_dir)
path = target_dir + os.sep + LOG_FILE_NAME
file=open(path, "w")
consoleLog = logging.StreamHandler(file)
consoleLog.setFormatter(formatter)
logger.addHandler(consoleLog)
main()
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment