aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/test/py
diff options
context:
space:
mode:
authorGravatar Googler <noreply@google.com>2018-04-11 07:06:28 -0700
committerGravatar Copybara-Service <copybara-piper@google.com>2018-04-11 07:07:41 -0700
commit6a5b0772c6e5fedc912949663de8b79503df5e78 (patch)
treeac99c34a085126310097552bbbb0fe08e60b793b /src/test/py
parentda32f42b75de137b1302632d1dbbb0b1e281ac53 (diff)
Add a test that builds a Windows binary remotely and runs it locally, to validate this key use case for remote Windows builds.
This is a working test case, but I plan to add more in this style to demonstrate fixes to address #4962. Note that to run this test requires a build of Bazel that includes https://github.com/bazelbuild/bazel/commit/b4545ba2b1aa4079b09a346a6d441ffa1e1b7d20 since this changed the way runfile manifests are discovered. Bazel 0.11 doesn't include this. RELNOTES: None. PiperOrigin-RevId: 192444770
Diffstat (limited to 'src/test/py')
-rw-r--r--src/test/py/bazel/BUILD19
-rw-r--r--src/test/py/bazel/test_base.py75
-rw-r--r--src/test/py/bazel/windows_remote_test.py88
3 files changed, 182 insertions, 0 deletions
diff --git a/src/test/py/bazel/BUILD b/src/test/py/bazel/BUILD
index fd79511fd7..c2b7f01a65 100644
--- a/src/test/py/bazel/BUILD
+++ b/src/test/py/bazel/BUILD
@@ -10,6 +10,7 @@ filegroup(
name = "test-deps",
testonly = 1,
srcs = ["//src:bazel_with_jdk"],
+ data = ["//src/tools/remote:worker"],
)
py_library(
@@ -85,6 +86,24 @@ py_test(
)
py_test(
+ name = "windows_remote_test",
+ size = "medium",
+ srcs = select({
+ "//src/conditions:windows": ["windows_remote_test.py"],
+ "//conditions:default": ["empty_test.py"],
+ }),
+ main = select({
+ "//src/conditions:windows": "windows_remote_test.py",
+ "//conditions:default": "empty_test.py",
+ }),
+ tags = ["manual"], # TODO(jsharpe): Reenable once Bazel 0.12 is used on CI.
+ deps = select({
+ "//src/conditions:windows": [":test_base"],
+ "//conditions:default": [],
+ }),
+)
+
+py_test(
name = "launcher_test",
size = "medium",
srcs = ["launcher_test.py"],
diff --git a/src/test/py/bazel/test_base.py b/src/test/py/bazel/test_base.py
index 27d1898ab7..345e3414ed 100644
--- a/src/test/py/bazel/test_base.py
+++ b/src/test/py/bazel/test_base.py
@@ -1,4 +1,5 @@
# pylint: disable=g-bad-file-header
+# pylint: disable=superfluous-parens
# Copyright 2017 The Bazel Authors. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,6 +16,7 @@
import locale
import os
+import socket
import stat
import subprocess
import tempfile
@@ -44,6 +46,9 @@ class TestBase(unittest.TestCase):
_temp = None
_tests_root = None
_test_cwd = None
+ _worker_stdout = None
+ _worker_stderr = None
+ _worker_proc = None
def setUp(self):
unittest.TestCase.setUp(self)
@@ -219,6 +224,73 @@ class TestBase(unittest.TestCase):
'--nomaster_bazelrc',
] + args, env_remove, env_add)
+ def StartRemoteWorker(self):
+ """Runs a "local remote worker" to run remote builds and tests on.
+
+ Returns:
+ int: port that the local remote worker runs on.
+ """
+ self._worker_stdout = tempfile.TemporaryFile(dir=self._test_cwd)
+ self._worker_stderr = tempfile.TemporaryFile(dir=self._test_cwd)
+ # Ideally we would use something under TEST_TMPDIR here, but the
+ # worker path must be as short as possible so we don't exceed Windows
+ # path length limits, so we run straight in TEMP. This should ideally
+ # be set to something like C:\temp. On CI this is set to D:\temp.
+ worker_path = TestBase.GetEnv('TEMP')
+
+ # Get an open port. Unfortunately this seems to be the best option in
+ # Python.
+ s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ s.bind(('', 0))
+ port = s.getsockname()[1]
+ s.close()
+
+ # Tip: To help debug remote build problems, add the --debug flag below.
+ self._worker_proc = subprocess.Popen(
+ [
+ self.Rlocation('io_bazel/src/tools/remote/worker.exe'),
+ '--listen_port=' + str(port),
+ # This path has to be extremely short to avoid Windows path
+ # length restrictions.
+ '--work_path=' + worker_path,
+ ],
+ stdout=self._worker_stdout,
+ stderr=self._worker_stderr,
+ cwd=self._test_cwd,
+ env=self._EnvMap(env_add={
+ 'RUNFILES_MANIFEST_FILE': TestBase.GetEnv('RUNFILES_MANIFEST_FILE'),
+ }))
+
+ return port
+
+ def StopRemoteWorker(self):
+ """Stop the "local remote worker" started by StartRemoteWorker.
+
+ Prints its stdout and stderr out for debug purposes.
+ """
+ self._worker_proc.terminate()
+ self._worker_proc.wait()
+
+ self._worker_stdout.seek(0)
+ stdout_lines = [
+ l.decode(locale.getpreferredencoding()).strip()
+ for l in self._worker_stdout.readlines()
+ ]
+ if stdout_lines:
+ print('Local remote worker stdout')
+ print('--------------------------')
+ print('\n'.join(stdout_lines))
+
+ self._worker_stderr.seek(0)
+ stderr_lines = [
+ l.decode(locale.getpreferredencoding()).strip()
+ for l in self._worker_stderr.readlines()
+ ]
+ if stderr_lines:
+ print('Local remote worker stderr')
+ print('--------------------------')
+ print('\n'.join(stderr_lines))
+
def RunProgram(self, args, env_remove=None, env_add=None):
"""Runs a program (args[0]), waits for it to exit.
@@ -263,6 +335,9 @@ class TestBase(unittest.TestCase):
TestBase.GetEnv('SYSTEMROOT'),
# TODO(laszlocsomor): Let Bazel pass BAZEL_SH to tests and use that
# here instead of hardcoding paths.
+ #
+ # You can override this with
+ # --action_env=BAZEL_SH=C:\path\to\my\bash.exe.
'BAZEL_SH':
TestBase.GetEnv('BAZEL_SH',
'c:\\tools\\msys64\\usr\\bin\\bash.exe'),
diff --git a/src/test/py/bazel/windows_remote_test.py b/src/test/py/bazel/windows_remote_test.py
new file mode 100644
index 0000000000..11b6d0d824
--- /dev/null
+++ b/src/test/py/bazel/windows_remote_test.py
@@ -0,0 +1,88 @@
+# pylint: disable=g-bad-file-header
+# pylint: disable=superfluous-parens
+# Copyright 2017 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 unittest
+from src.test.py.bazel import test_base
+
+
+class WindowsRemoteTest(test_base.TestBase):
+
+ def _RunRemoteBazel(self, args, port, env_remove=None, env_add=None):
+ return self.RunBazel(
+ args + [
+ '--spawn_strategy=remote',
+ '--strategy=Javac=remote',
+ '--strategy=Closure=remote',
+ '--genrule_strategy=remote',
+ '--define=EXECUTOR=remote',
+ '--remote_executor=localhost:' + str(port),
+ '--remote_cache=localhost:' + str(port),
+ '--experimental_strict_action_env=true',
+ '--remote_timeout=3600',
+ '--auth_enabled=false',
+ '--remote_accept_cached=false',
+ ],
+ env_remove=env_remove,
+ env_add=env_add)
+
+ # Check that a binary built remotely is runnable locally. Among other things,
+ # this means the runfiles manifest, which is not present remotely, must exist
+ # locally.
+ def testBinaryRunnableLocally(self):
+ self.ScratchFile('WORKSPACE')
+ self.ScratchFile('foo/BUILD', [
+ 'sh_binary(',
+ ' name = "foo",',
+ ' srcs = ["foo.sh"],',
+ ' data = ["//bar:bar.txt"],',
+ ')',
+ ])
+ self.ScratchFile(
+ 'foo/foo.sh', [
+ '#!/bin/bash',
+ 'echo hello shell',
+ ], executable=True)
+ self.ScratchFile('bar/BUILD', ['exports_files(["bar.txt"])'])
+ self.ScratchFile('bar/bar.txt', ['hello'])
+
+ exit_code, stdout, stderr = self.RunBazel(['info', 'bazel-bin'])
+ self.AssertExitCode(exit_code, 0, stderr)
+ bazel_bin = stdout[0]
+
+ port = self.StartRemoteWorker()
+
+ try:
+ # Build.
+ exit_code, stdout, stderr = self._RunRemoteBazel(['build', '//foo:foo'],
+ port)
+ print('\n'.join(stdout))
+ self.AssertExitCode(exit_code, 0, stderr)
+
+ # Run.
+ foo_bin = os.path.join(bazel_bin, 'foo', 'foo.exe')
+ self.assertTrue(os.path.exists(foo_bin))
+ exit_code, stdout, stderr = self.RunProgram([foo_bin])
+ self.AssertExitCode(exit_code, 0, stderr)
+ self.assertEqual(stdout, ['hello shell'])
+ finally:
+ # Always stop the worker so we obtain logs in case an assertion failed
+ # above.
+ self.StopRemoteWorker()
+
+
+if __name__ == '__main__':
+ unittest.main()