Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master' into edge
Browse files Browse the repository at this point in the history
  • Loading branch information
jonasbardino committed Oct 4, 2024
2 parents 687a842 + 5748ddd commit 8b3c81c
Show file tree
Hide file tree
Showing 2 changed files with 121 additions and 5 deletions.
47 changes: 46 additions & 1 deletion tests/support/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
#
# --- BEGIN_HEADER ---
#
# __init__ - package marker
# __init__ - package marker and core package functions
# Copyright (C) 2003-2024 The MiG Project by the Science HPC Center at UCPH
#
# This file is part of MiG.
Expand Down Expand Up @@ -40,6 +40,7 @@
import sys
from unittest import TestCase, main as testmain

from tests.support.configsupp import FakeConfiguration
from tests.support.suppconst import MIG_BASE, TEST_BASE, TEST_FIXTURE_DIR, \
TEST_OUTPUT_DIR

Expand All @@ -48,6 +49,20 @@
# force defaults to a local environment
os.environ['MIG_ENV'] = 'local'

# expose the configured environment as a constant
MIG_ENV = os.environ['MIG_ENV']

if MIG_ENV == 'local':
# force testconfig as the conig file path
is_py2 = PY2
_conf_dir_suffix = "-py%s" % ('2' if is_py2 else '3',)
_conf_dir = "testconfs%s" % (_conf_dir_suffix,)
_local_conf = os.path.join(
MIG_BASE, 'envhelp/output', _conf_dir, 'MiGserver.conf')
_config_file = os.getenv('MIG_CONF', None)
if _config_file is None:
os.environ['MIG_CONF'] = _local_conf

# All MiG related code will at some point include bits from the mig module
# namespace. Rather than have this knowledge spread through every test file,
# make the sole responsbility of test files to find the support file and
Expand Down Expand Up @@ -103,6 +118,7 @@ def __init__(self, *args):
super(MigTestCase, self).__init__(*args)
self._cleanup_checks = list()
self._cleanup_paths = set()
self._configuration = None
self._logger = None
self._skip_logging = False

Expand Down Expand Up @@ -153,6 +169,31 @@ def _reset_logging(self, stream):
root_handler = root_logger.handlers[0]
root_handler.stream = stream

# testcase defaults

@staticmethod
def _make_configuration_instance(configuration_to_make):
if configuration_to_make == 'fakeconfig':
return FakeConfiguration()
elif configuration_to_make == 'testconfig':
from mig.shared.conf import get_configuration_object
return get_configuration_object(skip_log=True, disable_auth_log=True)
else:
raise AssertionError(
"MigTestCase: unknown configuration %r" % (configuration_to_make,))

def _provide_configuration(self):
return 'fakeconfig'

@property
def configuration(self):
"""Init a fake configuration if not already done"""
if self._configuration is None:
configuration_to_make = self._provide_configuration()
self._configuration = self._make_configuration_instance(
configuration_to_make)
return self._configuration

@property
def logger(self):
"""Init a fake logger if not already done"""
Expand Down Expand Up @@ -199,6 +240,10 @@ def assertPathExists(self, relative_path):
assert not os.path.isabs(
relative_path), "expected relative path within output folder"
absolute_path = os.path.join(TEST_OUTPUT_DIR, relative_path)
return MigTestCase._absolute_path_kind(absolute_path)

@staticmethod
def _absolute_path_kind(absolute_path):
stat_result = os.lstat(absolute_path)
if stat.S_ISLNK(stat_result.st_mode):
return "symlink"
Expand Down
79 changes: 75 additions & 4 deletions tests/test_support.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,47 @@
# -*- coding: utf-8 -*-
#
# --- BEGIN_HEADER ---
#
# test_support - unit test of the corresponding tests module
# Copyright (C) 2003-2024 The MiG Project by the Science HPC Center at UCPH
#
# This file is part of MiG.
#
# MiG is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# MiG is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
# USA.
#
# --- END_HEADER ---
#

"""Unit tests for the tests module pointed to in the filename"""

from __future__ import print_function
import os
import sys
import unittest

from tests.support import MigTestCase, PY2, testmain, temppath, \
AssertOver
AssertOver, FakeConfiguration

from mig.shared.conf import get_configuration_object
from mig.shared.configuration import Configuration


class InstrumentedAssertOver(AssertOver):
"""Helper to keep track of AssertOver runs"""

def __init__(self, *args, **kwargs):
AssertOver.__init__(self, *args, **kwargs)
self._check_callable = None
Expand All @@ -24,6 +58,7 @@ def was_check_callable_called(self):

def to_check_callable(self):
_check_callable = AssertOver.to_check_callable(self)

def _wrapped_check_callable():
self._check_callable_called = True
_check_callable()
Expand All @@ -32,13 +67,26 @@ def _wrapped_check_callable():


class SupportTestCase(MigTestCase):
"""Coverage of base Support helpers"""

def _class_attribute(self, name, **kwargs):
cls = type(self)
if 'value' in kwargs:
setattr(cls, name, kwargs['value'])
else:
return getattr(cls, name, None)

def test_provides_a_fake_configuration(self):
configuration = self.configuration

self.assertIsInstance(configuration, FakeConfiguration)

def test_provides_a_fake_configuration_for_the_duration_of_the_test(self):
c1 = self.configuration
c2 = self.configuration

self.assertIs(c2, c1)

@unittest.skipIf(PY2, "Python 3 only")
def test_unclosed_files_are_recorded(self):
tmp_path = temppath("support-unclosed", self)
Expand Down Expand Up @@ -67,18 +115,21 @@ def test_when_asserting_over_multiple_values(self):
def assert_is_int(value):
assert isinstance(value, int)

attempt_wrapper = self.assert_over(values=(1, 2, 3), _AssertOver=InstrumentedAssertOver)
attempt_wrapper = self.assert_over(
values=(1, 2, 3), _AssertOver=InstrumentedAssertOver)

# record the wrapper on the test case so the subsequent test can assert against it
self._class_attribute('surviving_attempt_wrapper', value=attempt_wrapper)
self._class_attribute('surviving_attempt_wrapper',
value=attempt_wrapper)

with attempt_wrapper as attempt:
attempt(assert_is_int)
attempt_wrapper.assert_success()

self.assertTrue(attempt_wrapper.has_check_callable())
# cleanup was recorded
self.assertIn(attempt_wrapper.get_check_callable(), self._cleanup_checks)
self.assertIn(attempt_wrapper.get_check_callable(),
self._cleanup_checks)

def test_when_asserting_over_multiple_values_after(self):
# test name is purposefully after ..._recorded in sort order
Expand All @@ -88,5 +139,25 @@ def test_when_asserting_over_multiple_values_after(self):
self.assertTrue(attempt_wrapper.was_check_callable_called())


class SupportTestCase_overridden_configuration(MigTestCase):
"""Coverage of base Support helpers extension with configuration override"""

def _provide_configuration(self):
return 'testconfig'

def test_provides_the_test_configuration(self):
expected_last_dir = 'testconfs-py2' if PY2 else 'testconfs-py3'

configuration = self.configuration

# check we have a real config object
self.assertIsInstance(configuration, Configuration)
# check for having loaded a config file from a test config dir
config_file_path_parts = configuration.config_file.split(os.path.sep)
config_file_path_parts.pop() # discard file part
config_file_last_dir = config_file_path_parts.pop()
self.assertTrue(config_file_last_dir, expected_last_dir)


if __name__ == '__main__':
testmain()

0 comments on commit 8b3c81c

Please sign in to comment.