diff options
Diffstat (limited to 'python/mozbuild/mozbuild/test/test_base.py')
-rw-r--r-- | python/mozbuild/mozbuild/test/test_base.py | 446 |
1 files changed, 446 insertions, 0 deletions
diff --git a/python/mozbuild/mozbuild/test/test_base.py b/python/mozbuild/mozbuild/test/test_base.py new file mode 100644 index 0000000000..c75a71ef5d --- /dev/null +++ b/python/mozbuild/mozbuild/test/test_base.py @@ -0,0 +1,446 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import json +import os +import shutil +import sys +import tempfile +import unittest + +import mozpack.path as mozpath +from buildconfig import topobjdir, topsrcdir +from mach.logging import LoggingManager +from mozfile.mozfile import NamedTemporaryFile +from mozunit import main +from six import StringIO + +from mozbuild.backend.configenvironment import ConfigEnvironment +from mozbuild.base import ( + BadEnvironmentException, + MachCommandBase, + MozbuildObject, + PathArgument, +) +from mozbuild.test.common import prepare_tmp_topsrcdir + +curdir = os.path.dirname(__file__) +log_manager = LoggingManager() + + +class TestMozbuildObject(unittest.TestCase): + def setUp(self): + self._old_cwd = os.getcwd() + self._old_env = dict(os.environ) + os.environ.pop("MOZCONFIG", None) + os.environ.pop("MOZ_OBJDIR", None) + + def tearDown(self): + os.chdir(self._old_cwd) + os.environ.clear() + os.environ.update(self._old_env) + + def get_base(self, topobjdir=None): + return MozbuildObject(topsrcdir, None, log_manager, topobjdir=topobjdir) + + def test_objdir_config_guess(self): + base = self.get_base() + + with NamedTemporaryFile(mode="wt") as mozconfig: + os.environ["MOZCONFIG"] = mozconfig.name + + self.assertIsNotNone(base.topobjdir) + self.assertEqual(len(base.topobjdir.split()), 1) + config_guess = base.resolve_config_guess() + self.assertTrue(base.topobjdir.endswith(config_guess)) + self.assertTrue(os.path.isabs(base.topobjdir)) + self.assertTrue(base.topobjdir.startswith(base.topsrcdir)) + + def test_objdir_trailing_slash(self): + """Trailing slashes in topobjdir should be removed.""" + base = self.get_base() + + with NamedTemporaryFile(mode="wt") as mozconfig: + mozconfig.write("mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/foo/") + mozconfig.flush() + os.environ["MOZCONFIG"] = mozconfig.name + + self.assertEqual(base.topobjdir, mozpath.join(base.topsrcdir, "foo")) + self.assertTrue(base.topobjdir.endswith("foo")) + + def test_objdir_config_status(self): + """Ensure @CONFIG_GUESS@ is handled when loading mozconfig.""" + base = self.get_base() + guess = base.resolve_config_guess() + + # There may be symlinks involved, so we use real paths to ensure + # path consistency. + d = os.path.realpath(tempfile.mkdtemp()) + try: + mozconfig = os.path.join(d, "mozconfig") + with open(mozconfig, "wt") as fh: + fh.write("mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/foo/@CONFIG_GUESS@") + print("Wrote mozconfig %s" % mozconfig) + + topobjdir = os.path.join(d, "foo", guess) + os.makedirs(topobjdir) + + # Create a fake topsrcdir. + prepare_tmp_topsrcdir(d) + + mozinfo = os.path.join(topobjdir, "mozinfo.json") + with open(mozinfo, "wt") as fh: + json.dump( + dict( + topsrcdir=d, + mozconfig=mozconfig, + ), + fh, + ) + + os.environ["MOZCONFIG"] = mozconfig + os.chdir(topobjdir) + + obj = MozbuildObject.from_environment(detect_virtualenv_mozinfo=False) + + self.assertEqual(obj.topobjdir, mozpath.normsep(topobjdir)) + finally: + os.chdir(self._old_cwd) + shutil.rmtree(d) + + def test_relative_objdir(self): + """Relative defined objdirs are loaded properly.""" + d = os.path.realpath(tempfile.mkdtemp()) + try: + mozconfig = os.path.join(d, "mozconfig") + with open(mozconfig, "wt") as fh: + fh.write("mk_add_options MOZ_OBJDIR=./objdir") + + topobjdir = mozpath.join(d, "objdir") + os.mkdir(topobjdir) + + mozinfo = os.path.join(topobjdir, "mozinfo.json") + with open(mozinfo, "wt") as fh: + json.dump( + dict( + topsrcdir=d, + mozconfig=mozconfig, + ), + fh, + ) + + os.environ["MOZCONFIG"] = mozconfig + child = os.path.join(topobjdir, "foo", "bar") + os.makedirs(child) + os.chdir(child) + + obj = MozbuildObject.from_environment(detect_virtualenv_mozinfo=False) + + self.assertEqual(obj.topobjdir, topobjdir) + + finally: + os.chdir(self._old_cwd) + shutil.rmtree(d) + + @unittest.skipIf( + not hasattr(os, "symlink") or os.name == "nt", "symlinks not available." + ) + def test_symlink_objdir(self): + """Objdir that is a symlink is loaded properly.""" + d = os.path.realpath(tempfile.mkdtemp()) + try: + topobjdir_real = os.path.join(d, "objdir") + topobjdir_link = os.path.join(d, "objlink") + + os.mkdir(topobjdir_real) + os.symlink(topobjdir_real, topobjdir_link) + + mozconfig = os.path.join(d, "mozconfig") + with open(mozconfig, "wt") as fh: + fh.write("mk_add_options MOZ_OBJDIR=%s" % topobjdir_link) + + mozinfo = os.path.join(topobjdir_real, "mozinfo.json") + with open(mozinfo, "wt") as fh: + json.dump( + dict( + topsrcdir=d, + mozconfig=mozconfig, + ), + fh, + ) + + os.chdir(topobjdir_link) + obj = MozbuildObject.from_environment(detect_virtualenv_mozinfo=False) + self.assertEqual(obj.topobjdir, topobjdir_real) + + os.chdir(topobjdir_real) + obj = MozbuildObject.from_environment(detect_virtualenv_mozinfo=False) + self.assertEqual(obj.topobjdir, topobjdir_real) + + finally: + os.chdir(self._old_cwd) + shutil.rmtree(d) + + def test_mach_command_base_inside_objdir(self): + """Ensure a MachCommandBase constructed from inside the objdir works.""" + + d = os.path.realpath(tempfile.mkdtemp()) + + try: + topobjdir = os.path.join(d, "objdir") + os.makedirs(topobjdir) + + topsrcdir = os.path.join(d, "srcdir") + prepare_tmp_topsrcdir(topsrcdir) + + mozinfo = os.path.join(topobjdir, "mozinfo.json") + with open(mozinfo, "wt") as fh: + json.dump( + dict( + topsrcdir=topsrcdir, + ), + fh, + ) + + os.chdir(topobjdir) + + class MockMachContext(object): + pass + + context = MockMachContext() + context.cwd = topobjdir + context.topdir = topsrcdir + context.settings = None + context.log_manager = None + context.detect_virtualenv_mozinfo = False + + o = MachCommandBase(context, None) + + self.assertEqual(o.topobjdir, mozpath.normsep(topobjdir)) + self.assertEqual(o.topsrcdir, mozpath.normsep(topsrcdir)) + + finally: + os.chdir(self._old_cwd) + shutil.rmtree(d) + + def test_objdir_is_srcdir_rejected(self): + """Ensure the srcdir configurations are rejected.""" + d = os.path.realpath(tempfile.mkdtemp()) + + try: + # The easiest way to do this is to create a mozinfo.json with data + # that will never happen. + mozinfo = os.path.join(d, "mozinfo.json") + with open(mozinfo, "wt") as fh: + json.dump({"topsrcdir": d}, fh) + + os.chdir(d) + + with self.assertRaises(BadEnvironmentException): + MozbuildObject.from_environment(detect_virtualenv_mozinfo=False) + + finally: + os.chdir(self._old_cwd) + shutil.rmtree(d) + + def test_objdir_mismatch(self): + """Ensure MachCommandBase throwing on objdir mismatch.""" + d = os.path.realpath(tempfile.mkdtemp()) + + try: + real_topobjdir = os.path.join(d, "real-objdir") + os.makedirs(real_topobjdir) + + topobjdir = os.path.join(d, "objdir") + os.makedirs(topobjdir) + + topsrcdir = os.path.join(d, "srcdir") + prepare_tmp_topsrcdir(topsrcdir) + + mozconfig = os.path.join(d, "mozconfig") + with open(mozconfig, "wt") as fh: + fh.write( + "mk_add_options MOZ_OBJDIR=%s" % real_topobjdir.replace("\\", "/") + ) + + mozinfo = os.path.join(topobjdir, "mozinfo.json") + with open(mozinfo, "wt") as fh: + json.dump( + dict( + topsrcdir=topsrcdir, + mozconfig=mozconfig, + ), + fh, + ) + + os.chdir(topobjdir) + + class MockMachContext(object): + pass + + context = MockMachContext() + context.cwd = topobjdir + context.topdir = topsrcdir + context.settings = None + context.log_manager = None + context.detect_virtualenv_mozinfo = False + + stdout = sys.stdout + sys.stdout = StringIO() + try: + with self.assertRaises(SystemExit): + MachCommandBase(context, None) + + self.assertTrue( + sys.stdout.getvalue().startswith( + "Ambiguous object directory detected." + ) + ) + finally: + sys.stdout = stdout + + finally: + os.chdir(self._old_cwd) + shutil.rmtree(d) + + def test_config_environment(self): + d = os.path.realpath(tempfile.mkdtemp()) + + try: + with open(os.path.join(d, "config.status"), "w") as fh: + fh.write("# coding=utf-8\n") + fh.write("from __future__ import unicode_literals\n") + fh.write("topobjdir = '%s'\n" % mozpath.normsep(d)) + fh.write("topsrcdir = '%s'\n" % topsrcdir) + fh.write("mozconfig = None\n") + fh.write("defines = { 'FOO': 'foo' }\n") + fh.write("substs = { 'QUX': 'qux' }\n") + fh.write( + "__all__ = ['topobjdir', 'topsrcdir', 'defines', " + "'substs', 'mozconfig']" + ) + + base = self.get_base(topobjdir=d) + + ce = base.config_environment + self.assertIsInstance(ce, ConfigEnvironment) + + self.assertEqual(base.defines, ce.defines) + self.assertEqual(base.substs, ce.substs) + + self.assertEqual(base.defines, {"FOO": "foo"}) + self.assertEqual( + base.substs, + { + "ACDEFINES": "-DFOO=foo", + "ALLEMPTYSUBSTS": "", + "ALLSUBSTS": "ACDEFINES = -DFOO=foo\nQUX = qux", + "QUX": "qux", + }, + ) + finally: + shutil.rmtree(d) + + def test_get_binary_path(self): + base = self.get_base(topobjdir=topobjdir) + + platform = sys.platform + + # We should ideally use the config.status from the build. Let's install + # a fake one. + substs = [ + ("MOZ_APP_NAME", "awesomeapp"), + ("MOZ_BUILD_APP", "awesomeapp"), + ] + if sys.platform.startswith("darwin"): + substs.append(("OS_ARCH", "Darwin")) + substs.append(("BIN_SUFFIX", "")) + substs.append(("MOZ_MACBUNDLE_NAME", "Nightly.app")) + elif sys.platform.startswith(("win32", "cygwin")): + substs.append(("OS_ARCH", "WINNT")) + substs.append(("BIN_SUFFIX", ".exe")) + else: + substs.append(("OS_ARCH", "something")) + substs.append(("BIN_SUFFIX", "")) + + base._config_environment = ConfigEnvironment( + base.topsrcdir, base.topobjdir, substs=substs + ) + + p = base.get_binary_path("xpcshell", False) + if platform.startswith("darwin"): + self.assertTrue(p.endswith("Contents/MacOS/xpcshell")) + elif platform.startswith(("win32", "cygwin")): + self.assertTrue(p.endswith("xpcshell.exe")) + else: + self.assertTrue(p.endswith("dist/bin/xpcshell")) + + p = base.get_binary_path(validate_exists=False) + if platform.startswith("darwin"): + self.assertTrue(p.endswith("Contents/MacOS/awesomeapp")) + elif platform.startswith(("win32", "cygwin")): + self.assertTrue(p.endswith("awesomeapp.exe")) + else: + self.assertTrue(p.endswith("dist/bin/awesomeapp")) + + p = base.get_binary_path(validate_exists=False, where="staged-package") + if platform.startswith("darwin"): + self.assertTrue( + p.endswith("awesomeapp/Nightly.app/Contents/MacOS/awesomeapp") + ) + elif platform.startswith(("win32", "cygwin")): + self.assertTrue(p.endswith("awesomeapp\\awesomeapp.exe")) + else: + self.assertTrue(p.endswith("awesomeapp/awesomeapp")) + + self.assertRaises(Exception, base.get_binary_path, where="somewhere") + + p = base.get_binary_path("foobar", validate_exists=False) + if platform.startswith("win32"): + self.assertTrue(p.endswith("foobar.exe")) + else: + self.assertTrue(p.endswith("foobar")) + + +class TestPathArgument(unittest.TestCase): + def test_path_argument(self): + # Absolute path + p = PathArgument("/obj/foo", "/src", "/obj", "/src") + self.assertEqual(p.relpath(), "foo") + self.assertEqual(p.srcdir_path(), "/src/foo") + self.assertEqual(p.objdir_path(), "/obj/foo") + + # Relative path within srcdir + p = PathArgument("foo", "/src", "/obj", "/src") + self.assertEqual(p.relpath(), "foo") + self.assertEqual(p.srcdir_path(), "/src/foo") + self.assertEqual(p.objdir_path(), "/obj/foo") + + # Relative path within subdirectory + p = PathArgument("bar", "/src", "/obj", "/src/foo") + self.assertEqual(p.relpath(), "foo/bar") + self.assertEqual(p.srcdir_path(), "/src/foo/bar") + self.assertEqual(p.objdir_path(), "/obj/foo/bar") + + # Relative path within objdir + p = PathArgument("foo", "/src", "/obj", "/obj") + self.assertEqual(p.relpath(), "foo") + self.assertEqual(p.srcdir_path(), "/src/foo") + self.assertEqual(p.objdir_path(), "/obj/foo") + + # "." path + p = PathArgument(".", "/src", "/obj", "/src/foo") + self.assertEqual(p.relpath(), "foo") + self.assertEqual(p.srcdir_path(), "/src/foo") + self.assertEqual(p.objdir_path(), "/obj/foo") + + # Nested src/obj directories + p = PathArgument("bar", "/src", "/src/obj", "/src/obj/foo") + self.assertEqual(p.relpath(), "foo/bar") + self.assertEqual(p.srcdir_path(), "/src/foo/bar") + self.assertEqual(p.objdir_path(), "/src/obj/foo/bar") + + +if __name__ == "__main__": + main() |