blob: 9435e13101cc9828a8e567e2988dd164ee190ecd [file] [log] [blame]
#!/bin/bash
#
# Copyright 2016 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.
#
# These are end to end tests for building Java.
CURRENT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "${CURRENT_DIR}/../shell_utils.sh" \
|| { echo "shell_utils.sh not found!" >&2; exit 1; }
# Load the test setup defined in the parent directory
source "${CURRENT_DIR}/../integration_test_setup.sh" \
|| { echo "integration_test_setup.sh not found!" >&2; exit 1; }
set -eu
declare -r runfiles_relative_javabase="$1"
add_to_bazelrc "build --package_path=%workspace%"
#### HELPER FUNCTIONS ##################################################
function setup_local_jdk() {
local -r dest="$1"
local -r src="${BAZEL_RUNFILES}/${runfiles_relative_javabase}"
mkdir -p "$dest" || fail "mkdir -p $dest"
cp -LR "${src}"/* "$dest" || fail "cp -LR \"${src}\"/* \"$dest\""
chmod -R ug+rwX "$dest" || fail "chmod -R ug+rwX \"$dest\""
}
function write_hello_world_files() {
local pkg="$1"
mkdir -p $pkg/java/hello || fail "mkdir"
cat >$pkg/java/hello/BUILD <<EOF
java_binary(name = 'hello',
srcs = ['Hello.java'],
main_class = 'hello.Hello')
EOF
cat >$pkg/java/hello/Hello.java <<EOF
package hello;
public class Hello {
public static void main(String[] args) {
System.out.println("Hello, World!");
}
}
EOF
}
function write_hello_world_files_for_singlejar() {
local -r pkg="$1"
mkdir -p $pkg/java/hello || fail "mkdir"
cat >$pkg/java/hello/BUILD <<EOF
java_binary(name = 'hello',
srcs = ['Hello.java'],
main_class = 'hello.Hello')
EOF
cat >$pkg/java/hello/Hello.java <<EOF
package hello;
import java.util.Properties;
public class Hello {
private static void printMap(Properties p) {
System.err.println("Available keys and values are:");
for (Object key : p.keySet()) {
System.err.printf(" '%s': '%s'%n", key, p.get(key));
}
}
public static void main(String[] args) throws Exception {
Properties properties = new Properties();
properties.load(Hello.class.getResourceAsStream("/build-data.properties"));
for (String arg : args) {
String[] keyValue = arg.split("=", 2);
Object value = properties.get(keyValue[0]);
if (value == null) {
System.err.println("Key '" + keyValue[0] + "' not found");
printMap(properties);
return;
}
if (keyValue.length > 1 && !keyValue[1].equals(value)) {
System.err.println("Value for key '" + keyValue[0] + "' is '" + value
+ "' while it should be '" + keyValue[1] + "'");
printMap(properties);
return;
}
}
System.out.println("Hello, World!");
}
}
EOF
}
function write_hello_library_files() {
local -r pkg="$1"
mkdir -p $pkg/java/main || fail "mkdir"
cat >$pkg/java/main/BUILD <<EOF
java_binary(
name = 'main',
deps = ['//$pkg/java/hello_library'],
srcs = ['Main.java'],
main_class = 'main.Main',
deploy_manifest_lines = ['k1: v1', 'k2: v2'])
EOF
cat >$pkg/java/main/Main.java <<EOF
package main;
import hello_library.HelloLibrary;
public class Main {
public static void main(String[] args) {
HelloLibrary.funcHelloLibrary();
System.out.println("Hello, World!");
}
}
EOF
mkdir -p $pkg/java/hello_library || fail "mkdir"
cat >$pkg/java/hello_library/BUILD <<EOF
package(default_visibility=['//visibility:public'])
java_library(name = 'hello_library',
srcs = ['HelloLibrary.java']);
EOF
cat >$pkg/java/hello_library/HelloLibrary.java <<EOF
package hello_library;
public class HelloLibrary {
public static void funcHelloLibrary() {
System.out.print("Hello, Library!;");
}
}
EOF
}
function write_hello_sailor_files() {
local -r pkg="$1"
mkdir -p $pkg/java/hellosailor || fail "mkdir"
cat >$pkg/java/hellosailor/BUILD <<EOF
java_binary(name = 'hellosailor',
srcs = ['HelloSailor.java'],
create_executable = 0)
EOF
cat >$pkg/java/hellosailor/HelloSailor.java <<EOF
package hellosailor;
public class HelloSailor {
public static int addtwoNumbers(int a, int b) {
return a + b;
}
}
EOF
}
#### TESTS #############################################################
# This test intentionally show some errors on the standard output.
function test_compiles_hello_world() {
declare -a bazel_opts=("${@:+$@}")
local -r pkg="${FUNCNAME[0]}"
mkdir "$pkg" || fail "mkdir $pkg"
write_hello_world_files "$pkg"
bazel clean
bazel build ${bazel_opts[@]+"${bazel_opts[@]}"} //$pkg/java/hello:hello || fail "build failed"
${PRODUCT_NAME}-bin/$pkg/java/hello/hello | grep -q 'Hello, World!' \
|| fail "comparison failed"
function check_deploy_jar_should_not_exist() {
"$@" && fail "deploy jar should not exist"
true # reset the last exit code so the test won't be considered failed
}
function check_arglists() {
check_deploy_jar_should_not_exist "$@" --singlejar
check_deploy_jar_should_not_exist "$@" --wrapper_script_flag=--singlejar
check_deploy_jar_should_not_exist "$@" REGULAR_ARG \
--wrapper_script_flag=--singlejar
}
check_arglists bazel run //$pkg/java/hello:hello --
check_arglists ${PRODUCT_NAME}-bin/$pkg/java/hello/hello
}
function test_compiles_hello_world_remote_java_tools() {
test_compiles_hello_world \
--incompatible_use_remote_host_java_toolchain \
--incompatible_use_remote_java_toolchain
}
function test_compiles_hello_world_from_deploy_jar() {
declare -a bazel_opts=("${@:+$@}")
local -r pkg="${FUNCNAME[0]}"
mkdir "$pkg" || fail "mkdir $pkg"
write_hello_world_files "$pkg"
bazel build ${bazel_opts[@]+"${bazel_opts[@]}"} //$pkg/java/hello:hello_deploy.jar || fail "build failed"
bazel run ${bazel_opts[@]+"${bazel_opts[@]}"} //$pkg/java/hello:hello -- --singlejar | grep -q 'Hello, World!' \
|| fail "comparison failed"
${PRODUCT_NAME}-bin/$pkg/java/hello/hello -- --singlejar | \
grep -q 'Hello, World!' || fail "comparison failed"
bazel run ${bazel_opts[@]+"${bazel_opts[@]}"} //$pkg/java/hello:hello -- --wrapper_script_flag=--singlejar \
| grep -q 'Hello, World!' || fail "comparison failed"
${PRODUCT_NAME}-bin/$pkg/java/hello/hello -- \
--wrapper_script_flag=--singlejar | grep -q 'Hello, World!' \
|| fail "comparison failed"
bazel run ${bazel_opts[@]+"${bazel_opts[@]}"} //$pkg/java/hello:hello -- REGULAR_ARG \
--wrapper_script_flag=--singlejar | grep -q 'Hello, World!' \
|| fail "comparison failed"
${PRODUCT_NAME}-bin/$pkg/java/hello/hello -- REGULAR_ARG \
--wrapper_script_flag=--singlejar | grep -q 'Hello, World!' \
|| fail "comparison failed"
}
function test_compiles_hello_world_from_deploy_jar_remote_java_tools() {
test_compiles_hello_world_from_deploy_jar \
--incompatible_use_remote_host_java_toolchain \
--incompatible_use_remote_java_toolchain
}
function test_explicit_bogus_wrapper_args_are_rejected() {
declare -a bazel_opts=("${@:+$@}")
local -r pkg="${FUNCNAME[0]}"
mkdir "$pkg" || fail "mkdir $pkg"
write_hello_world_files "$pkg"
bazel build ${bazel_opts[@]+"${bazel_opts[@]}"} //$pkg/java/hello:hello_deploy.jar || fail "build failed"
function check_arg_rejected() {
"$@" && fail "bogus arg should be rejected"
true # reset the last exit code so the test won't be considered failed
}
function check_arglists() {
check_arg_rejected "$@" --wrapper_script_flag=--bogus
check_arg_rejected "$@" REGULAR_ARG --wrapper_script_flag=--bogus
}
check_arglists bazel run //$pkg/java/hello:hello --
check_arglists ${PRODUCT_NAME}-bin/$pkg/java/hello/hello
}
function test_explicit_bogus_wrapper_args_are_rejected_remote_java_tools() {
test_explicit_bogus_wrapper_args_are_rejected \
--incompatible_use_remote_host_java_toolchain \
--incompatible_use_remote_java_toolchain
}
function assert_singlejar_works() {
local -r pkg="$1"
local -r copy_jdk="$2"
local -r stamp_arg="$3"
local -r embed_label="$4"
local -r expected_build_data="$5"
write_hello_world_files_for_singlejar "$pkg"
if "$copy_jdk"; then
local -r local_jdk="$pkg/my_jdk"
setup_local_jdk "$local_jdk"
ln -s "my_jdk" "$pkg/my_jdk.symlink"
local -r javabase="$(get_real_path "$pkg/my_jdk.symlink")"
else
local -r javabase="${BAZEL_RUNFILES}/${runfiles_relative_javabase}"
fi
mkdir -p "$pkg/jvm"
cat > "$pkg/jvm/BUILD" <<EOF
package(default_visibility=["//visibility:public"])
java_runtime(name='runtime', java_home='$javabase')
EOF
# Set javabase to an absolute path.
bazel build //$pkg/java/hello:hello //$pkg/java/hello:hello_deploy.jar \
"$stamp_arg" --javabase="//$pkg/jvm:runtime" "$embed_label" >&"$TEST_log" \
|| fail "Build failed"
mkdir $pkg/ugly/ || fail "mkdir failed"
# The stub script follows symlinks, so copy the files.
cp ${PRODUCT_NAME}-bin/$pkg/java/hello/hello $pkg/ugly/
cp ${PRODUCT_NAME}-bin/$pkg/java/hello/hello_deploy.jar $pkg/ugly/
$pkg/ugly/hello build.target build.time build.timestamp \
main.class=hello.Hello "$expected_build_data" >> $TEST_log 2>&1
expect_log 'Hello, World!'
}
function test_singlejar_with_default_jdk_with_stamp() {
local -r pkg="${FUNCNAME[0]}"
assert_singlejar_works "$pkg" true "--stamp" "--embed_label=toto" \
"build.label=toto"
}
# Regression test for b/17658100, ensure that --nostamp generate correct
# build-info.properties file.
function test_singlejar_with_default_jdk_without_stamp() {
local -r pkg="${FUNCNAME[0]}"
assert_singlejar_works "$pkg" true "--nostamp" "--embed_label=" \
"build.timestamp.as.int=0"
}
# Regression test for b/3244955, to ensure that running the deploy jar works
# even without the runfiles available.
function test_singlejar_with_custom_jdk_with_stamp() {
local -r pkg="${FUNCNAME[0]}"
assert_singlejar_works "$pkg" false "--stamp" "--embed_label=toto" \
"build.label=toto"
}
function test_singlejar_with_custom_jdk_without_stamp() {
local -r pkg="${FUNCNAME[0]}"
assert_singlejar_works "$pkg" false "--nostamp" "--embed_label=" \
"build.timestamp.as.int=0"
}
# Regression test for b/18191163: ensure that the build is deterministic when
# used with --nostamp.
function test_deterministic_nostamp_build() {
declare -a bazel_opts=("${@:+$@}")
local -r pkg="${FUNCNAME[0]}"
mkdir "$pkg" || fail "mkdir $pkg"
write_hello_world_files "$pkg"
bazel clean || fail "Clean failed"
bazel build ${bazel_opts[@]+"${bazel_opts[@]}"} --nostamp //$pkg/java/hello:hello_deploy.jar \
|| fail "Build failed"
# TODO(bazel-team) .a files (C/C++ static library file generated by
# archive tool) on darwin OS only are not deterministic.
# https://github.com/bazelbuild/bazel/issues/3156
local -r first_run="$(md5_file $(find "${PRODUCT_NAME}-out/" -type f '!' \
-name build-changelist.txt -a '!' -name volatile-status.txt \
-a '!' -name 'stderr-*' -a '!' -name '*.a' \
-a '!' -name __xcodelocatorcache -a '!' -name __xcruncache \
| sort -u))"
sleep 1 # Ensure the timestamp change between builds.
bazel clean || fail "Clean failed"
bazel build --nostamp //$pkg/java/hello:hello_deploy.jar \
|| fail "Build failed"
local -r second_run="$(md5_file $(find "${PRODUCT_NAME}-out/" -type f '!' \
-name build-changelist.txt -a '!' -name volatile-status.txt \
-a '!' -name 'stderr-*' -a '!' -name '*.a' \
-a '!' -name __xcodelocatorcache -a '!' -name __xcruncache \
| sort -u))"
assert_equals "$first_run" "$second_run"
}
function test_deterministic_nostamp_build_remote_java_tools() {
test_deterministic_nostamp_build \
--incompatible_use_remote_host_java_toolchain \
--incompatible_use_remote_java_toolchain
}
function test_compiles_hello_library() {
declare -a bazel_opts=("${@:+$@}")
local -r pkg="${FUNCNAME[0]}"
mkdir "$pkg" || fail "mkdir $pkg"
write_hello_library_files "$pkg"
bazel clean
bazel build ${bazel_opts[@]+"${bazel_opts[@]}"} //$pkg/java/main:main || fail "build failed"
${PRODUCT_NAME}-bin/$pkg/java/main/main \
| grep -q "Hello, Library!;Hello, World!" || fail "comparison failed"
bazel run ${bazel_opts[@]+"${bazel_opts[@]}"} //$pkg/java/main:main -- --singlejar && fail "deploy jar should not exist"
true # reset the last exit code so the test won't be considered failed
}
function test_compiles_hello_library_remote_java_tools() {
test_compiles_hello_library \
--incompatible_use_remote_host_java_toolchain \
--incompatible_use_remote_java_toolchain
}
function test_compiles_hello_library_using_ijars() {
declare -a bazel_opts=("${@:+$@}")
local -r pkg="${FUNCNAME[0]}"
mkdir "$pkg" || fail "mkdir $pkg"
write_hello_library_files "$pkg"
bazel clean
bazel build ${bazel_opts[@]+"${bazel_opts[@]}"} --use_ijars //$pkg/java/main:main || fail "build failed"
${PRODUCT_NAME}-bin/$pkg/java/main/main \
| grep -q "Hello, Library!;Hello, World!" || fail "comparison failed"
}
function test_compiles_hello_library_using_ijars_remote_java_tools() {
test_compiles_hello_library_using_ijars \
--incompatible_use_remote_host_java_toolchain \
--incompatible_use_remote_java_toolchain
}
function test_compiles_hello_library_from_deploy_jar() {
declare -a bazel_opts=("${@:+$@}")
local -r pkg="${FUNCNAME[0]}"
mkdir "$pkg" || fail "mkdir $pkg"
write_hello_library_files "$pkg"
bazel build ${bazel_opts[@]+"${bazel_opts[@]}"} //$pkg/java/main:main_deploy.jar || fail "build failed"
${PRODUCT_NAME}-bin/$pkg/java/main/main --singlejar \
| grep -q "Hello, Library!;Hello, World!" || fail "comparison failed"
unzip -p ${PRODUCT_NAME}-bin/$pkg/java/main/main_deploy.jar META-INF/MANIFEST.MF \
| grep -q "k1: v1" || fail "missing manifest lines"
unzip -p ${PRODUCT_NAME}-bin/$pkg/java/main/main_deploy.jar META-INF/MANIFEST.MF \
| grep -q "k2: v2" || fail "missing manifest lines"
}
function test_compiles_hello_library_from_deploy_jar_remote_java_tools() {
test_compiles_hello_library_from_deploy_jar \
--incompatible_use_remote_host_java_toolchain \
--incompatible_use_remote_java_toolchain
}
function test_building_deploy_jar_twice_does_not_rebuild() {
declare -a bazel_opts=("${@:+$@}")
local -r pkg="${FUNCNAME[0]}"
mkdir "$pkg" || fail "mkdir $pkg"
write_hello_library_files "$pkg"
bazel build ${bazel_opts[@]+"${bazel_opts[@]}"} //$pkg/java/main:main_deploy.jar || fail "build failed"
touch -r ${PRODUCT_NAME}-bin/$pkg/java/main/main_deploy.jar old
bazel build ${bazel_opts[@]+"${bazel_opts[@]}"} //$pkg/java/main:main_deploy.jar || fail "build failed"
find ${PRODUCT_NAME}-bin/$pkg/java/main/main_deploy.jar -newer old \
| grep -q . && fail "file was rebuilt"
true # reset the last exit code so the test won't be considered failed
}
function test_building_deploy_jar_twice_does_not_rebuild_remote_java_tools() {
test_building_deploy_jar_twice_does_not_rebuild \
--incompatible_use_remote_host_java_toolchain \
--incompatible_use_remote_java_toolchain
}
function test_does_not_create_executable_when_not_asked_for() {
declare -a bazel_opts=("${@:+$@}")
local -r pkg="${FUNCNAME[0]}"
mkdir "$pkg" || fail "mkdir $pkg"
write_hello_sailor_files "$pkg"
bazel build ${bazel_opts[@]+"${bazel_opts[@]}"} //$pkg/java/hellosailor:hellosailor_deploy.jar \
|| fail "build failed"
if [[ ! -e ${PRODUCT_NAME}-bin/$pkg/java/hellosailor/hellosailor.jar ]]; then
fail "output jar does not exist";
fi
if [[ -e ${PRODUCT_NAME}-bin/$pkg/java/hellosailor/hellosailor ]]; then
fail "output executable should not exist";
fi
if [[ ! -e ${PRODUCT_NAME}-bin/$pkg/java/hellosailor/hellosailor_deploy.jar ]]; then
fail "output deploy jar does not exist";
fi
}
function test_does_not_create_executable_when_not_asked_for_remote_java_tools() {
test_does_not_create_executable_when_not_asked_for \
--incompatible_use_remote_host_java_toolchain \
--incompatible_use_remote_java_toolchain
}
# Assert that the a deploy jar can be a dependency of another java_binary.
function test_building_deploy_jar_dependent_on_deploy_jar() {
declare -a bazel_opts=("${@:+$@}")
local -r pkg="${FUNCNAME[0]}"
mkdir -p $pkg/java/deploy || fail "mkdir"
cat > $pkg/java/deploy/BUILD <<EOF
java_binary(name = 'Hello',
srcs = ['Hello.java'],
deps = ['Other_deploy.jar'],
main_class = 'hello.Hello')
java_binary(name = 'Other',
resources = ['//$pkg/hello:Test.txt'],
main_class = 'none')
EOF
cat >$pkg/java/deploy/Hello.java <<EOF
package deploy;
public class Hello {
public static void main(String[] args) {
System.out.println("Hello, World!");
}
}
EOF
mkdir -p $pkg/hello
echo "exports_files(['Test.txt'])" >$pkg/hello/BUILD
echo "Some other File" >$pkg/hello/Test.txt
bazel build ${bazel_opts[@]+"${bazel_opts[@]}"} //$pkg/java/deploy:Hello_deploy.jar || fail "build failed"
unzip -p ${PRODUCT_NAME}-bin/$pkg/java/deploy/Hello_deploy.jar \
$pkg/hello/Test.txt | grep -q "Some other File" || fail "missing resource"
}
function test_building_deploy_jar_dependent_on_deploy_jar_remote_java_tools() {
test_building_deploy_jar_dependent_on_deploy_jar \
--incompatible_use_remote_host_java_toolchain \
--incompatible_use_remote_java_toolchain
}
function test_wrapper_script_arg_handling() {
declare -a bazel_opts=("${@:+$@}")
local -r pkg="${FUNCNAME[0]}"
mkdir -p $pkg/java/hello/ || fail "Expected success"
cat > $pkg/java/hello/Test.java <<EOF
package hello;
public class Test {
public static void main(String[] args) {
System.out.print("Args:");
for (String arg : args) {
System.out.print(" '" + arg + "'");
}
System.out.println();
}
}
EOF
cat > $pkg/java/hello/BUILD <<EOF
java_binary(name='hello', srcs=['Test.java'], main_class='hello.Test')
EOF
bazel run ${bazel_opts[@]+"${bazel_opts[@]}"} //$pkg/java/hello:hello -- '' foo '' '' 'bar quux' '' \
>&$TEST_log || fail "Build failed"
expect_log "Args: '' 'foo' '' '' 'bar quux' ''"
}
function test_wrapper_script_arg_handling_remote_java_tools() {
test_wrapper_script_arg_handling \
--incompatible_use_remote_host_java_toolchain \
--incompatible_use_remote_java_toolchain
}
function test_srcjar_compilation() {
declare -a bazel_opts=("${@:+$@}")
local -r pkg="${FUNCNAME[0]}"
mkdir -p $pkg/java/hello/ || fail "Expected success"
cat > $pkg/java/hello/Test.java <<EOF
package hello;
public class Test {
public static void main(String[] args) {
System.out.println("Hello World!");
}
}
EOF
cd $pkg
zip -q java/hello/test.srcjar java/hello/Test.java || fail "zip failed"
cd ..
cat > $pkg/java/hello/BUILD <<EOF
java_binary(name='hello', srcs=['test.srcjar'], main_class='hello.Test')
EOF
bazel build ${bazel_opts[@]+"${bazel_opts[@]}"} //$pkg/java/hello:hello //$pkg/java/hello:hello_deploy.jar \
>&$TEST_log || fail "Expected success"
bazel run ${bazel_opts[@]+"${bazel_opts[@]}"} //$pkg/java/hello:hello -- --singlejar >&$TEST_log
expect_log "Hello World!"
}
function test_srcjar_compilation_remote_java_tools() {
test_srcjar_compilation \
--incompatible_use_remote_host_java_toolchain \
--incompatible_use_remote_java_toolchain
}
function test_private_initializers() {
local -r pkg="${FUNCNAME[0]}"
mkdir -p $pkg/java/hello/ || fail "Expected success"
cat > $pkg/java/hello/A.java <<EOF
package hello;
public class A { private B b; }
EOF
cat > $pkg/java/hello/B.java <<EOF
package hello;
public class B { private C c; }
EOF
cat > $pkg/java/hello/C.java <<EOF
package hello;
public class C {}
EOF
# This definition is only to make sure that A's interface is built.
cat > $pkg/java/hello/App.java <<EOF
package hello;
public class App { }
EOF
cat > $pkg/java/hello/BUILD <<EOF
java_library(name = 'app',
srcs = ['App.java'],
deps = [':a'])
java_library(name = 'a',
srcs = ['A.java'],
deps = [':b'])
java_library(name = 'b',
srcs = ['B.java'],
deps = [':c'])
java_library(name = 'c',
srcs = ['C.java'])
EOF
bazel build //$pkg/java/hello:app || fail "Expected success"
}
function test_java_plugin() {
declare -a bazel_opts=("${@:+$@}")
local -r pkg="${FUNCNAME[0]}"
mkdir -p $pkg/java/test/processor || fail "mkdir"
cat >$pkg/java/test/processor/BUILD <<EOF
package(default_visibility=['//visibility:public'])
java_library(name = 'annotation',
srcs = [ 'TestAnnotation.java' ])
java_library(name = 'processor_dep',
srcs = [ 'ProcessorDep.java' ])
java_plugin(name = 'processor',
processor_class = 'test.processor.Processor',
deps = [ ':annotation', ':processor_dep' ],
srcs = [ 'Processor.java' ])
EOF
cat >$pkg/java/test/processor/TestAnnotation.java <<EOF
package test.processor;
import java.lang.annotation.*;
@Target(value = {ElementType.TYPE})
public @interface TestAnnotation {
}
EOF
cat >$pkg/java/test/processor/ProcessorDep.java <<EOF
package test.processor;
class ProcessorDep {
static String value = "DependencyValue";
}
EOF
cat >$pkg/java/test/processor/Processor.java <<EOF
package test.processor;
import java.util.*;
import java.io.*;
import javax.annotation.processing.*;
import javax.tools.*;
import javax.lang.model.*;
import javax.lang.model.element.*;
@SupportedAnnotationTypes(value= {"test.processor.TestAnnotation"})
public class Processor extends AbstractProcessor {
private static final String OUTFILE_CONTENT = "package test;\n"
+ "public class Generated {\n"
+ " public static String value = \"" + ProcessorDep.value + "\";\n"
+ "}";
private ProcessingEnvironment mainEnvironment;
public void init(ProcessingEnvironment environment) {
mainEnvironment = environment;
}
public boolean process(Set<? extends TypeElement> annotations,
RoundEnvironment roundEnv) {
Filer filer = mainEnvironment.getFiler();
try {
FileObject output = filer.createSourceFile("test.Generated");
Writer writer = output.openWriter();
writer.append(OUTFILE_CONTENT);
writer.close();
} catch (IOException ex) {
return false;
}
return true;
}
}
EOF
mkdir -p $pkg/java/test/client
cat >$pkg/java/test/client/BUILD <<EOF
java_library(name = 'client',
srcs = [ 'ProcessorClient.java' ],
deps = [ '//$pkg/java/test/processor:annotation' ],
plugins = [ '//$pkg/java/test/processor:processor' ])
EOF
cat >$pkg/java/test/client/ProcessorClient.java <<EOF
package test.client;
import test.processor.TestAnnotation;
@TestAnnotation()
class ProcessorClient { }
EOF
bazel build ${bazel_opts[@]+"${bazel_opts[@]}"} //$pkg/java/test/client:client --use_ijars || fail "build failed"
unzip -l ${PRODUCT_NAME}-bin/$pkg/java/test/client/libclient.jar > $TEST_log
expect_log " test/Generated.class" "missing class file from annotation processing"
bazel build ${bazel_opts[@]+"${bazel_opts[@]}"} //$pkg/java/test/client:libclient-src.jar --use_ijars \
|| fail "build failed"
unzip -l ${PRODUCT_NAME}-bin/$pkg/java/test/client/libclient-src.jar > $TEST_log
expect_log " test/Generated.java" "missing source file from annotation processing"
}
function test_java_plugin_remote_java_tools() {
test_java_plugin \
--incompatible_use_remote_host_java_toolchain \
--incompatible_use_remote_java_toolchain
}
function test_jvm_flags_are_passed_verbatim() {
declare -a bazel_opts=("${@:+$@}")
local -r pkg="${FUNCNAME[0]}"
mkdir -p $pkg/java/com/google/jvmflags || fail "mkdir"
cat >$pkg/java/com/google/jvmflags/BUILD <<EOF
java_binary(
name = 'foo',
srcs = ['Foo.java'],
main_class = 'com.google.jvmflags.Foo',
toolchains = ['${TOOLS_REPOSITORY}//tools/jdk:current_java_runtime'],
jvm_flags = [
# test quoting
'--a=\\'single_single\\'',
'--b="single_double"',
"--c='double_single'",
"--d=\\"double_double\\"",
'--e=no_quotes',
# no escaping expected
'--f=stuff\$\$to"escape\\\\',
],
)
EOF
cat >$pkg/java/com/google/jvmflags/Foo.java <<EOF
package com.google.jvmflags;
public class Foo { public static void main(String[] args) {} }
EOF
bazel build ${bazel_opts[@]+"${bazel_opts[@]}"} //$pkg/java/com/google/jvmflags:foo || fail "build failed"
STUBSCRIPT=${PRODUCT_NAME}-bin/$pkg/java/com/google/jvmflags/foo
[ -e $STUBSCRIPT ] || fail "$STUBSCRIPT not found"
for flag in \
" --a='single_single' " \
" --b=\"single_double\" " \
" --c='double_single' " \
" --d=\"double_double\" " \
' --e=no_quotes ' \
' --f=stuff$to"escape\\ ' \
; do
# NOTE: don't test the full path of the JDK, it's architecture-dependent.
assert_contains $flag $STUBSCRIPT
done
}
function test_jvm_flags_are_passed_verbatim_remote_java_tools() {
test_jvm_flags_are_passed_verbatim \
--incompatible_use_remote_host_java_toolchain \
--incompatible_use_remote_java_toolchain
}
function test_classpath_fiddling() {
declare -a bazel_opts=("${@:+$@}")
local -r pkg="${FUNCNAME[0]}"
mkdir "$pkg" || fail "mkdir $pkg"
write_hello_library_files "$pkg"
mkdir -p $pkg/java/classpath
cat >$pkg/java/classpath/BUILD <<EOF
java_binary(name = 'classpath',
deps = ['//$pkg/java/hello_library'],
srcs = ['Classpath.java'],
main_class = 'classpath.Classpath')
EOF
cat >$pkg/java/classpath/Classpath.java <<'EOF'
package classpath;
public class Classpath {
public static void main(String[] args) {
String cp = System.getProperty("java.class.path");
String[] jars = cp.split(":"); // TODO(bazel-team): this is ";" on Windows
boolean singlejar
= (args.length > 1 && args[1].equals("SINGLEJAR"));
System.out.printf("CLASSPATH=%s%n", cp);
if (jars.length != 2 && !singlejar) {
throw new Error("Unexpected class path length");
}
String jarRegex = args[0];
for (String jar : jars) {
if (!jar.matches(jarRegex)) {
throw new Error("No match for regex: " + jarRegex);
}
if (!new java.io.File(jar).exists()) {
throw new Error("No such file: " + jar);
}
}
}
}
EOF
bazel clean
bazel build ${bazel_opts[@]+"${bazel_opts[@]}"} //$pkg/java/classpath || fail "build failed"
bazel run ${bazel_opts[@]+"${bazel_opts[@]}"} //$pkg/java/classpath -- \
"^$pkg/java/(classpath|hello_library)/.*\.jar\$" || fail "bazel run"
local PROG="${PRODUCT_NAME}-bin/$pkg/java/classpath/classpath"
function check_classpath_invocations() {
"$PROG" "^${PRODUCT_NAME}-bin/.*\.jar\$" "$@" \
|| fail "direct run relative classpath $*"
"./$PROG" "^\./${PRODUCT_NAME}-bin/.*\.jar\$" "$@" \
|| fail "direct run '.'-relative classpath $*"
"$PWD/$PROG" "^${PRODUCT_NAME}-bin/.*\.jar\$" "$@" \
|| fail "direct run absolute classpath $*"
(PROG="$PWD/$PROG"; cd / && exec "$PROG" '^/.*\.jar$' "$@") \
|| fail "direct run from / absolute classpath $*"
}
check_classpath_invocations
# Test --singlejar and --wrapper_script_flag
bazel build ${bazel_opts[@]+"${bazel_opts[@]}"} //$pkg/java/classpath:classpath_deploy.jar || fail "build failed"
for prog in "$PROG" "./$PROG" "$PWD/$PROG"; do
"$prog" --singlejar '.*_deploy.jar$' "SINGLEJAR" \
|| fail "$prog --singlejar"
"$prog" '.*_deploy.jar$' "SINGLEJAR" --wrapper_script_flag=--singlejar \
|| fail "$prog --wrapper_script_flag=--singlejar"
done
}
function test_classpath_fiddling_remote_java_tools() {
test_classpath_fiddling \
--incompatible_use_remote_host_java_toolchain \
--incompatible_use_remote_java_toolchain
}
function test_java7() {
declare -a bazel_opts=("${@:+$@}")
local -r pkg="${FUNCNAME[0]}"
mkdir -p $pkg/java/foo/ || fail "Expected success"
cat > $pkg/java/foo/Foo.java <<EOF
package foo;
import java.lang.invoke.MethodHandle; // In Java 7 class library only
import java.util.ArrayList;
public class Foo {
public static void main(String[] args) {
ArrayList<Object> list = new ArrayList<>(); // In Java 7 language only
System.out.println("Success!");
}
}
EOF
cat > $pkg/java/foo/BUILD <<EOF
java_binary(name = 'foo',
srcs = ['Foo.java'],
main_class = 'foo.Foo')
EOF
bazel run ${bazel_opts[@]+"${bazel_opts[@]}"} //$pkg/java/foo:foo | grep -q "Success!" || fail "Expected success"
}
function test_java7_remote_java_tools() {
test_java7 \
--incompatible_use_remote_host_java_toolchain \
--incompatible_use_remote_java_toolchain
}
function test_header_compilation() {
declare -a bazel_opts=("${@:+$@}")
local -r pkg="${FUNCNAME[0]}"
mkdir "$pkg" || fail "mkdir $pkg"
write_hello_library_files "$pkg"
bazel build ${bazel_opts[@]+"${bazel_opts[@]}"} -s --java_header_compilation=true \
//$pkg/java/main:main || fail "build failed"
unzip -l ${PRODUCT_NAME}-bin/$pkg/java/hello_library/libhello_library-hjar.jar \
> $TEST_log
expect_log " hello_library/HelloLibrary.class" \
"missing class file from header compilation"
}
function test_header_compilation_remote_java_tools() {
test_header_compilation \
--incompatible_use_remote_host_java_toolchain \
--incompatible_use_remote_java_toolchain
}
function test_header_compilation_errors() {
declare -a bazel_opts=("${@:+$@}")
local -r pkg="${FUNCNAME[0]}"
mkdir -p $pkg/java/test/ || fail "Expected success"
cat > $pkg/java/test/A.java <<EOF
package test;
public class A {}
EOF
cat > $pkg/java/test/B.java <<EOF
package test;
import missing.NoSuch;
@NoSuch
public class B {}
EOF
cat > $pkg/java/test/BUILD <<EOF
java_library(
name='a',
srcs=['A.java'],
deps=[':b'],
)
java_library(
name='b',
srcs=['B.java'],
)
EOF
bazel build ${bazel_opts[@]+"${bazel_opts[@]}"} --java_header_compilation=true \
//$pkg/java/test:liba.jar >& "$TEST_log" && fail "Unexpected success"
expect_log "symbol not found missing.NoSuch"
}
function test_header_compilation_errors_remote_java_tools() {
test_header_compilation_errors \
--incompatible_use_remote_host_java_toolchain \
--incompatible_use_remote_java_toolchain
}
function test_java_import_with_empty_jars_attribute() {
declare -a bazel_opts=("${@:+$@}")
local -r pkg="${FUNCNAME[0]}"
mkdir -p $pkg/java/hello/ || fail "Expected success"
cat > $pkg/java/hello/Hello.java <<EOF
package hello;
public class Hello {
public static void main(String[] args) {
System.out.println("Hello World!");
}
}
EOF
cat > $pkg/java/hello/BUILD <<EOF
java_import(
name='empty_java_import',
jars=[]
)
java_binary(
name='hello',
srcs=['Hello.java'],
deps=[':empty_java_import'],
main_class = 'hello.Hello'
)
EOF
bazel build ${bazel_opts[@]+"${bazel_opts[@]}"} //$pkg/java/hello:hello //$pkg/java/hello:hello_deploy.jar >& "$TEST_log" \
|| fail "Expected success"
bazel run ${bazel_opts[@]+"${bazel_opts[@]}"} //$pkg/java/hello:hello -- --singlejar >& "$TEST_log"
expect_log "Hello World!"
}
function test_java_import_with_empty_jars_attribute_remote_java_tools() {
test_java_import_with_empty_jars_attribute \
--incompatible_use_remote_host_java_toolchain \
--incompatible_use_remote_java_toolchain
}
run_suite "Java integration tests"