diff options
author | Laszlo Csomor <laszlocsomor@google.com> | 2016-09-19 12:59:16 +0000 |
---|---|---|
committer | Laszlo Csomor <laszlocsomor@google.com> | 2016-09-19 13:03:35 +0000 |
commit | 68c8656e9f068072faa5b6819bd9a304626a1cc8 (patch) | |
tree | 5984ed99788e55e192a8d1254763a0bb0b74eb8e /src/test | |
parent | e1949e5b803d9479907128b3438d8a8c5cf9d858 (diff) |
Open-source java_integration_test
--
MOS_MIGRATED_REVID=133576201
Diffstat (limited to 'src/test')
-rw-r--r-- | src/test/shell/BUILD | 1 | ||||
-rw-r--r-- | src/test/shell/integration/BUILD | 12 | ||||
-rwxr-xr-x | src/test/shell/integration/java_integration_test.sh | 884 |
3 files changed, 897 insertions, 0 deletions
diff --git a/src/test/shell/BUILD b/src/test/shell/BUILD index 6ab4cb8e33..9db5e5bb6e 100644 --- a/src/test/shell/BUILD +++ b/src/test/shell/BUILD @@ -28,6 +28,7 @@ sh_test( sh_library( name = "shell_utils", srcs = ["shell_utils.sh"], + visibility = ["//src/test/shell/integration:__pkg__"], ) sh_test( diff --git a/src/test/shell/integration/BUILD b/src/test/shell/integration/BUILD index c85c8b9574..57fd25d5cb 100644 --- a/src/test/shell/integration/BUILD +++ b/src/test/shell/integration/BUILD @@ -48,6 +48,18 @@ sh_test( ) sh_test( + name = "java_integration_test", + size = "medium", + srcs = ["java_integration_test.sh"], + args = ["$(JAVABASE)"], + data = [ + ":test-deps", + "//src/test/shell:shell_utils", + ], + shard_count = 5, +) + +sh_test( name = "startup_options_test", size = "medium", srcs = ["startup_options_test.sh"], diff --git a/src/test/shell/integration/java_integration_test.sh b/src/test/shell/integration/java_integration_test.sh new file mode 100755 index 0000000000..5050eb4626 --- /dev/null +++ b/src/test/shell/integration/java_integration_test.sh @@ -0,0 +1,884 @@ +#!/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. + +# Load test environment +source $(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/testenv.sh \ + || { echo "testenv.sh not found!" >&2; exit 1; } + +source $(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)/shell_utils.sh \ + || { echo "shell_utils.sh not found!" >&2; exit 1; } + +set -eu + +declare -r runfiles_relative_javabase="$1" + +create_and_cd_client +put_bazel_on_path + +write_default_bazelrc +add_to_bazelrc "build --package_path=%workspace% --embed_changelist=none" + +#### 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() { + local -r pkg="${FUNCNAME[0]}" + mkdir "$pkg" || fail "mkdir $pkg" + write_hello_world_files "$pkg" + + bazel clean + bazel build //$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_from_deploy_jar() { + local -r pkg="${FUNCNAME[0]}" + mkdir "$pkg" || fail "mkdir $pkg" + write_hello_world_files "$pkg" + + bazel build //$pkg/java/hello:hello_deploy.jar || fail "build failed" + function check_deploy_jar_works() { + "$@" | grep -q 'Hello, World!' || fail "comparison failed" + } + function check_arglists() { + check_deploy_jar_works "$@" --singlejar + check_deploy_jar_works "$@" --wrapper_script_flag=--singlejar + check_deploy_jar_works "$@" 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_explicit_bogus_wrapper_args_are_rejected() { + local -r pkg="${FUNCNAME[0]}" + mkdir "$pkg" || fail "mkdir $pkg" + write_hello_world_files "$pkg" + + bazel build //$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 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 + + # Set javabase to an absolute path. + bazel build //$pkg/java/hello:hello //$pkg/java/hello:hello_deploy.jar \ + "$stamp_arg" --javabase="$javabase" "$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" 2>&1 >>$TEST_log + 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() { + local -r pkg="${FUNCNAME[0]}" + mkdir "$pkg" || fail "mkdir $pkg" + write_hello_world_files "$pkg" + + bazel clean || fail "Clean failed" + bazel build --nostamp //$pkg/java/hello:hello_deploy.jar \ + || fail "Build failed" + local -r first_run="$(md5_file $(find "${PRODUCT_NAME}-out/" -type f '!' \ + -name build-changelist.txt -a '!' -name volatile-status.txt | 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 | sort -u))" + + assert_equals "$first_run" "$second_run" +} + +function test_compiles_hello_library() { + local -r pkg="${FUNCNAME[0]}" + mkdir "$pkg" || fail "mkdir $pkg" + write_hello_library_files "$pkg" + + bazel clean + bazel build //$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 //$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_using_ijars() { + local -r pkg="${FUNCNAME[0]}" + mkdir "$pkg" || fail "mkdir $pkg" + write_hello_library_files "$pkg" + + bazel clean + bazel build --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_from_deploy_jar() { + local -r pkg="${FUNCNAME[0]}" + mkdir "$pkg" || fail "mkdir $pkg" + write_hello_library_files "$pkg" + + bazel build //$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_building_deploy_jar_twice_does_not_rebuild() { + local -r pkg="${FUNCNAME[0]}" + mkdir "$pkg" || fail "mkdir $pkg" + write_hello_library_files "$pkg" + + bazel build //$pkg/java/main:main_deploy.jar || fail "build failed" + touch old -r ${PRODUCT_NAME}-bin/$pkg/java/main/main_deploy.jar + bazel build //$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_does_not_create_executable_when_not_asked_for() { + local -r pkg="${FUNCNAME[0]}" + mkdir "$pkg" || fail "mkdir $pkg" + write_hello_sailor_files "$pkg" + + bazel build //$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 + +} + +# Assert that the a deploy jar can be a dependency of another java_binary. +function test_building_deploy_jar_dependent_on_deploy_jar() { + 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 //$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_wrapper_script_arg_handling() { + 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 //$pkg/java/hello:hello -- '' foo '' '' 'bar quux' '' \ + >&$TEST_log || fail "Build failed" + expect_log "Args: '' 'foo' '' '' 'bar quux' ''" +} + +function test_srcjar_compilation() { + 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 //$pkg/java/hello:hello //$pkg/java/hello:hello_deploy.jar \ + >&$TEST_log || fail "Expected success" + bazel run //$pkg/java/hello:hello -- --singlejar >&$TEST_log + expect_log "Hello World!" +} + +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() { + 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 //$pkg/java/test/client:client --use_ijars || fail "build failed" + unzip -l ${PRODUCT_NAME}-bin/$pkg/java/test/client/libclient.jar \ + | grep -q " test/Generated.class" \ + || fail "missing class file from annotation processing" + + bazel build //$pkg/java/test/client:libclient-src.jar --use_ijars \ + || fail "build failed" + unzip -l ${PRODUCT_NAME}-bin/$pkg/java/test/client/libclient-src.jar \ + | grep -q " test/Generated.java" \ + || fail "missing source file from annotation processing" +} + +function test_jvm_flags_are_passed_verbatim() { + 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', + 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\\', + # test make variable expansion + '--g=$(JAVABASE)', + ], +) +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 //$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\\ ' \ + " --g=${runfiles_relative_javabase}" \ + ; do + # NOTE: don't test the full path of the JDK, it's architecture-dependent. + assert_contains $flag $STUBSCRIPT + done +} + +function test_classpath_fiddling() { + 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 //$pkg/java/classpath || fail "build failed" + bazel run //$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 //$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_java7() { + 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 //$pkg/java/foo:foo | grep -q "Success!" || fail "Expected success" +} + +# Regression tests for b/18183921: broken java_library as data dependency won't +# break the build. +function test_java_library_fails_when_dependency_with_only_xmb_file_fails() { + local -r pkg="${FUNCNAME[0]}" + mkdir -p $pkg/java/test || fail "mkdir" + cat > $pkg/java/test/BUILD <<EOF +genrule( + name = 'failure', + outs = ['failure.xmb'], + cmd = 'false', +) + +java_library(name = 'javalib-a', + srcs = ['Hello.java', ':failure']) +java_library(name = 'javalib-b', + srcs = [':failure']) + +# Tests for dependencies on java_library +sh_test(name = 'test-a', + srcs = ['buildtest.sh'], + data = [':javalib-a'], +) +sh_test(name = 'test-b', + srcs = ['buildtest.sh'], + data = [':javalib-b'], +) +EOF + + cat >$pkg/java/test/Hello.java <<EOF +package test; +public class Hello { + public void hello() { + System.out.println("Hello, World!"); + } +} +EOF + + cat >$pkg/java/test/buildtest.sh <<EOF +#!/bin/bash +exit 0 +EOF + chmod +x $pkg/java/test/buildtest.sh + + bazel build //$pkg/java/test:libjavalib-a.jar && fail "build succeeded" + bazel build //$pkg/java/test:libjavalib-b.jar && fail "build succeeded" + + bazel build //$pkg/java/test:test-a && fail "build test succeeded" + bazel build //$pkg/java/test:test-b && fail "build test succeeded" + + bazel test //$pkg/java/test:test-a && fail "test succeeded" + bazel test //$pkg/java/test:test-b && fail "test succeeded" + + true # reset the last exit code so the test won't be considered failed +} + +function test_header_compilation() { + local -r pkg="${FUNCNAME[0]}" + mkdir "$pkg" || fail "mkdir $pkg" + write_hello_library_files "$pkg" + + bazel build -s --java_header_compilation=true \ + //$pkg/java/main:main || fail "build failed" + echo >&2 "DEBUG[${FUNCNAME[0]}]: start" + unzip -l ${PRODUCT_NAME}-bin/$pkg/java/hello_library/libhello_library-hjar.jar >&2 + echo >&2 "DEBUG[${FUNCNAME[0]}]: end" + unzip -l ${PRODUCT_NAME}-bin/$pkg/java/hello_library/libhello_library-hjar.jar \ + | grep -q " hello_library/HelloLibrary.class" \ + || fail "missing class file from header compilation" +} + +function test_header_compilation_errors() { + 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 --java_header_compilation=true \ + //$pkg/java/test:a >& "$TEST_log" && fail "Unexpected success" + expect_log "package missing does not exist" +} + +function test_java_import_with_empty_jars_attribute() { + 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 //$pkg/java/hello:hello //$pkg/java/hello:hello_deploy.jar >& "$TEST_log" \ + || fail "Expected success" + bazel run //$pkg/java/hello:hello -- --singlejar >& "$TEST_log" + expect_log "Hello World!" +} + +run_suite "Java integration tests" |