Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 48 additions & 3 deletions mig/shared/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
#
# 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.

Check warning on line 23 in mig/shared/conf.py

View workflow job for this annotation

GitHub Actions / Style check python and annotate

line too long (81 > 80 characters)
#
# -- END_HEADER ---
#
Expand All @@ -32,17 +32,62 @@
import os
import sys

from mig.shared.configuration import Configuration
from mig.shared.defaults import MIG_ENV
from mig.shared.fileio import unpickle


def get_configuration_object(config_file=None, skip_log=False,
class RuntimeConfiguration:
"""A proxy object to be passed in-place of a Configuration which can be
extended with information relevant only at runtime.

Given Configuration objects are threaded into and through almost all
the necessary codepaths to make this information available, they are an
attractive place to put this - but a Configuration is currently loaded
from static per-site data.

Resolve this dichotomy with this class - a Configuration instance will
continue to represent the static data while an object that proxies its
attributes and thus is entirely drop-in compatible with it can be handed
to callers without being mixed in with the static data.
"""

def __init__(self, configuration):
object.__setattr__(self, '_configuration', configuration)
object.__setattr__(self, '_context', {})

def __delattr__(self, attr):
return delattr(self._configuration, attr)

def __getattr__(self, attr):
return getattr(self._configuration, attr)

def __setattr__(self, attr, value):
return setattr(self._configuration, attr, value)

def context_get(self, context_key):

Check failure on line 68 in mig/shared/conf.py

View workflow job for this annotation

GitHub Actions / Style check python and annotate

unused method 'context_get' (60% confidence)
"""Retrieve the context or a previously registered namespace.
"""
return self._context.get(context_key, None)

def context_set(self, context_key, context_value):

Check failure on line 73 in mig/shared/conf.py

View workflow job for this annotation

GitHub Actions / Style check python and annotate

unused method 'context_set' (60% confidence)
"""Attach a value as named namespace within the active configuration.
"""
self._context[context_key] = context_value

@classmethod

Check failure on line 78 in mig/shared/conf.py

View workflow job for this annotation

GitHub Actions / Style check python and annotate

unused method 'is_runtime_configuration' (60% confidence)
def is_runtime_configuration(cls, obj):
"""Is the given object a runtime configuration."""
return isinstance(obj, cls)


def get_configuration_object(config_file=None,
skip_log=False,
disable_auth_log=False):
"""Simple helper to call the general configuration init. Optional skip_log
and disable_auth_log arguments are passed on to allow skipping the default
log initialization and disabling auth log for unit tests.
"""
from mig.shared.configuration import Configuration
if config_file:
_config_file = config_file
elif os.environ.get('MIG_CONF', None):
Expand All @@ -65,7 +110,7 @@

configuration = Configuration(_config_file, False, skip_log,
disable_auth_log)
return configuration
return RuntimeConfiguration(configuration)


def get_resource_configuration(resource_home, unique_resource_name,
Expand All @@ -85,7 +130,7 @@
return (True, resource_config)


def get_resource_fields(resource_home, unique_resource_name, fields, logger):

Check failure on line 133 in mig/shared/conf.py

View workflow job for this annotation

GitHub Actions / Style check python and annotate

unused function 'get_resource_fields' (60% confidence)
"""Return a dictionary mapping fields to resource_config values.
Missing fields are left out of the result dictionary.
"""
Expand All @@ -102,7 +147,7 @@
return results


def get_resource_exe(resource_config, exe_name, logger):

Check failure on line 150 in mig/shared/conf.py

View workflow job for this annotation

GitHub Actions / Style check python and annotate

unused function 'get_resource_exe' (60% confidence)
for exe in resource_config['EXECONFIG']:

# find the right exe entry
Expand All @@ -119,7 +164,7 @@
return (False, msg)


def get_resource_all_exes(resource_config, logger):

Check failure on line 167 in mig/shared/conf.py

View workflow job for this annotation

GitHub Actions / Style check python and annotate

unused function 'get_resource_all_exes' (60% confidence)
msg = ''
if 'EXECONFIG' not in resource_config:
msg = 'No exe hosts configured!'
Expand All @@ -128,7 +173,7 @@
return (True, resource_config['EXECONFIG'])


def get_all_exe_names(unique_resource_name):

Check failure on line 176 in mig/shared/conf.py

View workflow job for this annotation

GitHub Actions / Style check python and annotate

unused function 'get_all_exe_names' (60% confidence)
exe_names = []
conf = get_configuration_object()
(status, resource_config) = \
Expand Down
6 changes: 4 additions & 2 deletions tests/support/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
Expand Down Expand Up @@ -92,10 +92,10 @@

# Exports to expose at the top level from the support library.

from tests.support.assertover import AssertOver

Check warning on line 95 in tests/support/__init__.py

View workflow job for this annotation

GitHub Actions / Style check python and annotate

module level import not at top of file
from tests.support.configsupp import FakeConfiguration

Check warning on line 96 in tests/support/__init__.py

View workflow job for this annotation

GitHub Actions / Style check python and annotate

module level import not at top of file
from tests.support.loggersupp import FakeLogger, FakeLoggerChecker

Check warning on line 97 in tests/support/__init__.py

View workflow job for this annotation

GitHub Actions / Style check python and annotate

module level import not at top of file
from tests.support.serversupp import make_wrapped_server

Check warning on line 98 in tests/support/__init__.py

View workflow job for this annotation

GitHub Actions / Style check python and annotate

module level import not at top of file


# Basic global logging configuration for testing
Expand Down Expand Up @@ -210,16 +210,18 @@
@staticmethod
def _make_configuration_instance(testcase, configuration_to_make):
if configuration_to_make == 'fakeconfig':
return FakeConfiguration(logger=testcase.logger)
fake_configuration = FakeConfiguration(logger=testcase.logger)
from mig.shared.conf import RuntimeConfiguration
return RuntimeConfiguration(fake_configuration)
elif configuration_to_make == 'testconfig':
from mig.shared.conf import get_configuration_object
configuration = get_configuration_object(skip_log=True,
configuration = get_configuration_object(skip_log=True,
disable_auth_log=True)
configuration.logger = testcase.logger
return configuration
else:
raise AssertionError(
"MigTestCase: unknown configuration %r" % (configuration_to_make,))

Check warning on line 224 in tests/support/__init__.py

View workflow job for this annotation

GitHub Actions / Style check python and annotate

line too long (83 > 80 characters)

def _provide_configuration(self):
return 'unspecified'
Expand Down Expand Up @@ -291,7 +293,7 @@

def assertFileContentIdentical(self, file_actual, file_expected):
"""Make sure file_actual and file_expected are identical"""
with io.open(file_actual) as f_actual, io.open(file_expected) as f_expected:

Check warning on line 296 in tests/support/__init__.py

View workflow job for this annotation

GitHub Actions / Style check python and annotate

line too long (84 > 80 characters)
lhs = f_actual.readlines()
rhs = f_expected.readlines()
different_lines = list(difflib.unified_diff(rhs, lhs))
Expand Down Expand Up @@ -359,7 +361,7 @@
Note that this method, along with a number of others, are defined in
the user portion of the test support libraries.
"""
return UserAssertMixin._provision_test_user(testcase, distinguished_name)

Check warning on line 364 in tests/support/__init__.py

View workflow job for this annotation

GitHub Actions / Style check python and annotate

line too long (81 > 80 characters)


def is_path_within(path, start=None, _msg=None):
Expand All @@ -367,7 +369,7 @@
try:
assert os.path.isabs(path), _msg
relative = os.path.relpath(path, start=start)
except:

Check warning on line 372 in tests/support/__init__.py

View workflow job for this annotation

GitHub Actions / Style check python and annotate

do not use bare 'except'
return False
return not relative.startswith('..')

Expand Down
54 changes: 54 additions & 0 deletions tests/test_mig_shared_conf.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# -*- coding: utf-8 -*-
#
# --- BEGIN_HEADER ---
#
# test_mig_shared_configuration - unit test of configuration
# Copyright (C) 2003-2026 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 shared conf"""

import inspect
import os
import unittest

from tests.support import MigTestCase, TEST_DATA_DIR, PY2, testmain
from tests.support.fixturesupp import FixtureAssertMixin

from mig.shared.conf import Configuration, \
RuntimeConfiguration, \
get_configuration_object


class MigSharedConf(MigTestCase):
"""Coverage of module methods."""

def test_get_configuration_object_returns_runtime_configuration(self):
configuration = get_configuration_object(skip_log=True,
disable_auth_log=True)
self.assertIsInstance(configuration, RuntimeConfiguration)
static_configuration = configuration._configuration
self.assertIsInstance(static_configuration, Configuration)


if __name__ == '__main__':
testmain()
10 changes: 5 additions & 5 deletions tests/test_support.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# -*- coding: utf-8 -*-
#
# --- BEGIN_HEADER ---
Expand Down Expand Up @@ -35,8 +35,7 @@
from tests.support import MigTestCase, PY2, testmain, temppath, \
AssertOver, FakeConfiguration

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


class InstrumentedAssertOver(AssertOver):
Expand Down Expand Up @@ -81,7 +80,7 @@
self.configuration
theexception = raised.exception
self.assertEqual(str(theexception),
"configuration access but testcase did not request it")

Check warning on line 83 in tests/test_support.py

View workflow job for this annotation

GitHub Actions / Style check python and annotate

continuation line under-indented for visual indent

@unittest.skipIf(PY2, "Python 3 only")
def test_unclosed_files_are_recorded(self):
Expand Down Expand Up @@ -143,8 +142,9 @@

def test_provides_a_fake_configuration(self):
configuration = self.configuration

self.assertIsInstance(configuration, FakeConfiguration)
self.assertIsInstance(configuration, RuntimeConfiguration)
static_configuration = configuration._configuration
self.assertIsInstance(static_configuration, FakeConfiguration)

def test_provides_a_fake_configuration_for_the_duration_of_the_test(self):
c1 = self.configuration
Expand All @@ -165,7 +165,7 @@
configuration = self.configuration

# check we have a real config object
self.assertIsInstance(configuration, Configuration)
self.assertIsInstance(configuration, RuntimeConfiguration)
# 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
Expand Down
Loading