Changeset - 67e54e3374dd
[Not reviewed]
0 3 0
Branko Majic (branko) - 3 months ago 2025-09-07 00:00:20
branko@majic.rs
GC-48: Update the test framework:

- Slight change required for handling differences in how the output
lines are being broken up during testing.
3 files changed with 7 insertions and 7 deletions:
0 comments (0 inline, 0 general)
functional_tests/test_client.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
#
 
# Copyright (C) 2018, 2020, 2024, 2025 Branko Majic
 
#
 
# This file is part of Gimmecert.
 
#
 
# Gimmecert is free software: you can redistribute it and/or modify it
 
# under the terms of the GNU General Public License as published by the Free
 
# Software Foundation, either version 3 of the License, or (at your option) any
 
# later version.
 
#
 
# Gimmecert is distributed in the hope that it will be useful, but
 
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 
# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
 
# details.
 
#
 
# You should have received a copy of the GNU General Public License along with
 
# Gimmecert.  If not, see <http://www.gnu.org/licenses/>.
 
#
 

	
 

	
 
from .base import run_command
 

	
 

	
 
def test_client_command_available_with_help():
 
    # After issuing a couple of server certificates, John has decided
 
    # to test out TLS client certificate authentication in his
 
    # project. For this, naturally, he needs a client certificate.
 
    # Hoping that the Gimmecert tool has ability to generate those
 
    # too, he runs the tool to see available commands.
 
    stdout, stderr, exit_code = run_command("gimmecert")
 

	
 
    # Looking at output, John notices the client command.
 
    assert exit_code == 0
 
    assert stderr == ""
 
    assert "client" in stdout
 

	
 
    # He goes ahead and has a look at the client command invocation to
 
    # check what kind of parameters he might need to provide.
 
    stdout, stderr, exit_code = run_command("gimmecert", "client", "-h")
 

	
 
    # John can see that the command accepts a single positional
 
    # argument - an entity name.
 
    assert exit_code == 0
 
    assert stderr == ""
 
    assert stdout.startswith("usage: gimmecert client")
 
    assert stdout.split('\n')[2].endswith(" entity_name")  # Third line of help.
 
    assert stdout.split('\n')[0].endswith(" entity_name")  # First line of help.
 

	
 

	
 
def test_client_command_requires_initialised_hierarchy(tmpdir):
 
    # John is about to issue a client certificate. He switches to his
 
    # project directory.
 
    tmpdir.chdir()
 

	
 
    # John tries to issue a client certificate.
 
    stdout, stderr, exit_code = run_command("gimmecert", "client", "myclient")
 

	
 
    # Unfortunately, John has forgotten to initialise the CA hierarchy
 
    # from within this directory, and is instead presented with an
 
    # error.
 
    assert stdout == ""
 
    assert stderr == "CA hierarchy must be initialised prior to issuing client certificates. Run the gimmecert init command first.\n"
 
    assert exit_code != 0
 

	
 

	
 
def test_client_command_issues_client_certificate(tmpdir):
 
    # John is about to issue a client certificate. He switches to his
 
    # project directory, and initialises the CA hierarchy there.
 
    tmpdir.chdir()
 
    run_command("gimmecert", "init")
 

	
 
    # He then runs command for issuing a client certificate.
 
    stdout, stderr, exit_code = run_command('gimmecert', 'client', 'myclient')
 

	
 
    # John notices that the command has run without an error, and that
 
    # it has printed out path to the private key and certificate.
 
    assert stderr == ""
 
    assert exit_code == 0
 
    assert "Client certificate issued." in stdout
 
    assert ".gimmecert/client/myclient.key.pem" in stdout
 
    assert ".gimmecert/client/myclient.cert.pem" in stdout
 

	
 
    # John has a look at the generated private key using the OpenSSL
 
    # CLI.
 
    stdout, stderr, exit_code = run_command('openssl', 'rsa', '-noout', '-text', '-in', '.gimmecert/client/myclient.key.pem')
 

	
 
    # No errors are reported, and John is able to see some details
 
    # about the generated key.
 
    assert exit_code == 0
 
    assert stderr == ""
 
    assert "Private-Key: (2048 bit, 2 primes)" in stdout
 

	
 
    # John then has a look at the generated certificate file.
 
    stdout, stderr, exit_code = run_command('openssl', 'x509', '-noout', '-text', '-in', '.gimmecert/client/myclient.cert.pem')
 

	
functional_tests/test_renew.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
#
 
# Copyright (C) 2018, 2020, 2024, 2025 Branko Majic
 
#
 
# This file is part of Gimmecert.
 
#
 
# Gimmecert is free software: you can redistribute it and/or modify it
 
# under the terms of the GNU General Public License as published by the Free
 
# Software Foundation, either version 3 of the License, or (at your option) any
 
# later version.
 
#
 
# Gimmecert is distributed in the hope that it will be useful, but
 
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 
# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
 
# details.
 
#
 
# You should have received a copy of the GNU General Public License along with
 
# Gimmecert.  If not, see <http://www.gnu.org/licenses/>.
 
#
 

	
 

	
 
from .base import run_command
 

	
 

	
 
def test_renew_command_available_with_help():
 
    # John has been issuing server and client certificates using
 
    # Gimmecert for a while now. The project has been in use for quite
 
    # some time, and John has realised the certificates might be about
 
    # to expire. Thinking how tedious it would be to generate
 
    # everything again from scratch, he tries to figure out if there
 
    # is an easier way to do it instead of providing information for
 
    # all of the entities instead.
 
    stdout, stderr, exit_code = run_command("gimmecert")
 

	
 
    # Looking at output, John notices the renew command.
 
    assert exit_code == 0
 
    assert stderr == ""
 
    assert "renew" in stdout
 

	
 
    # He goes ahead and has a look at command invocation to check what
 
    # kind of parameters he might need to provide.
 
    stdout, stderr, exit_code = run_command("gimmecert", "renew", "-h")
 

	
 
    # John can see that the command accepts two positional argument -
 
    # type of entity, and entity name.
 
    assert exit_code == 0
 
    assert stderr == ""
 
    assert stdout.startswith("usage: gimmecert renew")
 
    assert stdout.split('\n')[3].endswith("{server,client} entity_name")  # Fourth line of help (first two are options)
 
    assert stdout.split('\n')[0].endswith("{server,client} entity_name")  # First line of help.
 

	
 

	
 
def test_renew_command_requires_initialised_hierarchy(tmpdir):
 
    # John decides it's time to renew one of the certificates. He
 
    # switches to his project directory.
 
    tmpdir.chdir()
 

	
 
    # John tries to renew a server certificate.
 
    stdout, stderr, exit_code = run_command("gimmecert", "renew", "server", "myserver")
 

	
 
    # John has forgotten to initialise the CA hierarchy from within
 
    # this directory, and is instead presented with an error.
 
    assert exit_code != 0
 
    assert stdout == ""
 
    assert stderr == "No CA hierarchy has been initialised yet. Run the gimmecert init command and issue some certificates first.\n"
 

	
 
    # John gives the screen a weird look, and tries again, this time
 
    # with a client certificate renewal.
 
    stdout, stderr, exit_code = run_command("gimmecert", "renew", "client", "myclient")
 

	
 
    # John gets presented with the same error yet again. Suddenly, he
 
    # realizes he is in a wrong directory... Oh well...
 
    assert exit_code != 0
 
    assert stdout == ""
 
    assert stderr == "No CA hierarchy has been initialised yet. Run the gimmecert init command and issue some certificates first.\n"
 

	
 

	
 
def test_renew_command_reports_error_if_entity_does_not_exist(tmpdir):
 
    # John finally finds his way around to the project directory where
 
    # Gimmecert has already been used to set-up a hierarchy, and where
 
    # a couple of server and client certificates have been issued.
 
    tmpdir.chdir()
 
    run_command("gimmecert", "init")
 
    run_command("gimmecert", "server", "someserver")
 
    run_command("gimmecert", "client", "someclient")
 

	
 
    # He runs the command for renewing a server certificate.
 
    stdout, stderr, exit_code = run_command('gimmecert', 'renew', 'server', 'myserver')
 

	
 
    # Unfortunately for him, this server certificate has not been
 
    # issued before, and he is presented with an error.
 
    assert exit_code != 0
 
    assert stdout == ''
 
    assert stderr == "Cannot renew certificate. No existing certificate found for server myserver.\n"
 

	
 
    # This is going to be one of those days... He tries then to renew
 
    # a client certificate instead.
 
    stdout, stderr, exit_code = run_command('gimmecert', 'renew', 'client', 'myclient')
setup.py
Show inline comments
 
#!/usr/bin/env python
 
# -*- coding: utf-8 -*-
 
#
 
# Copyright (C) 2018, 2020, 2024, 2025 Branko Majic
 
#
 
# This file is part of Gimmecert.
 
#
 
# Gimmecert is free software: you can redistribute it and/or modify it
 
# under the terms of the GNU General Public License as published by the Free
 
# Software Foundation, either version 3 of the License, or (at your option) any
 
# later version.
 
#
 
# Gimmecert is distributed in the hope that it will be useful, but
 
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 
# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
 
# details.
 
#
 
# You should have received a copy of the GNU General Public License along with
 
# Gimmecert.  If not, see <http://www.gnu.org/licenses/>.
 
#
 

	
 
import os
 
from setuptools import setup, find_packages
 

	
 
README = open(os.path.join(os.path.dirname(__file__), 'README.rst')).read()
 

	
 
python_requirements = ">=3.9,<3.13"
 

	
 
install_requirements = [
 
    'cryptography>=42.0,<42.1',
 
    'python-dateutil>=2.8,<2.9',
 
]
 

	
 
doc_requirements = [
 
    'sphinx>=7.1,<7.2',
 
]
 

	
 
test_lint_requirements = [
 
    'flake8>=7.0,<7.1',
 
    'flake8>=7.3,<7.4',
 
]
 

	
 
test_requirements = [
 
    'time-machine>=2.13,<2.14',
 
    'pytest>=8.0,<8.1',
 
    'pytest-cov>=4.1,<4.2',
 
    'tox>=4.13,<4.14',
 
    'time-machine>=2.19,<2.20',
 
    'pytest>=8.4,<8.5',
 
    'pytest-cov>=6.3,<6.4',
 
    'tox>=4.30,<4.31',
 
    'pexpect>=4.9,<4.10',
 
]
 

	
 
release_requirements = [
 
    'twine',
 
]
 

	
 
development_requirements = doc_requirements + test_requirements + test_lint_requirements + release_requirements
 

	
 
extras_requirements = {
 
    'devel': development_requirements,
 
    'doc': doc_requirements,
 
    'test': test_requirements,
 
    'testlint': test_lint_requirements,
 
}
 

	
 
# allow setup.py to be run from any path
 
os.chdir(os.path.normpath(os.path.join(os.path.abspath(__file__), os.pardir)))
 

	
 
setup(
 
    name='gimmecert',
 
    version='0.0.0',
 
    packages=find_packages(exclude=['tests', 'functional_tests']),
 
    include_package_data=True,
 
    license='GPLv3+',
 
    description='A simple tool for quickly issuing server and client certificates.',
 
    long_description=README,
 
    url='http://projects.majic.rs/gimmecert',
 
    author='Branko Majic',
 
    author_email='branko@majic.rs',
 
    python_requires=python_requirements,
 
    install_requires=install_requirements,
 
    tests_require=test_requirements,
 
    extras_require=extras_requirements,
 
    entry_points={
 
        'console_scripts': ['gimmecert=gimmecert.cli:main'],
 
    },
 
    classifiers=[
 
        'Development Status :: 5 - Production/Stable',
 
        'Environment :: Console',
 
        'Intended Audience :: Developers',
 
        'Intended Audience :: System Administrators',
 
        'License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)',
 
        'Operating System :: OS Independent',
 
        'Programming Language :: Python :: 3.9',
 
        'Programming Language :: Python :: 3.10',
 
        'Programming Language :: Python :: 3.11',
 
        'Programming Language :: Python :: 3.12',
0 comments (0 inline, 0 general)