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
8 changes: 8 additions & 0 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,14 @@ has_g_spawn_check_wait_status = cc.has_function(
'g_spawn_check_wait_status',
dependencies : [ glib ])

# Check whether glib2 has G_TEST_SUBPROCESS_DEFAULT enum member.
has_g_test_subprocess_default = cc.compiles(
'''#include <glib.h>
int foo = G_TEST_SUBPROCESS_DEFAULT;
''',
dependencies : [ glib ],
name : 'G_TEST_SUBPROCESS_DEFAULT')

with_py3 = get_option('with_py3')
if with_py3
if get_option('skip_introspection')
Expand Down
4 changes: 4 additions & 0 deletions modulemd/include/private/glib-extensions.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@
G_DEFINE_AUTOPTR_CLEANUP_FUNC (GDate, g_date_free)
#endif

/* G_TEST_SUBPROCESS_DEFAULT was added in Glib 2.74. */
#ifndef HAVE_G_TEST_SUBPROCESS_DEFAULT
#define G_TEST_SUBPROCESS_DEFAULT 0
#endif

#ifndef HAVE_EXTEND_AND_STEAL

Expand Down
1 change: 1 addition & 0 deletions modulemd/include/private/test-utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include <glib.h>
#include <locale.h>
#include <yaml.h>
#include "glib-extensions.h"

G_BEGIN_DECLS

Expand Down
1 change: 1 addition & 0 deletions modulemd/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ cdata.set('HAVE_RPMIO', rpm.found())
cdata.set('HAVE_GDATE_AUTOPTR', has_gdate_autoptr)
cdata.set('HAVE_EXTEND_AND_STEAL', has_extend_and_steal)
cdata.set('HAVE_G_SPAWN_CHECK_WAIT_STATUS', has_g_spawn_check_wait_status)
cdata.set('HAVE_G_TEST_SUBPROCESS_DEFAULT', has_g_test_subprocess_default)
cdata.set('HAVE_OVERFLOWED_BUILDORDER', accept_overflowed_buildorder)
configure_file(
output : 'config.h',
Expand Down
25 changes: 25 additions & 0 deletions modulemd/tests/ModulemdTests/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,21 @@ def expect_signal(
elif self._caught_signal and not expect_signal:
raise AssertionError("Signal caught in non-warning state")

def assertProcessFailure(self, callable, *args):
"""Calls the callable in a subprocess and checks whether the process was
killed with a signal depending on Glib warning fatality."""
pid = os.fork()
if pid == 0:
callable(*args)
os._exit(0)
_, status = os.waitpid(pid, 0)
if self.warnings_fatal:
if not os.WIFSIGNALED(status):
raise AssertionError("Child process was not aborted")
else:
if os.WIFSIGNALED(status):
raise AssertionError("Child process was unexpectedly aborted")

@property
def warnings_fatal(self):
gdebug = os.getenv("G_DEBUG", "").split(",")
Expand All @@ -67,3 +82,13 @@ def assertRaisesRegex(self, *args, **kwargs):
return super(TestBase, self).assertRaisesRegex(*args, **kwargs)
except AttributeError:
return self.assertRaisesRegexp(*args, **kwargs)

def assertRaisesRegexOrDies(self, callable, *args, **kwargs):
"""Checks that the callable terminates a process if Glib warnings are
fatal. Otherwise, that the callable raised a given exception type with
the given value matching a regular expression."""
if self.warnings_fatal:
self.assertProcessFailure(callable)
else:
with self.assertRaisesRegex(*args, **kwargs):
callable()
31 changes: 21 additions & 10 deletions modulemd/tests/ModulemdTests/defaults.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,20 @@
from base import TestBase


def _zero_mdversion():
defs = Modulemd.Defaults.new(0, "foo")


def _unknown_mdversion():
defs = Modulemd.Defaults.new(
Modulemd.DefaultsVersionEnum.LATEST + 1, "foo"
)


def _set_module_name_to_none(defs):
defs.props.module_name = None


class TestDefaults(TestBase):
def test_constructors(self):
# Test that the new() function works
Expand All @@ -48,16 +62,14 @@ def test_constructors(self):
Modulemd.Defaults()

# Test with a zero mdversion
with self.assertRaisesRegex(TypeError, "constructor returned NULL"):
with self.expect_signal():
defs = Modulemd.Defaults.new(0, "foo")
self.assertRaisesRegexOrDies(
_zero_mdversion, TypeError, "constructor returned NULL"
)

# Test with an unknown mdversion
with self.assertRaisesRegex(TypeError, "constructor returned NULL"):
with self.expect_signal():
defs = Modulemd.Defaults.new(
Modulemd.DefaultsVersionEnum.LATEST + 1, "foo"
)
self.assertRaisesRegexOrDies(
_unknown_mdversion, TypeError, "constructor returned NULL"
)

# Test with no name
with self.assertRaisesRegex(
Expand Down Expand Up @@ -99,8 +111,7 @@ def test_module_name(self):
assert defs.get_module_name() == "foo"

# Ensure we cannot set the module_name
with self.expect_signal():
defs.props.module_name = None
self.assertProcessFailure(_set_module_name_to_none, defs)

def test_modified(self):
defs = Modulemd.Defaults.new(
Expand Down
26 changes: 14 additions & 12 deletions modulemd/tests/ModulemdTests/dependencies.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,38 +28,40 @@
from base import TestBase


def _get_buildtime_streams(modulemd_dependecies, stream_name):
modulemd_dependecies.get_buildtime_streams(stream_name)


def _get_runtime_streams(modulemd_dependecies, stream_name):
modulemd_dependecies.get_runtime_streams(stream_name)


class TestDependencies(TestBase):
def test_constructor(self):
# Test that the new() function works
d = Modulemd.Dependencies.new()
assert d
assert d.get_buildtime_modules() == []
with self.expect_signal(only_on_fatal_warnings=True):
d.get_buildtime_streams("foobar123")
self.assertProcessFailure(_get_buildtime_streams, d, "foobar123")
assert d.get_runtime_modules() == []
with self.expect_signal(only_on_fatal_warnings=True):
d.get_runtime_streams("foobar123")
self.assertProcessFailure(_get_runtime_streams, d, "foobar123")

# Test that keyword name is accepted
d = Modulemd.Dependencies()
assert d
assert d.get_buildtime_modules() == []
with self.expect_signal(only_on_fatal_warnings=True):
d.get_buildtime_streams("foobar123")
self.assertProcessFailure(_get_buildtime_streams, d, "foobar123")
assert d.get_runtime_modules() == []
with self.expect_signal(only_on_fatal_warnings=True):
d.get_runtime_streams("foobar123")
self.assertProcessFailure(_get_runtime_streams, d, "foobar123")

def test_copy(self):
d_orig = Modulemd.Dependencies()
d = d_orig.copy()
assert d
assert d.get_buildtime_modules() == []
with self.expect_signal(only_on_fatal_warnings=True):
d.get_buildtime_streams("foobar123")
self.assertProcessFailure(_get_buildtime_streams, d, "foobar123")
assert d.get_runtime_modules() == []
with self.expect_signal(only_on_fatal_warnings=True):
d.get_runtime_streams("foobar123")
self.assertProcessFailure(_get_runtime_streams, d, "foobar123")

d_orig.add_buildtime_stream("buildmod1", "stream2")
d_orig.add_buildtime_stream("buildmod1", "stream1")
Expand Down
21 changes: 15 additions & 6 deletions modulemd/tests/ModulemdTests/profile.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,18 @@
from base import TestBase


def construct_without_arguments():
Modulemd.Profile()


def construct_with_none_name():
Modulemd.Profile(name=None)


def _set_props_name(modulemd_profile, value):
modulemd_profile.props.name = value


class TestProfile(TestBase):
def test_constructor(self):
# Test that the new() function works
Expand All @@ -51,11 +63,9 @@ def test_constructor(self):
Modulemd.Profile.new(None)
assert "does not allow None as a value" in cm.exception.__str__()

with self.expect_signal():
Modulemd.Profile()
self.assertProcessFailure(construct_without_arguments)

with self.expect_signal():
Modulemd.Profile(name=None)
self.assertProcessFailure(construct_with_none_name)

def test_copy(self):
p_orig = Modulemd.Profile(name="testprofile")
Expand Down Expand Up @@ -84,8 +94,7 @@ def test_get_name(self):
assert p.get_name() == "testprofile"
assert p.props.name == "testprofile"

with self.expect_signal():
p.props.name = "notadrill"
self.assertProcessFailure(_set_props_name, p, "notadrill")

def test_get_set_description(self):
p = Modulemd.Profile(name="testprofile")
Expand Down
21 changes: 15 additions & 6 deletions modulemd/tests/ModulemdTests/servicelevel.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,18 @@
import datetime


def _construct_without_arguments():
Modulemd.ServiceLevel()


def _construct_with_none_name():
Modulemd.ServiceLevel(name=None)


def _set_props_name(modulemd_servicelevel, value):
modulemd_servicelevel.props.name = value


class TestServiceLevel(TestBase):
def test_constructors(self):
# Test that the new() function works
Expand All @@ -56,12 +68,10 @@ def test_constructors(self):
assert "does not allow None as a value" in e.__str__()

# Test that we fail if object is instantiated without a name
with self.expect_signal():
sl = Modulemd.ServiceLevel()
self.assertProcessFailure(_construct_without_arguments)

# Test that we fail if object is instantiated with a None name
with self.expect_signal():
sl = Modulemd.ServiceLevel(name=None)
self.assertProcessFailure(_construct_with_none_name)

def test_copy(self):
sl = Modulemd.ServiceLevel.new("foo")
Expand Down Expand Up @@ -93,8 +103,7 @@ def test_get_name(self):
assert sl.props.name == "foo"

# This property is not writable, make sure it fails to attempt it
with self.expect_signal():
sl.props.name = "bar"
self.assertProcessFailure(_set_props_name, sl, "bar")

def test_get_set_eol(self):
sl = Modulemd.ServiceLevel.new("foo")
Expand Down
21 changes: 15 additions & 6 deletions modulemd/tests/ModulemdTests/translationentry.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,18 @@
from base import TestBase


def _instantiate_without_locale():
Modulemd.TranslationEntry()


def _instantiate_with_none_local():
Modulemd.TranslationEntry(locale=None)


def _set_locale(te):
te.props.locale = "en_GB"


class TestTranslationEntry(TestBase):
def test_constructors(self):
# Test that the new() function works
Expand Down Expand Up @@ -118,12 +130,10 @@ def test_constructors(self):
assert "does not allow None as a value" in e.__str__()

# Test that we fail if object is instantiated without a locale
with self.expect_signal():
Modulemd.TranslationEntry()
self.assertProcessFailure(_instantiate_without_locale)

# Test that we fail if object is instantiated with a None locale
with self.expect_signal():
Modulemd.TranslationEntry(locale=None)
self.assertProcessFailure(_instantiate_with_none_local)

def test_copy(self):
te_orig = Modulemd.TranslationEntry(locale="en_US")
Expand Down Expand Up @@ -162,8 +172,7 @@ def test_get_locale(self):
assert te.get_locale() == "en_US"
assert te.props.locale == "en_US"

with self.expect_signal():
te.props.locale = "en_GB"
self.assertProcessFailure(_set_locale, te)

def test_get_set_summary(self):
te = Modulemd.TranslationEntry(locale="en_US")
Expand Down
Loading
Loading