ยปCore Development>Code coverage>Tools/ssl/test_multiple_versions.py

Python code coverage for Tools/ssl/test_multiple_versions.py

#countcontent
1n/a#./python
2n/a"""Run Python tests with multiple installations of OpenSSL
3n/a
4n/aThe script
5n/a
6n/a (1) downloads OpenSSL tar bundle
7n/a (2) extracts it to ../openssl/src/openssl-VERSION/
8n/a (3) compiles OpenSSL
9n/a (4) installs OpenSSL into ../openssl/VERSION/
10n/a (5) forces a recompilation of Python modules using the
11n/a header and library files from ../openssl/VERSION/
12n/a (6) runs Python's test suite
13n/a
14n/aThe script must be run with Python's build directory as current working
15n/adirectory:
16n/a
17n/a ./python Tools/ssl/test_multiple_versions.py
18n/a
19n/aThe script uses LD_RUN_PATH, LD_LIBRARY_PATH, CPPFLAGS and LDFLAGS to bend
20n/asearch paths for header files and shared libraries. It's known to work on
21n/aLinux with GCC 4.x.
22n/a
23n/a(c) 2013 Christian Heimes <christian@python.org>
24n/a"""
25n/aimport logging
26n/aimport os
27n/aimport tarfile
28n/aimport shutil
29n/aimport subprocess
30n/aimport sys
31n/afrom urllib.request import urlopen
32n/a
33n/alog = logging.getLogger("multissl")
34n/a
35n/aOPENSSL_VERSIONS = [
36n/a "0.9.7m", "0.9.8i", "0.9.8l", "0.9.8m", "0.9.8y", "1.0.0k", "1.0.1e"
37n/a]
38n/aFULL_TESTS = [
39n/a "test_asyncio", "test_ftplib", "test_hashlib", "test_httplib",
40n/a "test_imaplib", "test_nntplib", "test_poplib", "test_smtplib",
41n/a "test_smtpnet", "test_urllib2_localnet", "test_venv"
42n/a]
43n/aMINIMAL_TESTS = ["test_ssl", "test_hashlib"]
44n/aCADEFAULT = True
45n/aHERE = os.path.abspath(os.getcwd())
46n/aDEST_DIR = os.path.abspath(os.path.join(HERE, os.pardir, "openssl"))
47n/a
48n/a
49n/aclass BuildSSL:
50n/a url_template = "https://www.openssl.org/source/openssl-{}.tar.gz"
51n/a
52n/a module_files = ["Modules/_ssl.c",
53n/a "Modules/socketmodule.c",
54n/a "Modules/_hashopenssl.c"]
55n/a
56n/a def __init__(self, version, openssl_compile_args=(), destdir=DEST_DIR):
57n/a self._check_python_builddir()
58n/a self.version = version
59n/a self.openssl_compile_args = openssl_compile_args
60n/a # installation directory
61n/a self.install_dir = os.path.join(destdir, version)
62n/a # source file
63n/a self.src_file = os.path.join(destdir, "src",
64n/a "openssl-{}.tar.gz".format(version))
65n/a # build directory (removed after install)
66n/a self.build_dir = os.path.join(destdir, "src",
67n/a "openssl-{}".format(version))
68n/a
69n/a @property
70n/a def openssl_cli(self):
71n/a """openssl CLI binary"""
72n/a return os.path.join(self.install_dir, "bin", "openssl")
73n/a
74n/a @property
75n/a def openssl_version(self):
76n/a """output of 'bin/openssl version'"""
77n/a env = os.environ.copy()
78n/a env["LD_LIBRARY_PATH"] = self.lib_dir
79n/a cmd = [self.openssl_cli, "version"]
80n/a return self._subprocess_output(cmd, env=env)
81n/a
82n/a @property
83n/a def pyssl_version(self):
84n/a """Value of ssl.OPENSSL_VERSION"""
85n/a env = os.environ.copy()
86n/a env["LD_LIBRARY_PATH"] = self.lib_dir
87n/a cmd = ["./python", "-c", "import ssl; print(ssl.OPENSSL_VERSION)"]
88n/a return self._subprocess_output(cmd, env=env)
89n/a
90n/a @property
91n/a def include_dir(self):
92n/a return os.path.join(self.install_dir, "include")
93n/a
94n/a @property
95n/a def lib_dir(self):
96n/a return os.path.join(self.install_dir, "lib")
97n/a
98n/a @property
99n/a def has_openssl(self):
100n/a return os.path.isfile(self.openssl_cli)
101n/a
102n/a @property
103n/a def has_src(self):
104n/a return os.path.isfile(self.src_file)
105n/a
106n/a def _subprocess_call(self, cmd, stdout=subprocess.DEVNULL, env=None,
107n/a **kwargs):
108n/a log.debug("Call '%s'", " ".join(cmd))
109n/a return subprocess.check_call(cmd, stdout=stdout, env=env, **kwargs)
110n/a
111n/a def _subprocess_output(self, cmd, env=None, **kwargs):
112n/a log.debug("Call '%s'", " ".join(cmd))
113n/a out = subprocess.check_output(cmd, env=env)
114n/a return out.strip().decode("utf-8")
115n/a
116n/a def _check_python_builddir(self):
117n/a if not os.path.isfile("python") or not os.path.isfile("setup.py"):
118n/a raise ValueError("Script must be run in Python build directory")
119n/a
120n/a def _download_openssl(self):
121n/a """Download OpenSSL source dist"""
122n/a src_dir = os.path.dirname(self.src_file)
123n/a if not os.path.isdir(src_dir):
124n/a os.makedirs(src_dir)
125n/a url = self.url_template.format(self.version)
126n/a log.info("Downloading OpenSSL from {}".format(url))
127n/a req = urlopen(url, cadefault=CADEFAULT)
128n/a # KISS, read all, write all
129n/a data = req.read()
130n/a log.info("Storing {}".format(self.src_file))
131n/a with open(self.src_file, "wb") as f:
132n/a f.write(data)
133n/a
134n/a def _unpack_openssl(self):
135n/a """Unpack tar.gz bundle"""
136n/a # cleanup
137n/a if os.path.isdir(self.build_dir):
138n/a shutil.rmtree(self.build_dir)
139n/a os.makedirs(self.build_dir)
140n/a
141n/a tf = tarfile.open(self.src_file)
142n/a base = "openssl-{}/".format(self.version)
143n/a # force extraction into build dir
144n/a members = tf.getmembers()
145n/a for member in members:
146n/a if not member.name.startswith(base):
147n/a raise ValueError(member.name)
148n/a member.name = member.name[len(base):]
149n/a log.info("Unpacking files to {}".format(self.build_dir))
150n/a tf.extractall(self.build_dir, members)
151n/a
152n/a def _build_openssl(self):
153n/a """Now build openssl"""
154n/a log.info("Running build in {}".format(self.install_dir))
155n/a cwd = self.build_dir
156n/a cmd = ["./config", "shared", "--prefix={}".format(self.install_dir)]
157n/a cmd.extend(self.openssl_compile_args)
158n/a self._subprocess_call(cmd, cwd=cwd)
159n/a self._subprocess_call(["make"], cwd=cwd)
160n/a
161n/a def _install_openssl(self, remove=True):
162n/a self._subprocess_call(["make", "install"], cwd=self.build_dir)
163n/a if remove:
164n/a shutil.rmtree(self.build_dir)
165n/a
166n/a def install_openssl(self):
167n/a if not self.has_openssl:
168n/a if not self.has_src:
169n/a self._download_openssl()
170n/a else:
171n/a log.debug("Already has src %s", self.src_file)
172n/a self._unpack_openssl()
173n/a self._build_openssl()
174n/a self._install_openssl()
175n/a else:
176n/a log.info("Already has installation {}".format(self.install_dir))
177n/a # validate installation
178n/a version = self.openssl_version
179n/a if self.version not in version:
180n/a raise ValueError(version)
181n/a
182n/a def touch_pymods(self):
183n/a # force a rebuild of all modules that use OpenSSL APIs
184n/a for fname in self.module_files:
185n/a os.utime(fname)
186n/a
187n/a def recompile_pymods(self):
188n/a log.info("Using OpenSSL build from {}".format(self.build_dir))
189n/a # overwrite header and library search paths
190n/a env = os.environ.copy()
191n/a env["CPPFLAGS"] = "-I{}".format(self.include_dir)
192n/a env["LDFLAGS"] = "-L{}".format(self.lib_dir)
193n/a # set rpath
194n/a env["LD_RUN_PATH"] = self.lib_dir
195n/a
196n/a log.info("Rebuilding Python modules")
197n/a self.touch_pymods()
198n/a cmd = ["./python", "setup.py", "build"]
199n/a self._subprocess_call(cmd, env=env)
200n/a
201n/a def check_pyssl(self):
202n/a version = self.pyssl_version
203n/a if self.version not in version:
204n/a raise ValueError(version)
205n/a
206n/a def run_pytests(self, *args):
207n/a cmd = ["./python", "-m", "test"]
208n/a cmd.extend(args)
209n/a self._subprocess_call(cmd, stdout=None)
210n/a
211n/a def run_python_tests(self, *args):
212n/a self.recompile_pymods()
213n/a self.check_pyssl()
214n/a self.run_pytests(*args)
215n/a
216n/a
217n/adef main(*args):
218n/a builders = []
219n/a for version in OPENSSL_VERSIONS:
220n/a if version in ("0.9.8i", "0.9.8l"):
221n/a openssl_compile_args = ("no-asm",)
222n/a else:
223n/a openssl_compile_args = ()
224n/a builder = BuildSSL(version, openssl_compile_args)
225n/a builder.install_openssl()
226n/a builders.append(builder)
227n/a
228n/a for builder in builders:
229n/a builder.run_python_tests(*args)
230n/a # final touch
231n/a builder.touch_pymods()
232n/a
233n/a
234n/aif __name__ == "__main__":
235n/a logging.basicConfig(level=logging.INFO,
236n/a format="*** %(levelname)s %(message)s")
237n/a args = sys.argv[1:]
238n/a if not args:
239n/a args = ["-unetwork", "-v"]
240n/a args.extend(FULL_TESTS)
241n/a main(*args)