systemfixtures-0.6.7/0000755000175000017500000000000013545107112014525 5ustar freefree00000000000000systemfixtures-0.6.7/.coveragerc.py20000644000175000017500000000010013544465154017362 0ustar freefree00000000000000[report] exclude_lines = # pragma: no cover if six.PY3: systemfixtures-0.6.7/.coveragerc.py30000644000175000017500000000007613544465154017377 0ustar freefree00000000000000[report] exclude_lines = pragma: no cover if six.PY2: systemfixtures-0.6.7/AUTHORS0000644000175000017500000000023313545107111015572 0ustar freefree00000000000000Alexandre Gomes Alexandre Gomes Free Ekanayaka bjornt systemfixtures-0.6.7/ChangeLog0000644000175000017500000000235513545107111016303 0ustar freefree00000000000000CHANGES ======= 0.6.7 ----- * Make use of cwd in wget (#6) 0.6.6 ----- * Make wget works with no output argument (#5) * Add new timestamping flag to wget (#3) * Add Python 3.6 to the test matrix * Add more functions to be mocked by FakeFilesystem: (#1) 0.6.5 ----- * Move repository to github.com/testing-cabal, update pointers accordingly 0.6.4 ----- * Support os.rename in FakeFilesystem 0.6.3 ----- * Add FakeExecutable.log method and include timestamps in test\_listen 0.6.2 ----- * Add a mailmap file for unique AUTHORS entries * Add logging to FakeExecutable.hang() * Point the README to Read the Docs * Streamline development process * Make the FakeExecutableTest.test\_listen test more robust 0.6.1 ----- * Fix flakiness in FakeExecutable tests 0.6.0 ----- * Add FakeExecutable fixture for creating a Python script that behaves like some real executable 0.5.1 ----- * Add new FakeThreads fixture * Add FakeTime.reset method, as convenient passthrough to fakesleep.reset 0.4.3 ----- * Add documentation about filing issues 0.4.2 ----- * Add a section in the README pointing to the GitHub project * Fix unit tests failures when running as root 0.4.1 ----- * Don't include .travis.yml in the tarball 0.4.0 ----- * Initial release systemfixtures-0.6.7/HACKING.rst0000644000175000017500000000172413544465154016343 0ustar freefree00000000000000Run the tests ============= You can run the tests using either system packages or a tox-generated virtualenv. System packages --------------- Using system packages makes test runs significantly faster. If you are on a Debian-based system, install the relevant dependencies once with: .. code:: shell make dependencies Then you can run tests with: .. code:: shell make The default Python version is 2, to run tests against Python 3 just prepend `PYTHON=python3` to the make commands above, for example: .. code:: shell PYTHON=python3 make Tox --- Using tox to run the tests is easier since you won't have to deal with not-packaged or not-recent-enough versions in your system, but it's also a tad slower. Just run: .. code:: shell tox Cutting a release ================= Tag and sign the new version: .. code:: shell git tag -s X.Y.Z Upload to PyPI: .. code:: shell python3 setup.py sdist bdist_wheel upload -r pypi --sign -i systemfixtures-0.6.7/LICENSE0000644000175000017500000000204213544465154015544 0ustar freefree00000000000000Copyright (c) 2016 Free Ekanayaka Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. systemfixtures-0.6.7/MANIFEST.in0000644000175000017500000000004513544465154016276 0ustar freefree00000000000000exclude .travis.yml exclude .mailmap systemfixtures-0.6.7/Makefile0000644000175000017500000000225513544465154016205 0ustar freefree00000000000000PYTHON ?= python PYTHON_MAJOR = $(shell $(PYTHON) -c "import sys; print(sys.version_info.major)") # These paths are valid on Debian-based systems, on other systems you # might have to set these variables from the command line. COVERAGE ?= $(PYTHON)-coverage SPHINXBUILD ?= /usr/share/sphinx/scripts/python$(PYTHON_MAJOR)/sphinx-build SOURCE = systemfixtures all: check check-doc check: rm -f .coverage $(COVERAGE) run --source=$(SOURCE) -m testtools.run discover $(COVERAGE) report -m --fail-under=100 --rcfile=.coveragerc.py$(PYTHON_MAJOR) check-doc: SPHINXBUILD=$(SPHINXBUILD) $(MAKE) -C doc doctest dependencies: dependencies-python$(PYTHON_MAJOR) sudo apt-get install \ $(PYTHON)-pbr \ $(PYTHON)-six \ $(PYTHON)-fixtures \ $(PYTHON)-testtools \ $(PYTHON)-requests-mock \ $(PYTHON)-fakesleep \ $(PYTHON)-coverage \ $(PYTHON)-sphinx dependencies-python2: sudo apt-get install \ $(PYTHON)-subprocess32 dependencies-python3): clean: rm -rf $(SOURCE).egg-info dist rm -f AUTHORS ChangeLog find -type f -name "*.pyc" | xargs rm -f find -type d -name "__pycache_" | xargs rm -rf .PHONY: all check check-doc dependencies dependencies-python2 dependencies-python3 systemfixtures-0.6.7/PKG-INFO0000644000175000017500000000527413545107112015632 0ustar freefree00000000000000Metadata-Version: 2.1 Name: systemfixtures Version: 0.6.7 Summary: Test fixtures for providing fake versions of various system resources (processes, users, groups, etc.) Home-page: https://github.com/testing-cabal/systemfixtures Author: Free Ekanayaka Author-email: free@ekanayaka.io License: MIT Description: System fixtures =============== .. image:: https://img.shields.io/pypi/v/systemfixtures.svg :target: https://pypi.python.org/pypi/systemfixtures :alt: Latest Version .. image:: https://travis-ci.org/testing-cabal/systemfixtures.svg?branch=master :target: https://travis-ci.org/testing-cabal/systemfixtures :alt: Build Status .. image:: https://coveralls.io/repos/github/testing-cabal/systemfixtures/badge.svg?branch=master :target: https://coveralls.io/github/testing-cabal/systemfixtures?branch=master :alt: Coverage .. image:: https://readthedocs.org/projects/systemfixtures/badge/?version=latest :target: http://systemfixtures.readthedocs.io/en/latest/?badge=latest :alt: Documentation Status A collection of Python fixtures_ to fake out various system resources (processes, users, groups, etc.). .. _fixtures: https://github.com/testing-cabal/fixtures Each fake resource typically behaves as an "overlay" on the real resource, in that it can be programmed with fake behavior for a set of inputs, but falls back to the real behavior for the rest. .. code:: python >>> import pwd >>> from systemfixtures import FakeUsers >>> users = FakeUsers() >>> users.setUp() >>> pwd.getpwnam("foo") Traceback (most recent call last): ... KeyError: 'getpwnam(): name not found: foo' >>> users.add("foo", 123) >>> info = pwd.getpwnam("foo") >>> info.pw_uid 123 >>> users.cleanUp() Support and Documentation ------------------------- See the `online documentation `_ for a complete reference. Developing and Contributing --------------------------- See the `GitHub project `_. Bugs can be filed in the issues tracker. Platform: POSIX Classifier: License :: OSI Approved :: MIT License Classifier: Operating System :: POSIX Classifier: Programming Language :: Python :: 3 Provides-Extra: test systemfixtures-0.6.7/README.rst0000644000175000017500000000336613544465154016240 0ustar freefree00000000000000System fixtures =============== .. image:: https://img.shields.io/pypi/v/systemfixtures.svg :target: https://pypi.python.org/pypi/systemfixtures :alt: Latest Version .. image:: https://travis-ci.org/testing-cabal/systemfixtures.svg?branch=master :target: https://travis-ci.org/testing-cabal/systemfixtures :alt: Build Status .. image:: https://coveralls.io/repos/github/testing-cabal/systemfixtures/badge.svg?branch=master :target: https://coveralls.io/github/testing-cabal/systemfixtures?branch=master :alt: Coverage .. image:: https://readthedocs.org/projects/systemfixtures/badge/?version=latest :target: http://systemfixtures.readthedocs.io/en/latest/?badge=latest :alt: Documentation Status A collection of Python fixtures_ to fake out various system resources (processes, users, groups, etc.). .. _fixtures: https://github.com/testing-cabal/fixtures Each fake resource typically behaves as an "overlay" on the real resource, in that it can be programmed with fake behavior for a set of inputs, but falls back to the real behavior for the rest. .. code:: python >>> import pwd >>> from systemfixtures import FakeUsers >>> users = FakeUsers() >>> users.setUp() >>> pwd.getpwnam("foo") Traceback (most recent call last): ... KeyError: 'getpwnam(): name not found: foo' >>> users.add("foo", 123) >>> info = pwd.getpwnam("foo") >>> info.pw_uid 123 >>> users.cleanUp() Support and Documentation ------------------------- See the `online documentation `_ for a complete reference. Developing and Contributing --------------------------- See the `GitHub project `_. Bugs can be filed in the issues tracker. systemfixtures-0.6.7/doc/0000755000175000017500000000000013545107112015272 5ustar freefree00000000000000systemfixtures-0.6.7/doc/Makefile0000644000175000017500000001701113544465154016746 0ustar freefree00000000000000# Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD ?= sphinx-build PAPER = BUILDDIR = _build # User-friendly check for sphinx-build ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) endif # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . # the i18n builder cannot share the environment and doctrees with the others I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . .PHONY: help help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " dirhtml to make HTML files named index.html in directories" @echo " singlehtml to make a single large HTML file" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " applehelp to make an Apple Help Book" @echo " devhelp to make HTML files and a Devhelp project" @echo " epub to make an epub" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " latexpdf to make LaTeX files and run them through pdflatex" @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" @echo " text to make text files" @echo " man to make manual pages" @echo " texinfo to make Texinfo files" @echo " info to make Texinfo files and run them through makeinfo" @echo " gettext to make PO message catalogs" @echo " changes to make an overview of all changed/added/deprecated items" @echo " xml to make Docutils-native XML files" @echo " pseudoxml to make pseudoxml-XML files for display purposes" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" @echo " coverage to run coverage check of the documentation (if enabled)" .PHONY: clean clean: rm -rf $(BUILDDIR)/* .PHONY: html html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." .PHONY: dirhtml dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." .PHONY: singlehtml singlehtml: $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml @echo @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." .PHONY: pickle pickle: $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle @echo @echo "Build finished; now you can process the pickle files." .PHONY: json json: $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json @echo @echo "Build finished; now you can process the JSON files." .PHONY: htmlhelp htmlhelp: $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(BUILDDIR)/htmlhelp." .PHONY: qthelp qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in $(BUILDDIR)/qthelp, like this:" @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/systemfixtures.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/systemfixtures.qhc" .PHONY: applehelp applehelp: $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp @echo @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." @echo "N.B. You won't be able to view it unless you put it in" \ "~/Library/Documentation/Help or install it in your application" \ "bundle." .PHONY: devhelp devhelp: $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp @echo @echo "Build finished." @echo "To view the help file:" @echo "# mkdir -p $$HOME/.local/share/devhelp/systemfixtures" @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/systemfixtures" @echo "# devhelp" .PHONY: epub epub: $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub @echo @echo "Build finished. The epub file is in $(BUILDDIR)/epub." .PHONY: latex latex: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." @echo "Run \`make' in that directory to run these through (pdf)latex" \ "(use \`make latexpdf' here to do that automatically)." .PHONY: latexpdf latexpdf: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through pdflatex..." $(MAKE) -C $(BUILDDIR)/latex all-pdf @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." .PHONY: latexpdfja latexpdfja: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through platex and dvipdfmx..." $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." .PHONY: text text: $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text @echo @echo "Build finished. The text files are in $(BUILDDIR)/text." .PHONY: man man: $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man @echo @echo "Build finished. The manual pages are in $(BUILDDIR)/man." .PHONY: texinfo texinfo: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." @echo "Run \`make' in that directory to run these through makeinfo" \ "(use \`make info' here to do that automatically)." .PHONY: info info: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo "Running Texinfo files through makeinfo..." make -C $(BUILDDIR)/texinfo info @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." .PHONY: gettext gettext: $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale @echo @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." .PHONY: changes changes: $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes @echo @echo "The overview file is in $(BUILDDIR)/changes." .PHONY: linkcheck linkcheck: $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDDIR)/linkcheck/output.txt." .PHONY: doctest doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in $(BUILDDIR)/doctest/output.txt." .PHONY: coverage coverage: $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage @echo "Testing of coverage in the sources finished, look at the " \ "results in $(BUILDDIR)/coverage/python.txt." .PHONY: xml xml: $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml @echo @echo "Build finished. The XML files are in $(BUILDDIR)/xml." .PHONY: pseudoxml pseudoxml: $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml @echo @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." systemfixtures-0.6.7/doc/_static/0000755000175000017500000000000013545107112016720 5ustar freefree00000000000000systemfixtures-0.6.7/doc/_static/.placeholder0000644000175000017500000000000013544465154021205 0ustar freefree00000000000000systemfixtures-0.6.7/doc/conf.py0000644000175000017500000002361213544465154016611 0ustar freefree00000000000000#!/usr/bin/env python3 # -*- coding: utf-8 -*- # # systemfixtures documentation build configuration file, created by # sphinx-quickstart on Thu Oct 27 06:54:09 2016. # # This file is execfile()d with the current directory set to its # containing dir. # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. import sys import os import re import doctest import six # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. sys.path.insert(0, os.path.abspath('..')) # -- General configuration ------------------------------------------------ # If your documentation needs a minimal Sphinx version, state it here. #needs_sphinx = '1.0' # 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', 'sphinx.ext.coverage', ] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix(es) of source filenames. # You can specify multiple suffix as a list of string: # source_suffix = ['.rst', '.md'] source_suffix = '.rst' # The encoding of source files. #source_encoding = 'utf-8-sig' # The master toctree document. master_doc = 'index' # General information about the project. project = 'systemfixtures' copyright = '2016, Free Ekanayaka' author = 'Free Ekanayaka' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. version = '0.3.5' # The full version, including alpha/beta/rc tags. release = '0.3.5' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. # # This is also used if you do content translation via gettext catalogs. # Usually you set "language" from the command line for these cases. language = None # 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 patterns, relative to source directory, that match files and # directories to ignore when looking for source files. exclude_patterns = ['_build'] # 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 = True # 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 = 'sphinx' # A list of ignored prefixes for module index sorting. #modindex_common_prefix = [] # If true, keep warnings as "system message" paragraphs in the built documents. #keep_warnings = False # If true, `todo` and `todoList` produce output, else they produce nothing. todo_include_todos = False # -- Options for HTML output ---------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. html_theme = 'alabaster' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. #html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. #html_theme_path = [] # The name for this set of Sphinx documents. If None, it defaults to # " v 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 (relative to this directory) to use as a 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'] # Add any extra paths that contain custom files (such as robots.txt or # .htaccess) here, relative to this directory. These files are copied # directly to the root of the documentation. #html_extra_path = [] # 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_domain_indices = True # 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, links to the reST sources are added to the pages. #html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. #html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. #html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. #html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). #html_file_suffix = None # Language to be used for generating the HTML full-text search index. # Sphinx supports the following languages: # 'da', 'de', 'en', 'es', 'fi', 'fr', 'h', 'it', 'ja' # 'nl', 'no', 'pt', 'ro', 'r', 'sv', 'tr' #html_search_language = 'en' # A dictionary with options for the search language support, empty by default. # Now only 'ja' uses this config value #html_search_options = {'type': 'default'} # The name of a javascript file (relative to the configuration directory) that # implements a search results scorer. If empty, the default will be used. #html_search_scorer = 'scorer.js' # Output file base name for HTML help builder. htmlhelp_basename = 'systemfixturesdoc' # -- Options for LaTeX output --------------------------------------------- latex_elements = { # The paper size ('letterpaper' or 'a4paper'). #'papersize': 'letterpaper', # The font size ('10pt', '11pt' or '12pt'). #'pointsize': '10pt', # Additional stuff for the LaTeX preamble. #'preamble': '', # Latex figure (float) alignment #'figure_align': 'htbp', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ (master_doc, 'systemfixtures.tex', 'systemfixtures Documentation', 'Free Ekanayaka', '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 # If true, show page references after internal links. #latex_show_pagerefs = False # If true, show URL addresses after external links. #latex_show_urls = False # Documents to append as an appendix to all manuals. #latex_appendices = [] # If false, no module index is generated. #latex_domain_indices = True # -- Options for manual page output --------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ (master_doc, 'systemfixtures', 'systemfixtures Documentation', [author], 1) ] # If true, show URL addresses after external links. #man_show_urls = False # -- Options for Texinfo output ------------------------------------------- # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ (master_doc, 'systemfixtures', 'systemfixtures Documentation', author, 'systemfixtures', 'One line description of project.', 'Miscellaneous'), ] # Documents to append as an appendix to all manuals. #texinfo_appendices = [] # If false, no module index is generated. #texinfo_domain_indices = True # How to display URL addresses: 'footnote', 'no', or 'inline'. #texinfo_show_urls = 'footnote' # If true, do not generate a @detailmenu in the "Top" node's menu. #texinfo_no_detailmenu = False OutputChecker = doctest.OutputChecker class SixOutputChecker(OutputChecker): """Output checker compatible with both Python 2 and 3. See: https://dirkjan.ochtman.nl/writing/2014/07/06/single-source-python-23-doctests.html """ def check_output(self, want, got, optionflags): if six.PY2: if want == "12\n": # write() doesn't return number of bytes on PY2 want = "" want = re.sub("PermissionError: (.*)", "OSError: \\1", want) want = re.sub("'0o(.+)'\n", "'0\\1'\n", want) want = re.sub("b'(.*?)'", "'\\1'", want) got = re.sub("u'(.*?)'", "'\\1'", got) return OutputChecker.check_output(self, want, got, optionflags) doctest.OutputChecker = SixOutputChecker systemfixtures-0.6.7/doc/index.rst0000644000175000017500000002063313544465154017153 0ustar freefree00000000000000.. systemfixtures documentation master file, created by sphinx-quickstart on Thu Oct 27 06:54:09 2016. You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. Welcome to systemfixtures's documentation! ========================================== Overview -------- A collection of Python fixtures_ to fake out various system resources (processes, users, groups, etc.). .. _fixtures: https://github.com/testing-cabal/fixtures Each fake resource typically behaves as an "overlay" on the real resource, in that it can be programmed with fake behavior for a set of inputs, but falls back to the real behavior for the rest. See the examples below for more information. The implementation is mostly built on top of the basic MonkeyPatch_ fixture. .. _MonkeyPatch: https://github.com/testing-cabal/fixtures/blob/master/fixtures/_fixtures/monkeypatch.py Examples -------- Users +++++ The :class:`FakeUsers` fixture lets you add fake system users, that do not exist for real, but behave the same as real ones: .. doctest:: >>> import pwd >>> from systemfixtures import FakeUsers >>> users = FakeUsers() >>> users.setUp() >>> pwd.getpwnam("foo") Traceback (most recent call last): ... KeyError: 'getpwnam(): name not found: foo' >>> users.add("foo", 123) >>> info = pwd.getpwnam("foo") >>> info.pw_uid 123 >>> users.cleanUp() Groups ++++++ The :class:`FakeGroups` fixture lets you add fake system groups, that do not exist for real, but behave the same as real ones: .. doctest:: >>> import grp >>> from systemfixtures import FakeGroups >>> groups = FakeGroups() >>> groups.setUp() >>> grp.getgrnam("foo") Traceback (most recent call last): ... KeyError: 'getgrnam(): name not found: foo' >>> groups.add("foo", 123) >>> info = grp.getgrnam("foo") >>> info.gr_gid 123 >>> groups.cleanUp() Filesystem ++++++++++ The :class:`FakeFilesystem` fixture lets you add a temporary directory as filesystem "overlay". You can declare certain paths as belonging to the overlay, and filesystem APIs like :func:`open`, :func:`os.mkdir`, :func:`os.chown`, :func:`os.chmod` and :func:`os.stat` will be transparently redirected to act on the temporary directory instead of the real filesystem path: .. doctest:: >>> import os >>> import tempfile >>> from systemfixtures import FakeFilesystem >>> filesystem = FakeFilesystem() >>> filesystem.setUp() Trying to create a directory under the root one will fail, since we are running as unprivileged user: .. doctest:: >>> os.mkdir("/foo") Traceback (most recent call last): ... PermissionError: [Errno 13] Permission denied: '/foo' However, if we add the directory path to the fake filesystem, it will be possible to create it as overlay directory: .. doctest:: >>> filesystem.add("/foo") >>> os.mkdir("/foo") >>> os.path.isdir("/foo") True The overlay directory actually lives under the temporary tree of the fake filesystem fixture: .. doctest:: >>> filesystem.root.path.startswith(tempfile.gettempdir()) True >>> os.listdir(filesystem.root.path) ['foo'] It's possible to operate on the overlay directory as if it was a real top-level directory: .. doctest:: >>> with open("/foo/bar", "w") as fd: ... fd.write("Hello world!") 12 >>> with open("/foo/bar") as fd: ... fd.read() 'Hello world!' >>> os.listdir("/foo") ['bar'] It's possible to change the ownership of files in the overlay directory, even without superuser priviliges: .. doctest:: >>> os.chown("/foo/bar", 0, 0) >>> os.chmod("/foo/bar", 0o600) >>> info = os.stat("/foo/bar") >>> info.st_uid, info.st_gid (0, 0) >>> oct(info.st_mode) '0o100600' >>> filesystem.cleanUp() Network +++++++ The :class:`FakeNetwork` fixture is simply fixture-compatible adapter of the :class:`requests-mock` package, which provides facilities to stub out responses from the :class:`requests` package. For further details see the `official documentation `_. .. doctest:: >>> import requests >>> from systemfixtures import FakeNetwork >>> network = FakeNetwork() >>> network.setUp() >>> network.get("http://test.com", text="data") # doctest: +ELLIPSIS >>> response = requests.get("http://test.com") >>> response.text 'data' >>> network.cleanUp() Time ++++ The :class:`FakeTime` fixture is simply fixture-compatible adapter of the :class:`fakesleep` package, which provides facilities to stub out the API of :class:`time` package from the standard library. See the `external documentation `_ .. doctest:: >>> import time >>> from systemfixtures import FakeTime >>> fake_time = FakeTime() >>> fake_time.setUp() >>> stamp1 = time.time() >>> time.sleep(1) >>> stamp2 = time.time() Since :func:`sleep()` and :func:`time()` are fake, we get *exactly* 1.0: .. doctest:: >>> stamp2 - stamp1 1.0 >>> fake_time.cleanUp() Processes +++++++++ The :class:`FakeProcesses` fixture lets you fake out processes spawed with :class:`subprocess.Popen`, and have custom Python code be executed instead. You can both override available system executables, or add new ones are not available on the system: .. doctest:: >>> import io >>> import subprocess >>> from systemfixtures import FakeProcesses >>> processes = FakeProcesses() >>> processes.setUp() >>> subprocess.check_output(["uname"]) b'Linux\n' >>> def uname(proc_args): ... return {"stdout": io.BytesIO(b"Darwin\n")} >>> processes.add(uname, name="uname") >>> processes.uname # doctest: +ELLIPSIS >>> subprocess.check_output(["uname"]) b'Darwin\n' >>> def foo(proc_args): ... return {"stdout": io.BytesIO(b"Hello world!")} >>> processes.add(foo, name="foo") >>> subprocess.check_output(["foo"]) b'Hello world!' Some stock fake processes are provided as well: wget ^^^^ .. doctest:: >>> from systemfixtures.processes import Wget >>> processes.add(Wget()) >>> processes.wget.locations["http://foo"] = b"Hello world!" >>> subprocess.check_output(["wget", "-O", "-", "http://foo"]) b'Hello world!' systemctl ^^^^^^^^^ .. doctest:: >>> from systemfixtures.processes import Systemctl >>> processes.add(Systemctl()) >>> try: ... subprocess.check_output(["systemctl", "is-active", "foo"]) ... except subprocess.CalledProcessError as error: ... error.output b'inactive\n' >>> subprocess.check_call(["systemctl", "start", "foo"]) 0 >>> subprocess.check_output(["systemctl", "is-active", "foo"]) b'active\n' >>> subprocess.check_call(["systemctl", "stop", "foo"]) 0 >>> processes.systemctl.actions["foo"] ['start', 'stop'] dpkg ^^^^ .. doctest:: >>> from systemfixtures.processes import Dpkg >>> processes.add(Dpkg()) >>> subprocess.check_call(["dpkg", "-i", "foo_1.0-1.deb"]) 0 >>> processes.dpkg.actions["foo"] ['install'] .. doctest:: >>> processes.cleanUp() Threads +++++++ The :class:`FakeThreads` fixture lets you fake out threads spawed with the :class:`threading` module, and partially simulate their behavior in a synchronous way: .. doctest:: >>> import threading >>> from systemfixtures import FakeThreads >>> threads = FakeThreads() >>> threads.setUp() >>> calls = [None] >>> thread = threading.Thread(target=calls.pop) >>> thread.name 'fake-thread-0' >>> thread.start() >>> calls [] >>> thread.join() >>> thread.isAlive() False It's also possible to simulate a hung thread: >>> threads.hang() >>> thread = threading.Thread() >>> thread.name 'fake-thread-1' >>> thread.start() >>> thread.join(timeout=60) # This returns immediately >>> thread.isAlive() True Executables +++++++++++ The :class:`FakeExecutable` fixture lets you create temporary Python scripts that can be configured to mimic the behavior of some real executable (for instance listening to a port or emitting certain output): .. doctest:: >>> import stat >>> from systemfixtures import FakeExecutable >>> executable = FakeExecutable() >>> executable.setUp() >>> bool(os.stat(executable.path).st_mode & stat.S_IXUSR) True >>> executable.out('hello') >>> subprocess.check_output([executable.path]) b'hello\n' systemfixtures-0.6.7/requirements.txt0000644000175000017500000000013013544465154020017 0ustar freefree00000000000000pbr six fixtures testtools requests-mock fakesleep subprocess32; python_version < '3.5' systemfixtures-0.6.7/setup.cfg0000644000175000017500000000130213545107112016342 0ustar freefree00000000000000[metadata] name = systemfixtures summary = Test fixtures for providing fake versions of various system resources (processes, users, groups, etc.) home-page = https://github.com/testing-cabal/systemfixtures description-file = README.rst author = Free Ekanayaka author-email = free@ekanayaka.io license = MIT platform = POSIX classifier = License :: OSI Approved :: MIT License Operating System :: POSIX Programming Language :: Python :: 3 [files] packages = systemfixtures [extras] test = coverage>=4.2 sphinx [bdist_wheel] universal = 1 [build_sphinx] source-dir = docs/ build-dir = docs/_build all_files = 1 [upload_sphinx] upload-dir = docs/_build/html [egg_info] tag_build = tag_date = 0 systemfixtures-0.6.7/setup.py0000755000175000017500000000016313544465154016256 0ustar freefree00000000000000#!/usr/bin/env python import setuptools setuptools.setup( setup_requires=["pbr", "setuptools"], pbr=True) systemfixtures-0.6.7/systemfixtures/0000755000175000017500000000000013545107112017643 5ustar freefree00000000000000systemfixtures-0.6.7/systemfixtures/__init__.py0000644000175000017500000000151413544465154021771 0ustar freefree00000000000000import os from pbr.version import VersionInfo from .users import FakeUsers from .groups import FakeGroups from .filesystem import FakeFilesystem from .processes import FakeProcesses from .network import FakeNetwork from .time import FakeTime from .threads import FakeThreads from .executable import FakeExecutable __all__ = [ "FakeUsers", "FakeGroups", "FakeFilesystem", "FakeProcesses", "FakeNetwork", "FakeTime", "FakeThreads", "FakeExecutable", ] _v = VersionInfo("systemfixtures").semantic_version() __version__ = _v.release_string() version_info = _v.version_tuple() def load_tests(loader, standard_tests, pattern): this_dir = os.path.dirname(__file__) package_tests = loader.discover(start_dir=this_dir, pattern=pattern) standard_tests.addTests(package_tests) return standard_tests systemfixtures-0.6.7/systemfixtures/_overlay.py0000644000175000017500000000157213544465154022056 0ustar freefree00000000000000from fixtures import MonkeyPatch class Overlay(MonkeyPatch): def __init__(self, name, overlay, condition): super(Overlay, self).__init__(name, self._new_value) self.overlay = overlay self.condition = condition def _setUp(self): # XXX copied from MonkeyPatch location, attribute = self.name.rsplit('.', 1) __import__(location, {}, {}) components = location.split('.') current = __import__(components[0], {}, {}) for component in components[1:]: current = getattr(current, component) self._old_value = getattr(current, attribute) super(Overlay, self)._setUp() def _new_value(self, *args, **kwargs): if self.condition(*args, **kwargs): return self.overlay(self._old_value, *args, **kwargs) else: return self._old_value(*args, **kwargs) systemfixtures-0.6.7/systemfixtures/executable.py0000644000175000017500000000771713544465154022366 0ustar freefree00000000000000import os import socket import six from testtools.content import Content from testtools.content_type import UTF8_TEXT from fixtures import ( Fixture, TempDir, ) if six.PY2: import subprocess32 as subprocess if six.PY3: import subprocess class FakeExecutable(Fixture): """Create Python scripts that mimic the behavior of real executables.""" def _setUp(self): self.path = self.useFixture(TempDir()).join("executable") self.line("#!/usr/bin/env python") self.line("import logging") self.line("logging.basicConfig(" "format='%(asctime)s %(message)s', level=logging.DEBUG)") os.chmod(self.path, 0o0755) self._process = None self.addDetail("fake-process", Content(UTF8_TEXT, self._process_info)) def spawn(self): """Spawn the fake executable using subprocess.Popen.""" self._process = subprocess.Popen( [self.path], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) self.addCleanup(self._process_kill) def out(self, text): self.line("import sys") self.line("sys.stdout.write('{}\\n')".format(text)) self.line("sys.stdout.flush()") def log(self, message): self.line("logging.info('{}')".format(message)) def sleep(self, seconds): self.line("import time") self.line("time.sleep({})".format(seconds)) def hang(self): self.line("import time") self.line("import signal") self.line("signal.signal(signal.SIGTERM, lambda *args: None)") self.out("hanging") self.line("while True: time.sleep(1)") def listen(self, port=None): """Make the fake executable listen to the specified port. Possible values for 'port' are: - None: Allocate immediately a free port and instruct the fake executable to use it when it's invoked. This is subject to a race condition, if that port that was free when listen() was invoked later becomes used before the fake executable had chance to bind to it. However it has the advantage of exposing the free port as FakeExecutable.port instance variable, that can easily be consumed by tests. - An integer: Listen to this specific port. """ if port is None: port = allocate_port() self.port = port self.line("import socket") self.line("sock = socket.socket()") self.line("sock.bind(('localhost', {}))".format(self.port)) self.log("listening: %d" % self.port) self.line("sock.listen(0)") def line(self, line): with open(self.path, "a") as fd: fd.write("{}\n".format(line)) def _process_kill(self): """Kill the fake executable process if it's still running.""" if self._process.poll() is None: # pragma: no cover self._process.kill() self._process.wait(timeout=5) def _process_info(self): """Return details about the fake process.""" if not self._process: return [] output, error = self._process.communicate(timeout=5) if error is None: error = b"" output = output.decode("utf-8").strip() error = error.decode("utf-8").strip() info = (u"returncode: %r\n" u"output:\n%s\n" u"error:\n%s\n" % (self._process.returncode, output, error)) return [info.encode("utf-8")] def get_port(socket): """Return the port to which a socket is bound.""" addr, port = socket.getsockname() return port def allocate_port(): """Allocate an unused port. There is a small race condition here (between the time we allocate the port, and the time it actually gets used), but for the purposes for which this function gets used it isn't a problem in practice. """ sock = socket.socket() try: sock.bind(("localhost", 0)) return get_port(sock) finally: sock.close() systemfixtures-0.6.7/systemfixtures/filesystem.py0000644000175000017500000001120113544465154022410 0ustar freefree00000000000000import os import six from fixtures import ( Fixture, TempDir, ) from ._overlay import Overlay if six.PY2: BUILTIN_OPEN = "__builtin__.open" if six.PY3: BUILTIN_OPEN = "builtins.open" GENERIC_APIS = ( BUILTIN_OPEN, "glob.glob", "os.mkdir", "os.rmdir", "os.chmod", "os.remove", "os.unlink", "os.listdir", "os.walk", "os.open", "os.path.exists", "os.path.isdir", "os.utime", "sqlite3.connect", ) class FakeFilesystem(Fixture): """A transparent overlay test filesystem tree. It allows to transparently redirect filesystem APIs to a temporary directory, instead of the actual filesystem. """ def _setUp(self): self.root = self.useFixture(TempDir()) self._paths = {} self._ownership = {} if six.PY2: # Python 2 doesn't support a fd argument condition = self._is_fake_path if six.PY3: condition = self._is_fake_path_or_fd for api in GENERIC_APIS: self.useFixture(Overlay(api, self._generic, condition)) self.useFixture(Overlay("os.fchown", self._fchown, self._is_fake_fd)) self.useFixture(Overlay("os.chown", self._chown, self._is_fake_path)) self.useFixture(Overlay("os.stat", self._stat, self._is_fake_path)) self.useFixture(Overlay("os.lstat", self._stat, self._is_fake_path)) self.useFixture(Overlay( "os.symlink", self._symlink, self._is_fake_symlink)) self.useFixture( Overlay("os.readlink", self._readlink, self._is_fake_path)) self.useFixture(Overlay("os.rename", self._rename, lambda *args: True)) def add(self, path): """Add a path to the overlay filesytem. Any filesystem operation involving the this path or any sub-paths of it will be transparently redirected to temporary root dir. @path: An absolute path string. """ if not path.startswith(os.sep): raise ValueError("Non-absolute path '{}'".format(path)) path = path.rstrip(os.sep) while True: self._paths[path] = None path, _ = os.path.split(path) if path == os.sep: break def _fchown(self, real, fileno, uid, gid): """Run fake fchown code if fileno points to a sub-path of our tree. The ownership set with this fake fchown can be inspected by looking at the self.uid/self.gid dictionaries. """ path = self._fake_path(self._path_from_fd(fileno)) self._chown_common(path, uid, gid) def _chown(self, real, path, uid, gid): self._chown_common(path, uid, gid) def _chown_common(self, path, uid, gid): self._ownership[path] = (uid, gid) def _stat(self, real, path, *args, **kwargs): info = list(real(self._real_path(path))) if path in self._ownership: info[4:5] = self._ownership[path] return os.stat_result(info) def _symlink(self, real, src, dst, *args, **kwargs): if self._is_fake_path(src): src = self._real_path(src) if self._is_fake_path(dst): dst = self._real_path(dst) return real(src, dst, *args, **kwargs) def _readlink(self, real, path, *args, **kwargs): result = real(self._real_path(path), *args, **kwargs) if result.startswith(self.root.path): result = self._fake_path(result) return result def _rename(self, real, src, dst): if self._is_fake_path(src): src = self._real_path(src) if self._is_fake_path(dst): dst = self._real_path(dst) return real(src, dst) def _generic(self, real, path, *args, **kwargs): return real(self._real_path(path), *args, **kwargs) def _is_fake_path(self, path, *args, **kwargs): for prefix in self._paths: if path.startswith(prefix): return True return False def _is_fake_fd(self, fileno, *args, **kwargs): path = self._path_from_fd(fileno) return path.startswith(self.root.path) if six.PY3: def _is_fake_path_or_fd(self, path, *args, **kwargs): if isinstance(path, int): path = self._path_from_fd(path) return self._is_fake_path(path) def _is_fake_symlink(self, src, dst, *args, **kwargs): return self._is_fake_path(src) or self._is_fake_path(dst) def _path_from_fd(self, fileno): return os.readlink("/proc/self/fd/{}".format(fileno)) def _real_path(self, path): return self.root.join(path.lstrip(os.sep)) def _fake_path(self, path): return path[len(self.root.path):] systemfixtures-0.6.7/systemfixtures/groups.py0000644000175000017500000000073013544465154021550 0ustar freefree00000000000000import grp from fixtures import Fixture from ._overlay import Overlay class FakeGroups(Fixture): def _setUp(self): self._groups = {} self.useFixture(Overlay("grp.getgrnam", self._getgrnam, self._is_fake)) def add(self, name, gid): self._groups[name] = ("x", gid, []) def _getgrnam(self, real, name): return grp.struct_group((name,) + self._groups[name]) def _is_fake(self, name): return name in self._groups systemfixtures-0.6.7/systemfixtures/matchers.py0000644000175000017500000000041513544465154022037 0ustar freefree00000000000000import os from testtools.matchers import ( AfterPreprocessing, Equals, ) def HasOwnership(uid, gid): def ownership(path): info = os.stat(path) return info.st_uid, info.st_gid return AfterPreprocessing(ownership, Equals((uid, gid))) systemfixtures-0.6.7/systemfixtures/network.py0000644000175000017500000000054013544465154021721 0ustar freefree00000000000000from fixtures import Fixture from requests_mock import Mocker class FakeNetwork(Fixture): """Fixture adapter around request-mock.""" def _setUp(self): self._requests = Mocker() self._requests.start() self.addCleanup(self._requests.stop) def __getattr__(self, name): return getattr(self._requests, name) systemfixtures-0.6.7/systemfixtures/processes/0000755000175000017500000000000013545107112021651 5ustar freefree00000000000000systemfixtures-0.6.7/systemfixtures/processes/__init__.py0000644000175000017500000000030013544465154023767 0ustar freefree00000000000000from .fixture import FakeProcesses from .wget import Wget from .systemctl import Systemctl from .dpkg import Dpkg __all__ = [ "FakeProcesses", "Wget", "Systemctl", "Dpkg", ] systemfixtures-0.6.7/systemfixtures/processes/dpkg.py0000644000175000017500000000116713544465154023171 0ustar freefree00000000000000import os import argparse class Dpkg(object): name = "dpkg" def __init__(self): self.actions = {} def __call__(self, proc_args): parser = argparse.ArgumentParser() parser.add_argument("-i", dest="install") args = parser.parse_args(proc_args["args"][1:]) if args.install: package = os.path.basename(args.install) if package.endswith(".deb"): package = package[:-len(".deb")] package = package.split("_")[0] actions = self.actions.setdefault(package, []) actions.append("install") return {} systemfixtures-0.6.7/systemfixtures/processes/fixture.py0000644000175000017500000000361613544465154023733 0ustar freefree00000000000000import six import subprocess from fixtures import FakePopen from fixtures._fixtures import popen class FakeProcesses(FakePopen): """Enhances FakePopen by supporting multiple processes. This is essentially a registry to dispatch calls to FakePopen to fake code associated with an executable name, or to fall back to real executables in a matching name is not registered. """ def __init__(self): self._registry = {} self._real_Popen = subprocess.Popen def add(self, process, name=None): """Add a new process to the registry. :param process: A callable (either plain function or object implementing __calll). :param name: The name of the executable to match. If not given it must be provided as 'name' attribute of the given `process`. callable. """ name = name or process.name assert name, "No executable name given.""" self._registry[name] = process def get_info(self, proc_args): name = proc_args["args"][0] get_info = self._registry[name] return get_info(proc_args) def __call__(self, *args, **kwargs): name = args[0][0] if name not in self._registry: return self._real_Popen(*args, **kwargs) return super(FakeProcesses, self).__call__(*args, **kwargs) def __getattr__(self, name): return self._registry[name] class _FakeProcessWithMissingAPIs(popen.FakeProcess): """Can be dropped once: https://github.com/testing-cabal/fixtures/pull/32. is merged upstream. """ if six.PY3: @property def args(self): return self._args["args"] def poll(self): return self.returncode def communicate(self, input=None, timeout=None): return super(_FakeProcessWithMissingAPIs, self).communicate() popen.FakeProcess = _FakeProcessWithMissingAPIs systemfixtures-0.6.7/systemfixtures/processes/systemctl.py0000644000175000017500000000120613544465154024265 0ustar freefree00000000000000import io class Systemctl(object): name = "systemctl" def __init__(self): self.actions = {} def __call__(self, proc_args): action, service_name = proc_args["args"][1:] actions = self.actions.setdefault(service_name, []) returncode = 0 stdout = io.BytesIO() if action == "is-active": if not actions or actions[-1] != "start": returncode = 3 stdout.write(b"inactive\n") else: stdout.write(b"active\n") else: actions.append(action) return {"stdout": stdout, "returncode": returncode} systemfixtures-0.6.7/systemfixtures/processes/tests/0000755000175000017500000000000013545107112023013 5ustar freefree00000000000000systemfixtures-0.6.7/systemfixtures/processes/tests/__init__.py0000644000175000017500000000000013544465154025126 0ustar freefree00000000000000systemfixtures-0.6.7/systemfixtures/processes/tests/test_dpkg.py0000644000175000017500000000050513544465154025365 0ustar freefree00000000000000from testtools import TestCase from ..dpkg import Dpkg class DpkgTest(TestCase): def setUp(self): super(DpkgTest, self).setUp() self.dpkg = Dpkg() def test_install(self): self.dpkg({"args": ["dpkg", "-i", "foo_1.0-1.deb"]}) self.assertEqual(["install"], self.dpkg.actions["foo"]) systemfixtures-0.6.7/systemfixtures/processes/tests/test_fixture.py0000644000175000017500000000121213544465154026122 0ustar freefree00000000000000import io import subprocess from testtools import TestCase from ..fixture import FakeProcesses class FakeProcessesTest(TestCase): def setUp(self): super(FakeProcessesTest, self).setUp() self.processes = self.useFixture(FakeProcesses()) def test_real(self): self.assertEqual(b"hi\n", subprocess.check_output(["echo", "hi"])) def test_fake(self): def get_info(proc_args): return {"stdout": io.BytesIO(b"hi!")} self.processes.add(get_info, name="echo") self.assertIs(get_info, self.processes.echo) self.assertEqual(b"hi!", subprocess.check_output(["echo", "hi"])) systemfixtures-0.6.7/systemfixtures/processes/tests/test_systemctl.py0000644000175000017500000000160613544465154026472 0ustar freefree00000000000000from testtools import TestCase from ..systemctl import Systemctl class SystemctlTest(TestCase): def setUp(self): super(SystemctlTest, self).setUp() self.systemctl = Systemctl() def test_stop(self): self.systemctl({"args": ["systemctl", "stop", "foo"]}) self.assertEqual(["stop"], self.systemctl.actions["foo"]) def test_start(self): self.systemctl({"args": ["systemctl", "start", "foo"]}) self.assertEqual(["start"], self.systemctl.actions["foo"]) def test_is_active(self): self.systemctl({"args": ["systemctl", "start", "foo"]}) result = self.systemctl({"args": ["systemctl", "is-active", "foo"]}) self.assertEqual(0, result.get("returncode")) def test_is_not_active(self): result = self.systemctl({"args": ["systemctl", "is-active", "foo"]}) self.assertEqual(3, result["returncode"]) systemfixtures-0.6.7/systemfixtures/processes/tests/test_wget.py0000644000175000017500000000154413545107051025400 0ustar freefree00000000000000import os from testtools import TestCase from testtools.matchers import FileContains from fixtures import TempDir from ..wget import Wget class WgetTest(TestCase): def setUp(self): super(WgetTest, self).setUp() self.locations = {"http://x": b"data"} self.wget = Wget(locations=self.locations) def test_to_stdout(self): result = self.wget({"args": ["wget","-N", "-O", "-", "http://x"]}) self.assertEqual(b"data", result["stdout"].getvalue()) def test_to_file(self): temp_dir = self.useFixture(TempDir()) path = temp_dir.join("output") self.wget({"args": ["wget", "-N", "-O", path, "http://x"]}) self.assertThat(path, FileContains("data")) def test_to_default(self): self.wget({"args": ["wget", "-N", "http://x"]}) self.assertThat("x", FileContains("data")) systemfixtures-0.6.7/systemfixtures/processes/wget.py0000644000175000017500000000211413545107051023171 0ustar freefree00000000000000import io import os import argparse class Wget(object): name = "wget" def __init__(self, locations=None): self.locations = locations or {} def __call__(self, proc_args): cwd = proc_args.get("cwd") or "" parser = argparse.ArgumentParser() parser.add_argument("url") parser.add_argument("-O", dest="output") parser.add_argument("-q", dest="quiet", action="store_true") parser.add_argument("-N", dest="timestamping", action="store_true") parser.add_argument("--no-check-certificate", action="store_true") args = parser.parse_args(proc_args["args"][1:]) content = self.locations[args.url] file = args.url.split("/")[-1] file_dir = os.path.join(cwd, file) result = {} if args.output == "-": result["stdout"] = io.BytesIO(content) elif (args.output is None): with open(file_dir, "wb") as fd: fd.write(content) else: with open(args.output, "wb") as fd: fd.write(content) return result systemfixtures-0.6.7/systemfixtures/tests/0000755000175000017500000000000013545107112021005 5ustar freefree00000000000000systemfixtures-0.6.7/systemfixtures/tests/__init__.py0000644000175000017500000000000013544465154023120 0ustar freefree00000000000000systemfixtures-0.6.7/systemfixtures/tests/test_executable.py0000644000175000017500000000430513544465154024555 0ustar freefree00000000000000import os import time import errno import socket import logging import subprocess from fixtures import FakeLogger from testtools import TestCase from testtools.content import text_content from testtools.matchers import ( Contains, FileContains, ) from ..executable import FakeExecutable class FakeExecutableTest(TestCase): def setUp(self): super(FakeExecutableTest, self).setUp() self.executable = self.useFixture(FakeExecutable()) def test_out(self): self.executable.out("hello") self.assertEqual( b"hello\n", subprocess.check_output([self.executable.path])) def test_sleep(self): self.executable.sleep(1) self.assertThat( self.executable.path, FileContains(matcher=Contains("time.sleep(1)"))) def test_listen_random(self): self.executable.listen() self.assertIsNotNone(self.executable.port) def test_listen(self): logger = self.useFixture(FakeLogger(format="%(asctime)s %(message)s")) self.executable.listen(6666) self.executable.sleep(1) self.executable.spawn() # Try to connect to the socket sock = socket.socket() transient = (errno.ECONNREFUSED, errno.ECONNRESET) attempts = 10 for i in range(1, attempts + 1): try: sock.connect(("127.0.0.1", self.executable.port)) except socket.error as error: # pragma: no cover if error.errno in transient and i != attempts: time.sleep(0.05 * i) continue logging.error("connection attempt %d failed", i) raise error break self.assertEqual("127.0.0.1", sock.getsockname()[0]) def test_hang(self): self.executable.out("hello") # Used to ensure the process is running self.executable.hang() process = subprocess.Popen( [self.executable.path], stdout=subprocess.PIPE) self.assertEqual(b"hello\n", process.stdout.read(6)) process.terminate() self.addCleanup(process.wait) self.addCleanup(process.kill) self.assertEqual((0, 0), os.waitpid(process.pid, os.WNOHANG)) systemfixtures-0.6.7/systemfixtures/tests/test_filesystem.py0000644000175000017500000001042013544465154024613 0ustar freefree00000000000000import glob import os import sqlite3 import six import shutil from testtools import TestCase, skipIf from testtools.matchers import ( DirExists, HasPermissions, FileContains, ) from fixtures import TempDir from ..filesystem import FakeFilesystem from ..matchers import HasOwnership if six.PY2: PermissionError = OSError class FakeFilesystemTest(TestCase): def setUp(self): super(FakeFilesystemTest, self).setUp() self.fs = self.useFixture(FakeFilesystem()) def test_add(self): self.fs.add("/foo/bar") os.makedirs("/foo/bar") self.assertThat("/foo/bar", DirExists()) def test_add_sub_paths(self): self.fs.add("/foo") os.makedirs("/foo/bar") self.assertThat("/foo/bar", DirExists()) def test_add_non_absolute(self): self.assertRaises(ValueError, self.fs.add, "foo/bar") def test_fchown(self): self.fs.add("/foo/bar") os.mkdir("/foo") with open("/foo/bar", "w") as fd: os.fchown(fd.fileno(), 123, 456) self.assertThat("/foo/bar", HasOwnership(123, 456)) @skipIf(os.getuid() == 0, "Can't run as root") def test_fchown_real(self): temp_dir = self.useFixture(TempDir()) path = temp_dir.join("foo") with open(path, "w") as fd: self.assertRaises( PermissionError, os.fchown, fd.fileno(), 12345, 9999) def test_chown(self): self.fs.add("/foo/bar") os.makedirs("/foo/bar") os.chown("/foo/bar", 123, 456) self.assertThat("/foo/bar", HasOwnership(123, 456)) @skipIf(os.getuid() == 0, "Can't run as root") def test_chown_real(self): temp_dir = self.useFixture(TempDir()) path = temp_dir.join("foo") os.makedirs(path) self.assertRaises(PermissionError, os.chown, path, 12345, 9999) def test_chmod(self): self.fs.add("/foo") with open("/foo", "w") as fd: fd.write("") os.chmod("/foo", 0o600) self.assertThat("/foo", HasPermissions("0600")) def test_symlink(self): self.fs.add("/foo") os.mkdir("/foo") with open("/foo/bar", "w") as fd: fd.write("hello") os.symlink("/foo/bar", "/foo/egg") self.assertThat("/foo/egg", FileContains("hello")) def test_unlink(self): self.fs.add("/foo") os.mkdir("/foo") with open("/foo/bar", "w") as fd: fd.write("hello") os.unlink("/foo/bar") self.assertEqual([], os.listdir("/foo")) def test_rmtree(self): self.fs.add("/foo") os.makedirs("/foo/bar/egg") shutil.rmtree("/foo/bar") self.assertEqual([], os.listdir("/foo")) if six.PY3: def test_listdir_with_fd(self): self.fs.add("/foo") os.makedirs("/foo/bar") fd = os.open("/foo", os.O_RDONLY) self.addCleanup(os.close, fd) self.assertEqual(["bar"], os.listdir(fd)) def test_readlink_to_real_path(self): self.fs.add("/foo") os.mkdir("/foo") temp_dir = self.useFixture(TempDir()) os.symlink(temp_dir.path, "/foo/bar") self.assertEqual(temp_dir.path, os.readlink("/foo/bar")) def test_readlink_to_fake_path(self): self.fs.add("/foo") os.mkdir("/foo") os.symlink("/foo/bar", "/foo/egg") self.assertEqual("/foo/bar", os.readlink("/foo/egg")) def test_rename(self): self.fs.add("/foo") os.makedirs("/foo/bar") os.rename("/foo/bar", "/foo/egg") self.assertThat("/foo/egg", DirExists()) def test_glob(self): self.fs.add("/foo") os.makedirs("/foo/bar") os.makedirs("/foo/baz") self.assertEqual( [os.path.join(self.fs.root.path, "foo/bar"), os.path.join(self.fs.root.path, "foo/baz")], sorted(glob.glob("/foo/ba*"))) def test_walk(self): self.fs.add("/foo") os.makedirs("/foo/bar") self.assertEqual( [(os.path.join(self.fs.root.path, "foo/bar"), [], [])], list(os.walk("/foo/bar"))) def test_sqlite3(self): self.fs.add("/foo") os.makedirs("/foo/bar") conn = sqlite3.connect("/foo/bar/db") self.addCleanup(conn.close) self.assertIsNotNone(conn) systemfixtures-0.6.7/systemfixtures/tests/test_groups.py0000644000175000017500000000072713544465154023757 0ustar freefree00000000000000import grp from testtools import TestCase from ..groups import FakeGroups class FakeGroupsTest(TestCase): def setUp(self): super(FakeGroupsTest, self).setUp() self.groups = self.useFixture(FakeGroups()) def test_real(self): info = grp.getgrnam("root") self.assertEqual(0, info.gr_gid) def test_fake(self): self.groups.add("foo", 123) info = grp.getgrnam("foo") self.assertEqual(123, info.gr_gid) systemfixtures-0.6.7/systemfixtures/tests/test_network.py0000644000175000017500000000064213544465154024125 0ustar freefree00000000000000import requests from testtools import TestCase from ..network import FakeNetwork class FakeGroupsTest(TestCase): def setUp(self): super(FakeGroupsTest, self).setUp() self.network = self.useFixture(FakeNetwork()) def test_get(self): self.network.get('http://test.com', text='data') response = requests.get('http://test.com') self.assertEqual("data", response.text) systemfixtures-0.6.7/systemfixtures/tests/test_threads.py0000644000175000017500000000277413544465154024076 0ustar freefree00000000000000import threading from testtools import TestCase from ..threads import FakeThreads class FakeThreadsTest(TestCase): def setUp(self): super(FakeThreadsTest, self).setUp() self.threads = self.useFixture(FakeThreads()) def test_getitem(self): thread = threading.Thread() self.assertIs(thread, self.threads[0]) def test_start(self): calls = [None] thread = threading.Thread(target=calls.pop) self.assertFalse(thread.isAlive()) thread.start() self.assertEqual([], calls) self.assertFalse(thread.isAlive()) def test_twice(self): thread = threading.Thread(target=lambda: None) thread.start() error = self.assertRaises(RuntimeError, thread.start) self.assertEqual("threads can only be started once", str(error)) def test_join_before_starting(self): thread = threading.Thread() error = self.assertRaises(RuntimeError, thread.join) self.assertEqual("cannot join thread before it is started", str(error)) def test_hang(self): self.threads.hang() thread = threading.Thread() thread.start() thread.join(timeout=1) self.assertTrue(thread.isAlive()) def test_hang_without_timeout(self): self.threads.hang() thread = threading.Thread() thread.start() error = self.assertRaises(AssertionError, thread.join) self.assertEqual( "can't simulate hung thread with no timeout", str(error)) systemfixtures-0.6.7/systemfixtures/tests/test_time.py0000644000175000017500000000111713544465154023370 0ustar freefree00000000000000import time from testtools import TestCase from ..time import FakeTime class FakeTimeTest(TestCase): def setUp(self): super(FakeTimeTest, self).setUp() self.time = self.useFixture(FakeTime()) def test_time(self): stamp1 = time.time() stamp2 = time.time() self.assertEqual(stamp2, stamp1) def test_sleep(self): stamp1 = time.time() time.sleep(1) stamp2 = time.time() self.assertEqual(1, stamp2 - stamp1) def test_reset(self): self.time.set(123) self.assertEqual(123, time.time()) systemfixtures-0.6.7/systemfixtures/tests/test_users.py0000644000175000017500000000072013544465154023572 0ustar freefree00000000000000import pwd from testtools import TestCase from ..users import FakeUsers class FakeUsersTest(TestCase): def setUp(self): super(FakeUsersTest, self).setUp() self.users = self.useFixture(FakeUsers()) def test_real(self): info = pwd.getpwnam("root") self.assertEqual(0, info.pw_uid) def test_fake(self): self.users.add("foo", 123) info = pwd.getpwnam("foo") self.assertEqual(123, info.pw_uid) systemfixtures-0.6.7/systemfixtures/threads.py0000644000175000017500000000330713544465154021666 0ustar freefree00000000000000from fixtures import MonkeyPatch class FakeThreads(MonkeyPatch): def __init__(self): super(FakeThreads, self).__init__("threading.Thread", self) self._threads = [] self._hang = False def hang(self, flag=True): self._hang = flag def __getitem__(self, index): return self._threads[index] def __call__(self, *args, **kwargs): thread = _Thread(*args, **kwargs) if not thread.name: thread.name = "fake-thread-{}".format(len(self._threads)) thread.hang = self._hang self._threads.append(thread) return thread class _Thread(object): def __init__(self, group=None, target=None, name=None, args=(), kwargs={}, daemon=None): self.group = group self.target = target self.name = name self.args = args self.kwargs = kwargs self.daemon = daemon self.alive = None # None -> not started, True/False -> started stopped self.hang = None def start(self): if self.alive is not None: raise RuntimeError("threads can only be started once") self.alive = True if not self.hang: self.target(*self.args, **self.kwargs) self.alive = False def join(self, timeout=None): if self.alive is None: # It's an an error to join() a thread before it has been started raise RuntimeError("cannot join thread before it is started") if self.hang: if timeout is None: raise AssertionError( "can't simulate hung thread with no timeout") def isAlive(self): return bool(self.alive) is_alive = isAlive systemfixtures-0.6.7/systemfixtures/time.py0000644000175000017500000000104013544465154021162 0ustar freefree00000000000000from fixtures import Fixture from fakesleep import ( monkey_patch, monkey_restore, reset, ) class FakeTime(Fixture): """Fixture adapter around fakesleep.""" def set(self, seconds=None): """Set the global fake time to the given epoch or the real current one. :param seconds: Fake current time, in seconds since the epoch. If ``None``, use the real current time. """ reset(seconds=seconds) def _setUp(self): monkey_patch() self.addCleanup(monkey_restore) systemfixtures-0.6.7/systemfixtures/users.py0000644000175000017500000000101613544465154021370 0ustar freefree00000000000000import pwd from fixtures import Fixture from ._overlay import Overlay class FakeUsers(Fixture): def _setUp(self): self._users = {} self.useFixture(Overlay("pwd.getpwnam", self._getpwnam, self._is_fake)) def add(self, name, uid): self._users[name] = ( "x", uid, uid, name, "/home/{}".format(name), "/bin/bash") def _getpwnam(self, real, name): return pwd.struct_passwd((name,) + self._users[name]) def _is_fake(self, name): return name in self._users systemfixtures-0.6.7/systemfixtures.egg-info/0000755000175000017500000000000013545107112021335 5ustar freefree00000000000000systemfixtures-0.6.7/systemfixtures.egg-info/PKG-INFO0000644000175000017500000000527413545107111022441 0ustar freefree00000000000000Metadata-Version: 2.1 Name: systemfixtures Version: 0.6.7 Summary: Test fixtures for providing fake versions of various system resources (processes, users, groups, etc.) Home-page: https://github.com/testing-cabal/systemfixtures Author: Free Ekanayaka Author-email: free@ekanayaka.io License: MIT Description: System fixtures =============== .. image:: https://img.shields.io/pypi/v/systemfixtures.svg :target: https://pypi.python.org/pypi/systemfixtures :alt: Latest Version .. image:: https://travis-ci.org/testing-cabal/systemfixtures.svg?branch=master :target: https://travis-ci.org/testing-cabal/systemfixtures :alt: Build Status .. image:: https://coveralls.io/repos/github/testing-cabal/systemfixtures/badge.svg?branch=master :target: https://coveralls.io/github/testing-cabal/systemfixtures?branch=master :alt: Coverage .. image:: https://readthedocs.org/projects/systemfixtures/badge/?version=latest :target: http://systemfixtures.readthedocs.io/en/latest/?badge=latest :alt: Documentation Status A collection of Python fixtures_ to fake out various system resources (processes, users, groups, etc.). .. _fixtures: https://github.com/testing-cabal/fixtures Each fake resource typically behaves as an "overlay" on the real resource, in that it can be programmed with fake behavior for a set of inputs, but falls back to the real behavior for the rest. .. code:: python >>> import pwd >>> from systemfixtures import FakeUsers >>> users = FakeUsers() >>> users.setUp() >>> pwd.getpwnam("foo") Traceback (most recent call last): ... KeyError: 'getpwnam(): name not found: foo' >>> users.add("foo", 123) >>> info = pwd.getpwnam("foo") >>> info.pw_uid 123 >>> users.cleanUp() Support and Documentation ------------------------- See the `online documentation `_ for a complete reference. Developing and Contributing --------------------------- See the `GitHub project `_. Bugs can be filed in the issues tracker. Platform: POSIX Classifier: License :: OSI Approved :: MIT License Classifier: Operating System :: POSIX Classifier: Programming Language :: Python :: 3 Provides-Extra: test systemfixtures-0.6.7/systemfixtures.egg-info/SOURCES.txt0000644000175000017500000000262313545107112023224 0ustar freefree00000000000000.coveragerc.py2 .coveragerc.py3 AUTHORS ChangeLog HACKING.rst LICENSE MANIFEST.in Makefile README.rst requirements.txt setup.cfg setup.py tox.ini doc/Makefile doc/conf.py doc/index.rst doc/_static/.placeholder systemfixtures/__init__.py systemfixtures/_overlay.py systemfixtures/executable.py systemfixtures/filesystem.py systemfixtures/groups.py systemfixtures/matchers.py systemfixtures/network.py systemfixtures/threads.py systemfixtures/time.py systemfixtures/users.py systemfixtures.egg-info/PKG-INFO systemfixtures.egg-info/SOURCES.txt systemfixtures.egg-info/dependency_links.txt systemfixtures.egg-info/not-zip-safe systemfixtures.egg-info/pbr.json systemfixtures.egg-info/requires.txt systemfixtures.egg-info/top_level.txt systemfixtures/processes/__init__.py systemfixtures/processes/dpkg.py systemfixtures/processes/fixture.py systemfixtures/processes/systemctl.py systemfixtures/processes/wget.py systemfixtures/processes/tests/__init__.py systemfixtures/processes/tests/test_dpkg.py systemfixtures/processes/tests/test_fixture.py systemfixtures/processes/tests/test_systemctl.py systemfixtures/processes/tests/test_wget.py systemfixtures/tests/__init__.py systemfixtures/tests/test_executable.py systemfixtures/tests/test_filesystem.py systemfixtures/tests/test_groups.py systemfixtures/tests/test_network.py systemfixtures/tests/test_threads.py systemfixtures/tests/test_time.py systemfixtures/tests/test_users.pysystemfixtures-0.6.7/systemfixtures.egg-info/dependency_links.txt0000644000175000017500000000000113545107111025402 0ustar freefree00000000000000 systemfixtures-0.6.7/systemfixtures.egg-info/not-zip-safe0000644000175000017500000000000113544465355023602 0ustar freefree00000000000000 systemfixtures-0.6.7/systemfixtures.egg-info/pbr.json0000644000175000017500000000005713545107111023014 0ustar freefree00000000000000{"git_version": "6ff52e2", "is_release": false}systemfixtures-0.6.7/systemfixtures.egg-info/requires.txt0000644000175000017500000000017213545107111023734 0ustar freefree00000000000000fakesleep fixtures pbr requests-mock six testtools [:(python_version < '3.5')] subprocess32 [test] coverage>=4.2 sphinx systemfixtures-0.6.7/systemfixtures.egg-info/top_level.txt0000644000175000017500000000001713545107111024064 0ustar freefree00000000000000systemfixtures systemfixtures-0.6.7/tox.ini0000644000175000017500000000045513544465154016060 0ustar freefree00000000000000[tox] envlist = py27,py35,py36 skipsdist = True [tox:travis] 2.7 = py27 3.5 = py35 3.6 = py36 [testenv] usedevelop = True install_command = pip install -U {opts} {packages} deps = .[test] setenv = COVERAGE=coverage SPHINXBUILD=sphinx-build whitelist_externals = make commands = make