summaryrefslogtreecommitdiffstats
path: root/qa/base.py
diff options
context:
space:
mode:
Diffstat (limited to 'qa/base.py')
-rw-r--r--qa/base.py179
1 files changed, 108 insertions, 71 deletions
diff --git a/qa/base.py b/qa/base.py
index 05d85e5..2b83778 100644
--- a/qa/base.py
+++ b/qa/base.py
@@ -1,32 +1,21 @@
-# -*- coding: utf-8 -*-
-# pylint: disable=bad-option-value,unidiomatic-typecheck,undefined-variable,no-else-return,
-# pylint: disable=too-many-function-args,unexpected-keyword-arg
-
-import io
import os
import platform
import shutil
import sys
import tempfile
-from datetime import datetime
+from datetime import datetime, timezone
+from unittest import TestCase
from uuid import uuid4
import arrow
-try:
- # python 2.x
- from unittest2 import TestCase
-except ImportError:
- # python 3.x
- from unittest import TestCase
-
-from qa.shell import git, gitlint, RunningCommand
-from qa.utils import DEFAULT_ENCODING, ustr
+from qa.shell import RunningCommand, git, gitlint
+from qa.utils import FILE_ENCODING, PLATFORM_IS_WINDOWS, TERMINAL_ENCODING
class BaseTestCase(TestCase):
- """ Base class of which all gitlint integration test classes are derived.
- Provides a number of convenience methods. """
+ """Base class of which all gitlint integration test classes are derived.
+ Provides a number of convenience methods."""
# In case of assert failures, print the full error message
maxDiff = None
@@ -34,43 +23,39 @@ class BaseTestCase(TestCase):
GITLINT_USE_SH_LIB = os.environ.get("GITLINT_USE_SH_LIB", "[NOT SET]")
GIT_CONTEXT_ERROR_CODE = 254
-
- @classmethod
- def setUpClass(cls):
- """ Sets up the integration tests by creating a new temporary git repository """
- cls.tmp_git_repos = []
- cls.tmp_git_repo = cls.create_tmp_git_repo()
-
- @classmethod
- def tearDownClass(cls):
- """ Cleans up the temporary git repositories """
- for repo in cls.tmp_git_repos:
- shutil.rmtree(repo)
+ GITLINT_USAGE_ERROR = 253
def setUp(self):
+ """Sets up the integration tests by creating a new temporary git repository"""
self.tmpfiles = []
+ self.tmp_git_repos = []
+ self.tmp_git_repo = self.create_tmp_git_repo()
def tearDown(self):
+ # Clean up temporary files and repos
for tmpfile in self.tmpfiles:
os.remove(tmpfile)
+ for repo in self.tmp_git_repos:
+ # On windows we need to ignore errors because git might still be holding on to some files
+ shutil.rmtree(repo, ignore_errors=PLATFORM_IS_WINDOWS)
- def assertEqualStdout(self, output, expected): # pylint: disable=invalid-name
+ def assertEqualStdout(self, output, expected):
self.assertIsInstance(output, RunningCommand)
- output = ustr(output.stdout)
- output = output.replace('\r', '')
+ output = output.stdout.decode(TERMINAL_ENCODING)
+ output = output.replace("\r", "")
self.assertMultiLineEqual(output, expected)
- @classmethod
- def generate_temp_path(cls):
- return os.path.realpath("/tmp/gitlint-test-{0}".format(datetime.now().strftime("%Y%m%d-%H%M%S-%f")))
+ @staticmethod
+ def generate_temp_path():
+ timestamp = datetime.now(timezone.utc).strftime("%Y%m%d-%H%M%S-%f")
+ return os.path.realpath(f"/tmp/gitlint-test-{timestamp}") # noqa
- @classmethod
- def create_tmp_git_repo(cls):
- """ Creates a temporary git repository and returns its directory path """
- tmp_git_repo = cls.generate_temp_path()
- cls.tmp_git_repos.append(tmp_git_repo)
+ def create_tmp_git_repo(self):
+ """Creates a temporary git repository and returns its directory path"""
+ tmp_git_repo = self.generate_temp_path()
+ self.tmp_git_repos.append(tmp_git_repo)
- git("init", tmp_git_repo)
+ git("init", "--initial-branch", "main", tmp_git_repo)
# configuring name and email is required in every git repot
git("config", "user.name", "gitlint-test-user", _cwd=tmp_git_repo)
git("config", "user.email", "gitlint@test.com", _cwd=tmp_git_repo)
@@ -84,18 +69,48 @@ class BaseTestCase(TestCase):
# http://stackoverflow.com/questions/5581857/git-and-the-umlaut-problem-on-mac-os-x
git("config", "core.precomposeunicode", "true", _cwd=tmp_git_repo)
+ # Git now does commit message cleanup by default (e.g. removing trailing whitespace), disable that for testing
+ git("config", "commit.cleanup", "verbatim", _cwd=tmp_git_repo)
+
return tmp_git_repo
@staticmethod
- def create_file(parent_dir):
- """ Creates a file inside a passed directory. Returns filename."""
- test_filename = u"test-fïle-" + str(uuid4())
- io.open(os.path.join(parent_dir, test_filename), 'a', encoding=DEFAULT_ENCODING).close()
+ def create_file(parent_dir, content=None):
+ """Creates a file inside a passed directory. Returns filename."""
+ test_filename = "test-fïle-" + str(uuid4())
+ full_path = os.path.join(parent_dir, test_filename)
+
+ if content:
+ if isinstance(content, bytes):
+ open_kwargs = {"mode": "wb"}
+ else:
+ open_kwargs = {"mode": "w", "encoding": FILE_ENCODING}
+
+ with open(full_path, **open_kwargs) as f:
+ f.write(content)
+ else:
+ open(full_path, "a", encoding=FILE_ENCODING).close() # noqa: SIM115 (Use context handler for opening files)
+
return test_filename
- def create_simple_commit(self, message, out=None, ok_code=None, env=None, git_repo=None, tty_in=False):
- """ Creates a simple commit with an empty test file.
- :param message: Commit message for the commit. """
+ @staticmethod
+ def create_environment(envvars=None):
+ """Creates a copy of the current os.environ and adds/overwrites a given set of variables to it"""
+ environment = os.environ.copy()
+ if envvars:
+ environment.update(envvars)
+ return environment
+
+ def create_tmp_git_config(self, contents):
+ """Creates an environment with the GIT_CONFIG variable set to a file with the given contents."""
+ tmp_config = self.create_tmpfile(contents)
+ return self.create_environment({"GIT_CONFIG": tmp_config})
+
+ def create_simple_commit(
+ self, message, *, file_contents=None, out=None, ok_code=None, env=None, git_repo=None, tty_in=False
+ ):
+ """Creates a simple commit with an empty test file.
+ :param message: Commit message for the commit."""
git_repo = self.tmp_git_repo if git_repo is None else git_repo
@@ -103,28 +118,42 @@ class BaseTestCase(TestCase):
# variables can influence how git runs.
# This was needed to fix https://github.com/jorisroovers/gitlint/issues/15 as we need to make sure to use
# the PATH variable that contains the virtualenv's python binary.
- environment = os.environ
- if env:
- environment.update(env)
+ environment = self.create_environment(env)
# Create file and add to git
- test_filename = self.create_file(git_repo)
+ test_filename = self.create_file(git_repo, file_contents)
git("add", test_filename, _cwd=git_repo)
# https://amoffat.github.io/sh/#interactive-callbacks
if not ok_code:
ok_code = [0]
- git("commit", "-m", message, _cwd=git_repo, _err_to_out=True, _out=out, _tty_in=tty_in,
- _ok_code=ok_code, _env=environment)
+ git(
+ "commit",
+ "-m",
+ message,
+ _cwd=git_repo,
+ _err_to_out=True,
+ _out=out,
+ _tty_in=tty_in,
+ _ok_code=ok_code,
+ _env=environment,
+ )
return test_filename
def create_tmpfile(self, content):
- """ Utility method to create temp files. These are cleaned at the end of the test """
- # Not using a context manager to avoid unneccessary identation in test code
+ """Utility method to create temp files. These are cleaned at the end of the test"""
+ # Not using a context manager to avoid unnecessary indentation in test code
tmpfile, tmpfilepath = tempfile.mkstemp()
self.tmpfiles.append(tmpfilepath)
- with io.open(tmpfile, "w", encoding=DEFAULT_ENCODING) as f:
+
+ if isinstance(content, bytes):
+ open_kwargs = {"mode": "wb"}
+ else:
+ open_kwargs = {"mode": "w", "encoding": FILE_ENCODING}
+
+ with open(tmpfile, **open_kwargs) as f:
f.write(content)
+
return tmpfilepath
@staticmethod
@@ -147,32 +176,40 @@ class BaseTestCase(TestCase):
@staticmethod
def get_expected(filename="", variable_dict=None):
- """ Utility method to read an 'expected' file and return it as a string. Optionally replace template variables
- specified by variable_dict. """
+ """Utility method to read an 'expected' file and return it as a string. Optionally replace template variables
+ specified by variable_dict."""
expected_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), "expected")
expected_path = os.path.join(expected_dir, filename)
- expected = io.open(expected_path, encoding=DEFAULT_ENCODING).read()
+ # Expected files are UTF-8 encoded (not dependent on the system's default encoding)
+ with open(expected_path, encoding=FILE_ENCODING) as file:
+ expected = file.read()
- if variable_dict:
- expected = expected.format(**variable_dict)
- return expected
+ if variable_dict:
+ expected = expected.format(**variable_dict)
+ return expected
@staticmethod
def get_system_info_dict():
- """ Returns a dict with items related to system values logged by `gitlint --debug` """
- expected_gitlint_version = gitlint("--version").replace("gitlint, version ", "").replace("\n", "")
- expected_git_version = git("--version").replace("\n", "")
- return {'platform': platform.platform(), 'python_version': sys.version,
- 'git_version': expected_git_version, 'gitlint_version': expected_gitlint_version,
- 'GITLINT_USE_SH_LIB': BaseTestCase.GITLINT_USE_SH_LIB}
+ """Returns a dict with items related to system values logged by `gitlint --debug`"""
+ expected_gitlint_version = gitlint("--version").replace("gitlint, version ", "").strip()
+ expected_git_version = git("--version").strip()
+ return {
+ "platform": platform.platform(),
+ "python_version": sys.version,
+ "git_version": expected_git_version,
+ "gitlint_version": expected_gitlint_version,
+ "GITLINT_USE_SH_LIB": BaseTestCase.GITLINT_USE_SH_LIB,
+ "TERMINAL_ENCODING": TERMINAL_ENCODING,
+ "FILE_ENCODING": FILE_ENCODING,
+ }
def get_debug_vars_last_commit(self, git_repo=None):
- """ Returns a dict with items related to `gitlint --debug` output for the last commit. """
+ """Returns a dict with items related to `gitlint --debug` output for the last commit."""
target_repo = git_repo if git_repo else self.tmp_git_repo
commit_sha = self.get_last_commit_hash(git_repo=target_repo)
expected_date = git("log", "-1", "--pretty=%ai", _tty_out=False, _cwd=target_repo)
expected_date = arrow.get(str(expected_date), "YYYY-MM-DD HH:mm:ss Z").format("YYYY-MM-DD HH:mm:ss Z")
expected_kwargs = self.get_system_info_dict()
- expected_kwargs.update({'target': target_repo, 'commit_sha': commit_sha, 'commit_date': expected_date})
+ expected_kwargs.update({"target": target_repo, "commit_sha": commit_sha, "commit_date": expected_date})
return expected_kwargs