summaryrefslogtreecommitdiff
path: root/tests/dist.py
blob: 9403f256fbd23c541425b3eeba37db9ad4e3c0e9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
# Copyright (C) 2013 Red Hat, Inc.
#
# This work is licensed under the GNU GPLv2 or later.
# See the COPYING file in the top-level directory.

import fnmatch
import glob
import imp
import importlib
import os
import sys
import unittest
import xml.etree.ElementTree as ET

_badmodules = ["gi.repository.Gtk", "gi.repository.Gdk"]


def _restore_modules(fn):
    def wrap(*args, **kwargs):
        origimport = __builtins__["__import__"]
        def my_import(name, *iargs, **ikwargs):
            if name in _badmodules:
                raise AssertionError("Tried to import '%s'" % name)
            return origimport(name, *iargs, **ikwargs)

        try:
            __builtins__["__import__"] = my_import
            return fn(*args, **kwargs)
        finally:
            __builtins__["__import__"] = origimport
    return wrap


def _find_py(dirname):
    ret = []
    for root, ignore, filenames in os.walk(dirname):
        for filename in fnmatch.filter(filenames, "*.py"):
            ret.append(os.path.join(root, filename))
    ret.sort(key=lambda s: s.lower())
    return ret


class TestDist(unittest.TestCase):
    """
    Tests to run before release
    """
    def _check_modules(self, files):
        for f in files:
            regular_import = f.endswith(".py")
            if f.endswith("/__init__.py"):
                f = f.rsplit("/", 1)[0]
            name = f.rsplit(".", 1)[0].replace("/", ".")
            if name in sys.modules:
                continue

            if regular_import:
                importlib.import_module(name)
            else:
                imp.load_source(name, f)

        found = []
        for f in _badmodules:
            if f in sys.modules:
                found.append(f)

        if found:
            raise AssertionError("%s found in sys.modules" % found)


    @_restore_modules
    def test_no_gtk_virtinst(self):
        """
        Make sure virtinst doesn't pull in any gnome modules
        """
        files = ["virt-install", "virt-clone", "virt-convert"]
        files += _find_py("virtinst")
        files += _find_py("virtconv")
        files += _find_py("virtcli")

        self._check_modules(files)


    def test_validate_po_files(self):
        """
        Validate that po translations don't mess up python format strings,
        which has broken the app in the past:
        https://bugzilla.redhat.com/show_bug.cgi?id=1350185
        https://bugzilla.redhat.com/show_bug.cgi?id=1433800
        """
        failures = []
        for pofile in glob.glob("po/*.po"):
            import subprocess
            proc = subprocess.Popen(["msgfmt", "--output-file=/dev/null",
                "--check", pofile],
                stdout=subprocess.PIPE, stderr=subprocess.PIPE)
            ignore, stderr = proc.communicate()
            if proc.wait():
                failures.append("%s: %s" % (pofile, stderr))

        if not failures:
            return

        msg = "The following po files have errors:\n"
        msg += "\n".join(failures)
        raise AssertionError(msg)


    def test_ui_minimum_version(self):
        """
        Ensure all glade XML files don't _require_ UI bits later than
        our minimum supported version
        """
        # RHEL 7.3 has gtk 3.14, so that's our current minimum target
        minimum_version_major = 3
        minimum_version_minor = 14
        minimum_version_str = "%s.%s" % (minimum_version_major,
                                         minimum_version_minor)

        failures = []
        for filename in glob.glob("ui/*.ui"):
            required_version = None
            for line in open(filename).readlines():
                # This is much faster than XML parsing the whole file
                if not line.strip().startswith('<requires '):
                    continue

                req = ET.fromstring(line)
                if (req.tag != "requires" or
                    req.attrib.get("lib") != "gtk+"):
                    continue
                required_version = req.attrib["version"]

            if required_version is None:
                raise AssertionError("ui file=%s doesn't have a <requires> "
                    "tag for gtk+")

            if (int(required_version.split(".")[0]) != minimum_version_major or
                int(required_version.split(".")[1]) != minimum_version_minor):
                failures.append((filename, required_version))

        if not failures:
            return

        err = ("The following files should require version of gtk-%s:\n" %
            minimum_version_str)
        err += "\n".join([("%s version=%s" % tup) for tup in failures])
        raise AssertionError(err)


    def test_ui_translatable_atknames(self):
        """
        We only use accessible names for uitests, they shouldn't be
        marked as translatable
        """
        failures = []
        atkstr = "AtkObject::accessible-name"
        for filename in glob.glob("ui/*.ui"):
            for line in open(filename).readlines():
                if atkstr not in line:
                    continue
                if "translatable=" in line:
                    failures.append(filename)
                    break

        if not failures:
            return
        err = "Some files incorrectly have translatable ATK names.\n"
        err += "Run this command to fix:\n\n"
        err += ("""sed -i -e 's/%s" translatable="yes"/%s"/g' """ %
                (atkstr, atkstr))
        err += " ".join(failures)
        raise AssertionError(err)