"Fossies" - the Fresh Open Source Software Archive

Member "snapcraft-3.8/tests/unit/plugins/test_rust.py" (9 Sep 2019, 23446 Bytes) of package /linux/misc/snapcraft-3.8.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. See also the latest Fossies "Diffs" side-by-side code changes report for "test_rust.py": 3.7.2_vs_3.8.

    1 # -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*-
    2 #
    3 # Copyright (C) 2016-2017 Marius Gripsgard (mariogrip@ubuntu.com)
    4 # Copyright (C) 2016-2019 Canonical Ltd
    5 #
    6 # This program is free software: you can redistribute it and/or modify
    7 # it under the terms of the GNU General Public License version 3 as
    8 # published by the Free Software Foundation.
    9 #
   10 # This program is distributed in the hope that it will be useful,
   11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
   12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   13 # GNU General Public License for more details.
   14 #
   15 # You should have received a copy of the GNU General Public License
   16 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
   17 
   18 import collections
   19 import os
   20 import subprocess
   21 import textwrap
   22 
   23 from testtools.matchers import Contains, Equals, FileExists, Not
   24 from unittest import mock
   25 import toml
   26 
   27 import snapcraft
   28 from snapcraft.internal import errors
   29 from snapcraft.plugins import rust
   30 from tests import fixture_setup, unit
   31 
   32 
   33 class RustPluginBaseTest(unit.TestCase):
   34     def setUp(self):
   35         super().setUp()
   36 
   37         self.useFixture(fixture_setup.CleanEnvironment())
   38 
   39         class Options:
   40             makefile = None
   41             make_parameters = []
   42             rust_features = []
   43             rust_revision = ""
   44             rust_channel = ""
   45             source_subdir = ""
   46 
   47         self.options = Options()
   48 
   49         patcher = mock.patch("snapcraft.internal.common.run")
   50         self.run_mock = patcher.start()
   51         self.addCleanup(patcher.stop)
   52 
   53         patcher = mock.patch("snapcraft.internal.common.run_output")
   54         patcher.start()
   55         self.addCleanup(patcher.stop)
   56 
   57         original_exists = os.path.exists
   58 
   59         def exists_mock(*args, **kwargs):
   60             if args[0].endswith("rustup"):
   61                 return False
   62             else:
   63                 return original_exists(args[0])
   64 
   65         patcher = mock.patch("os.path.exists", side_effect=exists_mock)
   66         patcher.start()
   67         self.addCleanup(patcher.stop)
   68 
   69 
   70 class RustPluginPropertiesTest(unit.TestCase):
   71     def test_schema(self):
   72         schema = rust.RustPlugin.schema()
   73 
   74         properties = schema["properties"]
   75         self.assertTrue(
   76             "rust-channel" in properties,
   77             'Expected "rust-channel" to be included in properties',
   78         )
   79         self.assertTrue(
   80             "rust-revision" in properties,
   81             'Expected "rust-revision to be included in properties',
   82         )
   83 
   84         # rust-channel
   85         rust_channel = properties["rust-channel"]
   86         self.assertTrue(
   87             "type" in rust_channel, 'Expected "type" to be included in "rust-channel"'
   88         )
   89         rust_channel_type = rust_channel["type"]
   90         self.assertThat(
   91             rust_channel_type,
   92             Equals("string"),
   93             'Expected "rust-channel" "type" to be "string", '
   94             'but it was "{}"'.format(rust_channel_type),
   95         )
   96         self.assertTrue(
   97             "enum" in rust_channel, 'Expected "enum" to be included in "rust-channel"'
   98         )
   99         rust_channel_enum = rust_channel["enum"]
  100         self.assertThat(
  101             rust_channel_enum,
  102             Equals(["stable", "beta", "nightly"]),
  103             'Expected "rust-channel" "enum" to be "["stable", "beta", "nightly"]", '
  104             'but it was "{}"'.format(rust_channel_enum),
  105         )
  106 
  107         # rust-revision
  108         rust_revision = properties["rust-revision"]
  109         self.assertTrue(
  110             "type" in rust_revision, 'Expected "type" to be included in "rust-revision"'
  111         )
  112         rust_revision_type = rust_revision["type"]
  113         self.assertThat(
  114             rust_revision_type,
  115             Equals("string"),
  116             'Expected "rust-revision" "type" to be "string", '
  117             'but it was "{}"'.format(rust_revision_type),
  118         )
  119 
  120 
  121 class RustPluginCrossCompileTest(RustPluginBaseTest):
  122 
  123     scenarios = [
  124         ("armv7l", dict(deb_arch="armhf", target="armv7-unknown-linux-gnueabihf")),
  125         ("aarch64", dict(deb_arch="arm64", target="aarch64-unknown-linux-gnu")),
  126         ("i386", dict(deb_arch="i386", target="i686-unknown-linux-gnu")),
  127         ("x86_64", dict(deb_arch="amd64", target="x86_64-unknown-linux-gnu")),
  128         ("ppc64le", dict(deb_arch="ppc64el", target="powerpc64le-unknown-linux-gnu")),
  129         ("s390x", dict(deb_arch="s390x", target="s390x-unknown-linux-gnu")),
  130     ]
  131 
  132     def setUp(self):
  133         super().setUp()
  134 
  135         self.project = snapcraft.project.Project(
  136             target_deb_arch=self.deb_arch,
  137             snapcraft_yaml_file_path=self.make_snapcraft_yaml(
  138                 textwrap.dedent(
  139                     """\
  140                     name: test-snap
  141                     base: core16
  142                     """
  143                 )
  144             ),
  145         )
  146 
  147         patcher = mock.patch(
  148             "snapcraft.project.Project.is_cross_compiling", return_value=True
  149         )
  150         patcher.start()
  151         self.addCleanup(patcher.stop)
  152 
  153     @mock.patch("snapcraft.internal.sources._script.Script.download")
  154     def test_cross_compile(self, mock_download):
  155         plugin = rust.RustPlugin("test-part", self.options, self.project)
  156         os.makedirs(plugin.sourcedir)
  157 
  158         plugin.pull()
  159 
  160         self.assertThat(self.run_mock.call_count, Equals(4))
  161         self.run_mock.assert_has_calls(
  162             [
  163                 mock.call(
  164                     [
  165                         os.path.join(plugin._rust_dir, "rustup.sh"),
  166                         "-y",
  167                         "--no-modify-path",
  168                         "--default-toolchain",
  169                         "none",
  170                     ],
  171                     cwd=os.path.join(plugin.partdir, "build"),
  172                     env=plugin._build_env(),
  173                 ),
  174                 mock.call(
  175                     [plugin._rustup_cmd, "install", "stable"],
  176                     cwd=plugin.builddir,
  177                     env=plugin._build_env(),
  178                 ),
  179                 mock.call(
  180                     [
  181                         plugin._rustup_cmd,
  182                         "target",
  183                         "add",
  184                         "--toolchain",
  185                         "stable",
  186                         self.target,
  187                     ],
  188                     cwd=plugin.builddir,
  189                     env=plugin._build_env(),
  190                 ),
  191                 mock.call(
  192                     [
  193                         plugin._cargo_cmd,
  194                         "+stable",
  195                         "fetch",
  196                         "--manifest-path",
  197                         os.path.join(plugin.sourcedir, "Cargo.toml"),
  198                     ],
  199                     cwd=plugin.builddir,
  200                     env=plugin._build_env(),
  201                 ),
  202             ]
  203         )
  204 
  205         self.run_mock.reset_mock()
  206 
  207         plugin.build()
  208 
  209         self.assertThat(os.path.join(plugin.builddir, ".cargo", "config"), FileExists())
  210 
  211         self.assertThat(self.run_mock.call_count, Equals(1))
  212         self.run_mock.assert_has_calls(
  213             [
  214                 mock.call(
  215                     [
  216                         plugin._cargo_cmd,
  217                         "+stable",
  218                         "install",
  219                         "--path",
  220                         plugin.builddir,
  221                         "--root",
  222                         plugin.installdir,
  223                         "--force",
  224                         "--target",
  225                         self.target,
  226                     ],
  227                     cwd=os.path.join(plugin.partdir, "build"),
  228                     env=plugin._build_env(),
  229                 )
  230             ]
  231         )
  232 
  233     @mock.patch("snapcraft.internal.sources._script.Script.download")
  234     def test_cross_compile_with_rust_toolchain_file(self, mock_download):
  235         plugin = rust.RustPlugin("test-part", self.options, self.project)
  236         os.makedirs(plugin.sourcedir)
  237         open(os.path.join(plugin.sourcedir, "rust-toolchain"), "w").close()
  238 
  239         plugin.pull()
  240 
  241         self.assertThat(self.run_mock.call_count, Equals(3))
  242         self.run_mock.assert_has_calls(
  243             [
  244                 mock.call(
  245                     [
  246                         os.path.join(plugin._rust_dir, "rustup.sh"),
  247                         "-y",
  248                         "--no-modify-path",
  249                     ],
  250                     cwd=os.path.join(plugin.partdir, "build"),
  251                     env=plugin._build_env(),
  252                 ),
  253                 mock.call(
  254                     [plugin._rustup_cmd, "target", "add", self.target],
  255                     cwd=plugin.builddir,
  256                     env=plugin._build_env(),
  257                 ),
  258                 mock.call(
  259                     [
  260                         plugin._cargo_cmd,
  261                         "fetch",
  262                         "--manifest-path",
  263                         os.path.join(plugin.sourcedir, "Cargo.toml"),
  264                     ],
  265                     cwd=plugin.builddir,
  266                     env=plugin._build_env(),
  267                 ),
  268             ]
  269         )
  270 
  271         self.run_mock.reset_mock()
  272 
  273         plugin.build()
  274 
  275         self.assertThat(os.path.join(plugin.builddir, ".cargo", "config"), FileExists())
  276 
  277         self.assertThat(self.run_mock.call_count, Equals(1))
  278         self.run_mock.assert_has_calls(
  279             [
  280                 mock.call(
  281                     [
  282                         plugin._cargo_cmd,
  283                         "install",
  284                         "--path",
  285                         plugin.builddir,
  286                         "--root",
  287                         plugin.installdir,
  288                         "--force",
  289                         "--target",
  290                         self.target,
  291                     ],
  292                     cwd=os.path.join(plugin.partdir, "build"),
  293                     env=plugin._build_env(),
  294                 )
  295             ]
  296         )
  297 
  298 
  299 class RustPluginTest(RustPluginBaseTest):
  300     def setUp(self):
  301         super().setUp()
  302 
  303         self.project = snapcraft.project.Project(
  304             snapcraft_yaml_file_path=self.make_snapcraft_yaml(
  305                 textwrap.dedent(
  306                     """\
  307                     name: test-snap
  308                     base: core16
  309                     """
  310                 )
  311             )
  312         )
  313 
  314         if self.project.deb_arch == "s390x":
  315             self.skipTest("architecture is not supported by rust")
  316 
  317     @mock.patch.object(rust.sources, "Script")
  318     def test_pull(self, script_mock):
  319         plugin = rust.RustPlugin("test-part", self.options, self.project)
  320         os.makedirs(plugin.sourcedir)
  321         plugin.options.rust_revision = []
  322         plugin.options.rust_channel = []
  323 
  324         plugin.pull()
  325 
  326         self.assertThat(self.run_mock.call_count, Equals(3))
  327 
  328         self.run_mock.assert_has_calls(
  329             [
  330                 mock.call(
  331                     [
  332                         os.path.join(plugin._rust_dir, "rustup.sh"),
  333                         "-y",
  334                         "--no-modify-path",
  335                         "--default-toolchain",
  336                         "none",
  337                     ],
  338                     cwd=os.path.join(plugin.partdir, "build"),
  339                     env=plugin._build_env(),
  340                 ),
  341                 mock.call(
  342                     [plugin._rustup_cmd, "install", "stable"],
  343                     cwd=plugin.builddir,
  344                     env=plugin._build_env(),
  345                 ),
  346                 mock.call(
  347                     [
  348                         plugin._cargo_cmd,
  349                         "+stable",
  350                         "fetch",
  351                         "--manifest-path",
  352                         os.path.join(plugin.sourcedir, "Cargo.toml"),
  353                     ],
  354                     cwd=plugin.builddir,
  355                     env=plugin._build_env(),
  356                 ),
  357             ]
  358         )
  359 
  360     @mock.patch.object(rust.sources, "Script")
  361     def test_pull_with_rust_toolchain_file(self, script_mock):
  362         plugin = rust.RustPlugin("test-part", self.options, self.project)
  363         os.makedirs(plugin.sourcedir)
  364         open(os.path.join(plugin.sourcedir, "rust-toolchain"), "w").close()
  365 
  366         plugin.options.rust_revision = []
  367         plugin.options.rust_channel = []
  368 
  369         plugin.pull()
  370 
  371         self.assertThat(self.run_mock.call_count, Equals(2))
  372 
  373         self.run_mock.assert_has_calls(
  374             [
  375                 mock.call(
  376                     [
  377                         os.path.join(plugin._rust_dir, "rustup.sh"),
  378                         "-y",
  379                         "--no-modify-path",
  380                     ],
  381                     cwd=os.path.join(plugin.partdir, "build"),
  382                     env=plugin._build_env(),
  383                 ),
  384                 mock.call(
  385                     [
  386                         plugin._cargo_cmd,
  387                         "fetch",
  388                         "--manifest-path",
  389                         os.path.join(plugin.sourcedir, "Cargo.toml"),
  390                     ],
  391                     cwd=plugin.builddir,
  392                     env=plugin._build_env(),
  393                 ),
  394             ]
  395         )
  396 
  397     @mock.patch.object(rust.sources, "Script")
  398     def test_pull_with_channel(self, script_mock):
  399         plugin = rust.RustPlugin("test-part", self.options, self.project)
  400         os.makedirs(plugin.sourcedir)
  401         plugin.options.rust_revision = ""
  402         plugin.options.rust_channel = "nightly"
  403 
  404         plugin.pull()
  405 
  406         self.assertThat(self.run_mock.call_count, Equals(3))
  407 
  408         self.run_mock.assert_has_calls(
  409             [
  410                 mock.call(
  411                     [
  412                         os.path.join(plugin._rust_dir, "rustup.sh"),
  413                         "-y",
  414                         "--no-modify-path",
  415                         "--default-toolchain",
  416                         "none",
  417                     ],
  418                     cwd=os.path.join(plugin.partdir, "build"),
  419                     env=plugin._build_env(),
  420                 ),
  421                 mock.call(
  422                     [plugin._rustup_cmd, "install", "nightly"],
  423                     cwd=plugin.builddir,
  424                     env=plugin._build_env(),
  425                 ),
  426                 mock.call(
  427                     [
  428                         plugin._cargo_cmd,
  429                         "+nightly",
  430                         "fetch",
  431                         "--manifest-path",
  432                         os.path.join(plugin.sourcedir, "Cargo.toml"),
  433                     ],
  434                     cwd=plugin.builddir,
  435                     env=plugin._build_env(),
  436                 ),
  437             ]
  438         )
  439 
  440     @mock.patch.object(rust.sources, "Script")
  441     def test_pull_with_revision(self, script_mock):
  442         plugin = rust.RustPlugin("test-part", self.options, self.project)
  443         os.makedirs(plugin.sourcedir)
  444         plugin.options.rust_revision = "1.13.0"
  445         plugin.options.rust_channel = ""
  446 
  447         plugin.pull()
  448 
  449         self.assertThat(self.run_mock.call_count, Equals(3))
  450 
  451         self.run_mock.assert_has_calls(
  452             [
  453                 mock.call(
  454                     [
  455                         os.path.join(plugin._rust_dir, "rustup.sh"),
  456                         "-y",
  457                         "--no-modify-path",
  458                         "--default-toolchain",
  459                         "none",
  460                     ],
  461                     cwd=os.path.join(plugin.partdir, "build"),
  462                     env=plugin._build_env(),
  463                 ),
  464                 mock.call(
  465                     [plugin._rustup_cmd, "install", "1.13.0"],
  466                     cwd=plugin.builddir,
  467                     env=plugin._build_env(),
  468                 ),
  469                 mock.call(
  470                     [
  471                         plugin._cargo_cmd,
  472                         "+1.13.0",
  473                         "fetch",
  474                         "--manifest-path",
  475                         os.path.join(plugin.sourcedir, "Cargo.toml"),
  476                     ],
  477                     cwd=plugin.builddir,
  478                     env=plugin._build_env(),
  479                 ),
  480             ]
  481         )
  482 
  483     @mock.patch.object(rust.sources, "Script")
  484     def test_pull_with_source_and_source_subdir(self, script_mock):
  485         plugin = rust.RustPlugin("test-part", self.options, self.project)
  486         os.makedirs(plugin.sourcedir)
  487         plugin.options.source_subdir = "test-subdir"
  488 
  489         plugin.pull()
  490 
  491         self.assertThat(self.run_mock.call_count, Equals(3))
  492 
  493         self.run_mock.assert_has_calls(
  494             [
  495                 mock.call(
  496                     [
  497                         os.path.join(plugin._rust_dir, "rustup.sh"),
  498                         "-y",
  499                         "--no-modify-path",
  500                         "--default-toolchain",
  501                         "none",
  502                     ],
  503                     cwd=os.path.join(plugin.partdir, "build"),
  504                     env=plugin._build_env(),
  505                 ),
  506                 mock.call(
  507                     [plugin._rustup_cmd, "install", "stable"],
  508                     cwd=plugin.builddir,
  509                     env=plugin._build_env(),
  510                 ),
  511                 mock.call(
  512                     [
  513                         plugin._cargo_cmd,
  514                         "+stable",
  515                         "fetch",
  516                         "--manifest-path",
  517                         os.path.join(plugin.sourcedir, "test-subdir", "Cargo.toml"),
  518                     ],
  519                     cwd=plugin.builddir,
  520                     env=plugin._build_env(),
  521                 ),
  522             ]
  523         )
  524 
  525     @mock.patch("snapcraft.ProjectOptions.deb_arch", "fantasy-arch")
  526     def test_unsupported_target_arch_raises_exception(self):
  527         plugin = rust.RustPlugin("test-part", self.options, self.project)
  528         os.makedirs(plugin.sourcedir)
  529 
  530         self.assertRaises(errors.SnapcraftEnvironmentError, plugin._get_target)
  531 
  532     def test_build(self):
  533         plugin = rust.RustPlugin("test-part", self.options, self.project)
  534         os.makedirs(plugin.sourcedir)
  535 
  536         plugin.build()
  537 
  538         self.run_mock.assert_called_once_with(
  539             [
  540                 plugin._cargo_cmd,
  541                 "+stable",
  542                 "install",
  543                 "--path",
  544                 plugin.builddir,
  545                 "--root",
  546                 plugin.installdir,
  547                 "--force",
  548             ],
  549             cwd=os.path.join(plugin.partdir, "build"),
  550             env=plugin._build_env(),
  551         )
  552 
  553     def test_build_with_rust_toolchain_file(self):
  554         plugin = rust.RustPlugin("test-part", self.options, self.project)
  555         os.makedirs(plugin.sourcedir)
  556         open(os.path.join(plugin.sourcedir, "rust-toolchain"), "w").close()
  557 
  558         plugin.build()
  559 
  560         self.run_mock.assert_called_once_with(
  561             [
  562                 plugin._cargo_cmd,
  563                 "install",
  564                 "--path",
  565                 plugin.builddir,
  566                 "--root",
  567                 plugin.installdir,
  568                 "--force",
  569             ],
  570             cwd=os.path.join(plugin.partdir, "build"),
  571             env=plugin._build_env(),
  572         )
  573 
  574     def test_build_with_conditional_compilation(self):
  575         plugin = rust.RustPlugin("test-part", self.options, self.project)
  576         plugin.options.rust_features = ["conditional-compilation"]
  577         os.makedirs(plugin.sourcedir)
  578 
  579         plugin.build()
  580 
  581         self.run_mock.assert_called_once_with(
  582             [
  583                 plugin._cargo_cmd,
  584                 "+stable",
  585                 "install",
  586                 "--path",
  587                 plugin.builddir,
  588                 "--root",
  589                 plugin.installdir,
  590                 "--force",
  591                 "--features",
  592                 "conditional-compilation",
  593             ],
  594             cwd=os.path.join(plugin.partdir, "build"),
  595             env=plugin._build_env(),
  596         )
  597 
  598     def test_get_manifest_with_cargo_lock_file(self):
  599         plugin = rust.RustPlugin("test-part", self.options, self.project)
  600         os.makedirs(plugin.sourcedir)
  601         os.makedirs(plugin.builddir)
  602 
  603         with open(os.path.join(plugin.builddir, "Cargo.lock"), "w") as cargo_lock_file:
  604             cargo_lock_file.write("test cargo lock contents")
  605 
  606         plugin.build()
  607 
  608         self.assertThat(
  609             plugin.get_manifest()["cargo-lock-contents"],
  610             Equals("test cargo lock contents"),
  611         )
  612 
  613     def test_get_manifest_with_unexisting_cargo_lock(self):
  614         plugin = rust.RustPlugin("test-part", self.options, self.project)
  615         os.makedirs(plugin.sourcedir)
  616         os.makedirs(plugin.builddir)
  617 
  618         plugin.build()
  619 
  620         self.assertThat(plugin.get_manifest(), Not(Contains("cargo-lock-contents")))
  621 
  622     def test_get_manifest_with_cargo_lock_dir(self, *_):
  623         plugin = rust.RustPlugin("test-part", self.options, self.project)
  624         os.makedirs(plugin.sourcedir)
  625         os.makedirs(plugin.builddir)
  626 
  627         os.mkdir(os.path.join(plugin.builddir, "Cargo.lock"))
  628 
  629         plugin.build()
  630 
  631         self.assertThat(plugin.get_manifest(), Not(Contains("cargo-lock-contents")))
  632 
  633     def test_get_manifest_with_versions(self):
  634         plugin = rust.RustPlugin("test-part", self.options, self.project)
  635         os.makedirs(plugin.sourcedir)
  636 
  637         original_check_output = subprocess.check_output
  638 
  639         def side_effect(cmd, *args, **kwargs):
  640             if cmd[-1] == "--version":
  641                 binary = os.path.basename(cmd[0])
  642                 return "test {} version".format(binary)
  643             return original_check_output(cmd, *args, **kwargs)
  644 
  645         with mock.patch.object(rust.RustPlugin, "run_output") as run_output_mock:
  646             run_output_mock.side_effect = side_effect
  647             plugin.build()
  648 
  649         expected_manifest = collections.OrderedDict()
  650         expected_manifest["rustup-version"] = "test rustup version"
  651         expected_manifest["rustc-version"] = "test rustc version"
  652         expected_manifest["cargo-version"] = "test cargo version"
  653 
  654         self.assertThat(plugin.get_manifest(), Equals(expected_manifest))
  655 
  656     def test_write_cargo_config(self):
  657         plugin = rust.RustPlugin("test-part", self.options, self.project)
  658         config_toml_path = "config.toml"
  659 
  660         plugin._write_cargo_config(cargo_config_path=config_toml_path)
  661 
  662         self.assertThat(config_toml_path, FileExists())
  663 
  664         config = toml.load(config_toml_path)
  665 
  666         self.assertThat(
  667             config,
  668             Equals(
  669                 dict(
  670                     rustdoc_cmd=plugin._rustdoc_cmd,
  671                     rustc_cmd=plugin._rustc_cmd,
  672                     arch_triplet=plugin.project.arch_triplet,
  673                     jobs=plugin.parallel_build_count,
  674                     target={plugin._get_target(): dict(linker=plugin._get_linker())},
  675                 )
  676             ),
  677         )
  678 
  679     def test_unsupported_base(self):
  680         project = snapcraft.project.Project(
  681             snapcraft_yaml_file_path=self.make_snapcraft_yaml(
  682                 textwrap.dedent(
  683                     """\
  684                     name: test-snap
  685                     base: unsupported-base
  686                     """
  687                 )
  688             )
  689         )
  690 
  691         raised = self.assertRaises(
  692             errors.PluginBaseError, rust.RustPlugin, "test-part", self.options, project
  693         )
  694 
  695         self.assertThat(raised.part_name, Equals("test-part"))
  696         self.assertThat(raised.base, Equals("unsupported-base"))