blob: 0268f30710891f5949865dcdb7aa3af09a2b4a32 [file] [log] [blame]
# pylint: disable=g-backslash-continuation
# Copyright 2021 The Bazel Authors. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import os
import tempfile
import unittest
from src.test.py.bazel import test_base
from src.test.py.bazel.bzlmod.test_utils import BazelRegistry
class BazelModuleTest(test_base.TestBase):
def setUp(self):
test_base.TestBase.setUp(self)
self.registries_work_dir = tempfile.mkdtemp(dir=self._test_cwd)
self.main_registry = BazelRegistry(
os.path.join(self.registries_work_dir, 'main'))
self.main_registry.createCcModule('A', '1.0') \
.createCcModule('A', '1.1') \
.createCcModule('B', '1.0', {'A': '1.0'}, {'A': 'com_foo_bar_a'}) \
.createCcModule('B', '1.1', {'A': '1.1'}) \
.createCcModule('C', '1.1', {'A': '1.1', 'B': '1.1'})
self.ScratchFile(
'.bazelrc',
[
# In ipv6 only network, this has to be enabled.
# 'startup --host_jvm_args=-Djava.net.preferIPv6Addresses=true',
'build --experimental_enable_bzlmod',
'build --registry=' + self.main_registry.getURL(),
'build --verbose_failures',
])
def writeMainProjectFiles(self):
self.ScratchFile('WORKSPACE')
self.ScratchFile('A.patch', [
'--- a/a.cc',
'+++ b/a.cc',
'@@ -1,6 +1,6 @@',
' #include <stdio.h>',
' #include "a.h"',
' void hello_a(const std::string& caller) {',
'- std::string lib_name = "A@1.0";',
'+ std::string lib_name = "A@1.0 (locally patched)";',
' printf("%s => %s\\n", caller.c_str(), lib_name.c_str());',
' }',
])
self.ScratchFile('BUILD', [
'cc_binary(',
' name = "main",',
' srcs = ["main.cc"],',
' deps = [',
' "@A//:lib_a",',
' "@B//:lib_b",',
' ],',
')',
])
self.ScratchFile('main.cc', [
'#include "a.h"',
'#include "b.h"',
'int main() {',
' hello_a("main function");',
' hello_b("main function");',
'}',
])
def testSimple(self):
self.ScratchFile('WORKSPACE')
self.ScratchFile('MODULE.bazel', [
'bazel_dep(name = "A", version = "1.0")',
])
self.ScratchFile('BUILD', [
'cc_binary(',
' name = "main",',
' srcs = ["main.cc"],',
' deps = ["@A//:lib_a"],',
')',
])
self.ScratchFile('main.cc', [
'#include "a.h"',
'int main() {',
' hello_a("main function");',
'}',
])
_, stdout, _ = self.RunBazel(['run', '//:main'], allow_failure=False)
self.assertIn('main function => A@1.0', stdout)
def testSimpleTransitive(self):
self.ScratchFile('WORKSPACE')
self.ScratchFile('MODULE.bazel', [
'bazel_dep(name = "B", version = "1.0")',
])
self.ScratchFile('BUILD', [
'cc_binary(',
' name = "main",',
' srcs = ["main.cc"],',
' deps = ["@B//:lib_b"],',
')',
])
self.ScratchFile('main.cc', [
'#include "b.h"',
'int main() {',
' hello_b("main function");',
'}',
])
_, stdout, _ = self.RunBazel(['run', '//:main'], allow_failure=False)
self.assertIn('main function => B@1.0', stdout)
self.assertIn('B@1.0 => A@1.0', stdout)
def testSimpleDiamond(self):
self.writeMainProjectFiles()
self.ScratchFile(
'MODULE.bazel',
[
'bazel_dep(name = "A", version = "1.1")',
# B1.0 has to depend on A1.1 after MVS.
'bazel_dep(name = "B", version = "1.0")',
])
_, stdout, _ = self.RunBazel(['run', '//:main'], allow_failure=False)
self.assertIn('main function => A@1.1', stdout)
self.assertIn('main function => B@1.0', stdout)
self.assertIn('B@1.0 => A@1.1', stdout)
def testSingleVersionOverrideWithPatch(self):
self.writeMainProjectFiles()
self.ScratchFile(
'MODULE.bazel',
[
'bazel_dep(name = "A", version = "1.1")',
'bazel_dep(name = "B", version = "1.1")',
# Both main and B1.1 has to depend on the locally patched A1.0.
'single_version_override(',
' module_name = "A",',
' version = "1.0",',
' patches = ["//:A.patch"],',
' patch_strip = 1,',
')',
])
_, stdout, _ = self.RunBazel(['run', '//:main'], allow_failure=False)
self.assertIn('main function => A@1.0 (locally patched)', stdout)
self.assertIn('main function => B@1.1', stdout)
self.assertIn('B@1.1 => A@1.0 (locally patched)', stdout)
def testRegistryOverride(self):
self.writeMainProjectFiles()
another_registry = BazelRegistry(
os.path.join(self.registries_work_dir, 'another'),
' from another registry')
another_registry.createCcModule('A', '1.0')
self.ScratchFile('MODULE.bazel', [
'bazel_dep(name = "A", version = "1.0")',
'bazel_dep(name = "B", version = "1.0")',
'single_version_override(',
' module_name = "A",',
' registry = "%s",' % another_registry.getURL(),
')',
])
_, stdout, _ = self.RunBazel(['run', '//:main'], allow_failure=False)
self.assertIn('main function => A@1.0 from another registry', stdout)
self.assertIn('main function => B@1.0', stdout)
self.assertIn('B@1.0 => A@1.0 from another registry', stdout)
def testArchiveOverride(self):
self.writeMainProjectFiles()
archive_a_1_0 = self.main_registry.archives.joinpath('A.1.0.zip')
self.ScratchFile('MODULE.bazel', [
'bazel_dep(name = "A", version = "1.1")',
'bazel_dep(name = "B", version = "1.1")',
'archive_override(',
' module_name = "A",',
' urls = ["%s"],' % archive_a_1_0.as_uri(),
' patches = ["//:A.patch"],',
' patch_strip = 1,',
')',
])
_, stdout, _ = self.RunBazel(['run', '//:main'], allow_failure=False)
self.assertIn('main function => A@1.0 (locally patched)', stdout)
self.assertIn('main function => B@1.1', stdout)
self.assertIn('B@1.1 => A@1.0 (locally patched)', stdout)
def testGitOverride(self):
self.writeMainProjectFiles()
src_a_1_0 = self.main_registry.projects.joinpath('A', '1.0')
self.RunProgram(['git', 'init'], cwd=src_a_1_0, allow_failure=False)
self.RunProgram(['git', 'config', 'user.name', 'tester'],
cwd=src_a_1_0,
allow_failure=False)
self.RunProgram(['git', 'config', 'user.email', 'tester@foo.com'],
cwd=src_a_1_0,
allow_failure=False)
self.RunProgram(['git', 'add', './'], cwd=src_a_1_0, allow_failure=False)
self.RunProgram(['git', 'commit', '-m', 'Initial commit.'],
cwd=src_a_1_0,
allow_failure=False)
_, stdout, _ = self.RunProgram(['git', 'rev-parse', 'HEAD'],
cwd=src_a_1_0,
allow_failure=False)
commit = stdout[0].strip()
self.ScratchFile('MODULE.bazel', [
'bazel_dep(name = "A", version = "1.1")',
'bazel_dep(name = "B", version = "1.1")',
'git_override(',
' module_name = "A",',
' remote = "%s",' % src_a_1_0.as_uri(),
' commit = "%s",' % commit,
' patches = ["//:A.patch"],',
' patch_strip = 1,',
')',
])
_, stdout, _ = self.RunBazel(['run', '//:main'], allow_failure=False)
self.assertIn('main function => A@1.0 (locally patched)', stdout)
self.assertIn('main function => B@1.1', stdout)
self.assertIn('B@1.1 => A@1.0 (locally patched)', stdout)
def testLocalPathOverride(self):
src_a_1_0 = self.main_registry.projects.joinpath('A', '1.0')
self.writeMainProjectFiles()
self.ScratchFile('MODULE.bazel', [
'bazel_dep(name = "A", version = "1.1")',
'bazel_dep(name = "B", version = "1.1")',
'local_path_override(',
' module_name = "A",',
' path = "%s",' % str(src_a_1_0.resolve()).replace('\\', '/'),
')',
])
_, stdout, _ = self.RunBazel(['run', '//:main'], allow_failure=False)
self.assertIn('main function => A@1.0', stdout)
self.assertIn('main function => B@1.1', stdout)
self.assertIn('B@1.1 => A@1.0', stdout)
def testRemotePatchForBazelDep(self):
patch_file = self.ScratchFile('A.patch', [
'--- a/a.cc',
'+++ b/a.cc',
'@@ -1,6 +1,6 @@',
' #include <stdio.h>',
' #include "a.h"',
' void hello_a(const std::string& caller) {',
'- std::string lib_name = "A@1.1-1";',
'+ std::string lib_name = "A@1.1-1 (remotely patched)";',
' printf("%s => %s\\n", caller.c_str(), lib_name.c_str());',
' }',
])
self.main_registry.createCcModule(
'A', '1.1-1', patches=[patch_file], patch_strip=1)
self.ScratchFile('WORKSPACE')
self.ScratchFile('MODULE.bazel', [
'bazel_dep(name = "A", version = "1.1-1")',
])
self.ScratchFile('BUILD', [
'cc_binary(',
' name = "main",',
' srcs = ["main.cc"],',
' deps = ["@A//:lib_a"],',
')',
])
self.ScratchFile('main.cc', [
'#include "a.h"',
'int main() {',
' hello_a("main function");',
'}',
])
_, stdout, _ = self.RunBazel(['run', '//:main'], allow_failure=False)
self.assertIn('main function => A@1.1-1 (remotely patched)', stdout)
def testRepoNameForBazelDep(self):
self.writeMainProjectFiles()
self.ScratchFile(
'MODULE.bazel',
[
'bazel_dep(name = "A", version = "1.0", repo_name = "my_repo_a_name")',
# B should still be able to access A as com_foo_bar_a
'bazel_dep(name = "B", version = "1.0")',
])
self.ScratchFile('BUILD', [
'cc_binary(',
' name = "main",',
' srcs = ["main.cc"],',
' deps = [',
' "@my_repo_a_name//:lib_a",',
' "@B//:lib_b",',
' ],',
')',
])
_, stdout, _ = self.RunBazel(['run', '//:main'], allow_failure=False)
self.assertIn('main function => A@1.0', stdout)
self.assertIn('main function => B@1.0', stdout)
self.assertIn('B@1.0 => A@1.0', stdout)
def testCheckDirectDependencies(self):
self.writeMainProjectFiles()
self.ScratchFile('MODULE.bazel', [
'bazel_dep(name = "A", version = "1.0")',
'bazel_dep(name = "B", version = "1.0")',
'bazel_dep(name = "C", version = "1.1")',
])
_, stdout, stderr = self.RunBazel(
['run', '//:main', '--check_direct_dependencies=warning'],
allow_failure=False)
self.assertIn(
'WARNING: For repository \'A\', the root module requires module version A@1.0, but got A@1.1 in the resolved dependency graph.',
stderr)
self.assertIn(
'WARNING: For repository \'B\', the root module requires module version B@1.0, but got B@1.1 in the resolved dependency graph.',
stderr)
self.assertIn('main function => A@1.1', stdout)
self.assertIn('main function => B@1.1', stdout)
self.assertIn('B@1.1 => A@1.1', stdout)
exit_code, _, stderr = self.RunBazel(
['run', '//:main', '--check_direct_dependencies=error'],
allow_failure=True)
self.AssertExitCode(exit_code, 48, stderr)
self.assertIn(
'ERROR: For repository \'A\', the root module requires module version A@1.0, but got A@1.1 in the resolved dependency graph.',
stderr)
self.assertIn(
'ERROR: For repository \'B\', the root module requires module version B@1.0, but got B@1.1 in the resolved dependency graph.',
stderr)
if __name__ == '__main__':
unittest.main()