blob: 6ff835ba84f5daf92ae91fdf08d0fe88b52c5966 [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.
#
# Tests the examples provided in Bazel
#
# Load the test setup defined in the parent directory
CURRENT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "${CURRENT_DIR}/../integration_test_setup.sh" \
|| { echo "integration_test_setup.sh not found!" >&2; exit 1; }
# Appends to "WORKSPACE" the declaration of 2 local repositories.
# Assumes the main content of WORKSPACE was created previously.
function add_local_repos_to_workspace() {
cat >> WORKSPACE <<EOF
local_repository(
name = "repo",
path = "a/b"
)
local_repository(
name = "main_repo",
path = "c/d"
)
EOF
}
# Appends to the WORKSPACE file under a given path (the first argument) the dependencies needed
# for proto_library.
function write_workspace() {
workspace=""
if [ ! -z "$1" ];
then
workspace=$1
mkdir -p "$workspace"
fi
cat >> "$workspace"WORKSPACE << EOF
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(
name = "rules_proto",
strip_prefix = "rules_proto-97d8af4dc474595af3900dd85cb3a29ad28cc313",
sha256 = "602e7161d9195e50246177e7c55b2f39950a9cf7366f74ed5f22fd45750cd208",
urls = [
"https://mirror.bazel.build/github.com/bazelbuild/rules_proto/archive/97d8af4dc474595af3900dd85cb3a29ad28cc313.tar.gz",
"https://github.com/bazelbuild/rules_proto/archive/97d8af4dc474595af3900dd85cb3a29ad28cc313.tar.gz",
],
)
load("@rules_proto//proto:repositories.bzl", "rules_proto_dependencies", "rules_proto_toolchains")
rules_proto_dependencies()
rules_proto_toolchains()
# @com_google_protobuf//:protoc depends on @io_bazel//third_party/zlib.
new_local_repository(
name = "io_bazel",
path = "$(dirname $(rlocation io_bazel/third_party/rules_python/rules_python.WORKSPACE))/../..",
build_file_content = "# Intentionally left empty.",
workspace_file_content = "workspace(name = 'io_bazel')",
)
# TODO(#9029): May require some adjustment if/when we depend on the real
# @rules_python in the real source tree, since this third_party/ package won't
# be available.
new_local_repository(
name = "rules_python",
path = "$(dirname $(rlocation io_bazel/third_party/rules_python/rules_python.WORKSPACE))",
build_file = "$(rlocation io_bazel/third_party/rules_python/BUILD)",
workspace_file = "$(rlocation io_bazel/third_party/rules_python/rules_python.WORKSPACE)",
)
EOF
}
# Creates directories and files with the structure:
# x/
# person/
# BUILD
# person.proto (imports "bar/bar.proto", has strip_import_prefix = "")
# phonenumber/
# phonenumber.proto
# phonebook/
# BUILD
# phonebook.proto (imports "person.proto" & "phonenumber/phonenumber.proto")
#
# The BUILD files could use directly "proto_library" rules or a macro called
# "proto_library_macro" that should be created beforehand using write_macro().
#
# Expected arguments:
# 1. The name of the proto library rule. Can be "proto_library" or
# "proto_library_macro".
# 2. A row in the BUILD file that specifies the strip_import_prefix attribute on
# proto_library. Should be left empty if a macro is used.
# 3. A load statement that includes a macro containing a wrapper around
# proto_library.
function write_setup() {
mkdir -p x/person/phonenumber
proto_library_name=$1
extra_attribute=$2
include_macro=$3
if [ "${include_macro}" -eq "" ]; then
include_macro="load('@rules_proto//proto:defs.bzl', 'proto_library')"
fi
cat > x/person/BUILD << EOF
package(default_visibility = ["//visibility:public"])
$include_macro
$proto_library_name(
name = "person_proto",
srcs = ["person.proto"],
deps = [":phonenumber_proto"],
$extra_attribute
)
$proto_library_name(
name = "phonenumber_proto",
srcs = ["phonenumber/phonenumber.proto"],
$extra_attribute
)
EOF
cat > x/person/person.proto << EOF
syntax = "proto2";
option java_package = "person";
option java_outer_classname = "Person";
import "phonenumber/phonenumber.proto";
message PersonProto {
optional string name = 1;
optional PhoneNumberProto phone = 2;
}
EOF
cat > x/person/phonenumber/phonenumber.proto << EOF
syntax = "proto2";
option java_package = "person.phonenumber";
option java_outer_classname = "PhoneNumber";
message PhoneNumberProto {
required string number = 1;
}
EOF
mkdir -p x/phonebook
cat > x/phonebook/BUILD << EOF
$include_macro
$proto_library_name(
name = "phonebook",
srcs = ["phonebook.proto"],
deps = ["//x/person:person_proto"],
)
EOF
cat > x/phonebook/phonebook.proto << EOF
import "person.proto";
import "phonenumber/phonenumber.proto";
message Agenda {
required PersonProto person = 1;
required PhoneNumberProto number = 2;
}
EOF
}
# Creates the files in the following directory structure:
# proto_library/
# BUILD <- empty
# src/
# BUILD <- has target "all" for all .proto
# address.proto <- imports "person.proto"
# person.proto <- imports "address.proto"
# zip_code.proto
function write_regression_setup() {
mkdir -p proto_library/src
touch proto_library/BUILD
cat > proto_library/src/BUILD << EOF
load("@rules_proto//proto:defs.bzl", "proto_library")
proto_library(
name = "all",
srcs = glob(["*.proto"]),
strip_import_prefix = "",
)
EOF
cat > proto_library/src/address.proto <<EOF
syntax = "proto3";
package demo; // Required to generate valid code.
// Always import protos with a full path relative to the WORKSPACE file.
import "zip_code.proto";
message Address {
string city = 1;
ZipCode zip_code = 2;
}
EOF
cat > proto_library/src/person.proto <<EOF
syntax = "proto3";
package demo; // Required to generate valid code.
// Always import protos with a full path relative to the WORKSPACE file.
import "address.proto";
message Person {
string name = 1;
int32 id = 2;
string email = 3;
Address address = 4;
}
EOF
cat > proto_library/src/zip_code.proto <<EOF
syntax = "proto3";
package demo; // Required to generate valid code.
message ZipCode {
string code = 1;
}
EOF
}
# Creates the directories and files in following the structure:
# a/b/
# WORKSPACE <- workspace referenced as "repo"
# BUILD <- empty
# src/
# BUILD <- "all_protos" with strip_import_prefix
# address.proto <- imports "zip_code.proto"
# zip_code.proto
# c/d/
# WORKSPACE <- workspace referenced as "main_repo"
# BUILD <- empty
# src/
# BUILD <- "all_protos" with strip_import_prefix
# person.proto <- imports "address.proto" and depends on @repo//src:all_protos
function write_workspaces_setup() {
mkdir -p a/b/src
touch a/b/BUILD
cat > a/b/src/BUILD <<EOF
package(default_visibility = ["//visibility:public"])
load("@rules_proto//proto:defs.bzl", "proto_library")
proto_library(
name = "all_protos",
srcs = glob(["*.proto"]),
strip_import_prefix = "",
)
EOF
cat > a/b/src/address.proto <<EOF
syntax = "proto3";
package demo; // Required to generate valid code.
// Always import protos with a full path relative to the WORKSPACE file.
import "zip_code.proto";
message Address {
string city = 1;
ZipCode zip_code = 2;
}
EOF
cat > a/b/src/zip_code.proto <<EOF
syntax = "proto3";
package demo; // Required to generate valid code.
message ZipCode {
string code = 1;
}
EOF
#### WORKSPACE(c/d) ####
mkdir -p c/d/src
touch c/d/BUILD
cat > c/d/src/BUILD <<EOF
package(default_visibility = ["//visibility:public"])
load("@rules_proto//proto:defs.bzl", "proto_library")
proto_library(
name = "all_protos",
srcs = glob(["*.proto"]),
strip_import_prefix = "",
deps = ["@repo//src:all_protos"]
)
EOF
cat > c/d/src/person.proto <<EOF
syntax = "proto3";
package demo; // Required to generate valid code.
// Always import protos with a full path relative to the WORKSPACE file.
import "address.proto";
message Person {
string name = 1;
int32 id = 2;
string email = 3;
Address address = 4;
}
EOF
}
# Creates macros/BUILD and macros/proto_library_macro.bzl, which contains a
# macro that wraps the proto_library rule. The macro passes to proto_library the
# same "name", "srcs", "deps" and adds "strip_import_prefix=''"
# This will be a common use case for the "strip_import_prefix" attribute.
function write_macro() {
mkdir macros
cat > macros/BUILD << EOF
export_files(["proto_library_macro.bzl])
EOF
cat > macros/proto_library_macro.bzl << EOF
load("@rules_proto//proto:defs.bzl", "proto_library")
def proto_library_macro(name, srcs, deps = []):
proto_library(
name = name,
srcs = srcs,
deps = deps,
strip_import_prefix = "",
)
EOF
}
# Creates the directories and files from the following structure
# java/com/google/src/
# BUILD
# A.java
function write_java_library() {
# should depend on x/foo:foo
mkdir -p java/com/google/src
cat > java/com/google/src/BUILD << EOF
java_library(
name = "top",
srcs = ["A.java"],
deps = [":jpl"]
)
java_proto_library(
name = "jpl",
deps = ["//x/person:person_proto"]
)
EOF
cat > java/com/google/src/A.java << EOF
import person.Person.PersonProto;
import person.phonenumber.PhoneNumber.PhoneNumberProto;
public class A {
private PersonProto person;
public A(PersonProto person) {
this.person = person;
PhoneNumberProto number = person.getPhone();
}
}
EOF
}
############# TESTS #############
function test_legacy_proto_library_include_well_known_protos() {
write_workspace ""
mkdir -p a
cat > a/BUILD <<EOF
proto_library(
name="a",
srcs=["a.proto"],
deps=[":b"],
)
proto_library(
name="b",
srcs=["b.proto"],
deps=["@com_google_protobuf//:duration_proto"],
)
EOF
cat > a/a.proto <<EOF
syntax = "proto3";
package a;
import "a/b.proto";
message A {
int32 a = 1;
b.B b = 2;
}
EOF
cat > a/b.proto <<EOF
syntax = "proto3";
package b;
import "google/protobuf/duration.proto";
message B {
int32 b = 1;
google.protobuf.Duration timing = 2;
}
EOF
bazel build //a:a || fail "build failed"
}
function test_javainfo_proto_aspect() {
write_workspace ""
mkdir -p java/proto/
touch java/proto/my.proto
cat > java/proto/BUILD << EOF
load(':my_rule_with_aspect.bzl', 'my_rule_with_aspect')
my_rule_with_aspect(
name = 'my_rule',
deps = [':my_java_proto']
)
java_proto_library(
name = 'my_java_proto',
deps = [':my_proto'],
)
proto_library(
name = 'my_proto',
srcs = ['my.proto'],
)
EOF
cat > java/proto/my_rule_with_aspect.bzl <<EOF
def _my_rule_impl(ctx):
aspect_java_infos = []
for dep in ctx.attr.deps:
aspect_java_infos += dep.my_aspect_providers
merged_java_info = java_common.merge(aspect_java_infos)
for jar in merged_java_info.transitive_runtime_jars.to_list():
print('Transitive runtime jar', jar)
def _my_aspect_impl(target, ctx):
aspect_java_infos = []
for dep in ctx.rule.attr.deps:
aspect_java_infos += dep.my_aspect_providers
aspect_java_infos.append(target[JavaInfo])
return struct(
my_aspect_providers = aspect_java_infos
)
my_aspect = aspect(
attr_aspects = ['deps'],
fragments = ['java'],
implementation = _my_aspect_impl,
required_aspect_providers = [[JavaInfo]]
)
my_rule_with_aspect = rule(
implementation = _my_rule_impl,
attrs = {
'deps': attr.label_list(aspects = [my_aspect]),
}
)
EOF
bazel build java/proto:my_rule &> "$TEST_log" || fail "build failed"
expect_log "Transitive runtime jar <generated file java/proto/libmy_proto-speed.jar>"
}
function test_strip_import_prefix() {
write_workspace ""
write_setup "proto_library" "strip_import_prefix = '/x/person'" ""
bazel build --verbose_failures //x/person:person_proto > "$TEST_log" || fail "Expected success"
}
function test_strip_import_prefix_fails() {
write_workspace ""
# Don't specify the "strip_import_prefix" attribute and expect failure.
write_setup "proto_library" "" ""
bazel build //x/person:person_proto >& "$TEST_log" && fail "Expected failure"
expect_log "phonenumber/phonenumber.proto: File not found."
}
function test_strip_import_prefix_macro() {
write_workspace ""
write_macro
write_setup "proto_library_macro" "" "load('//macros:proto_library_macro.bzl', 'proto_library_macro')"
bazel build //x/person:person_proto > "$TEST_log" || fail "Expected success"
}
# Fails with "IllegalArgumentException: external/lcocal_jdk in
# DumpPlatformClassPath.dumpJDK9AndNewerBootClassPath.java:67
function DISABLED_test_strip_import_prefix_with_java_library() {
write_workspace ""
write_setup "proto_library" "strip_import_prefix = '/x/person'" ""
write_java_library
bazel build //java/com/google/src:top \
--strict_java_deps=off > "$TEST_log" || fail "Expected success"
}
function test_strip_import_prefix_glob() {
write_workspace ""
write_regression_setup
bazel build //proto_library/src:all >& "$TEST_log" || fail "Expected success"
}
function test_strip_import_prefix_multiple_workspaces() {
write_workspace "a/b/"
write_workspace "c/d/"
write_workspace ""
add_local_repos_to_workspace
write_workspaces_setup
bazel build @main_repo//src:all_protos >& "$TEST_log" || fail "Expected success"
}
function test_cc_proto_library() {
write_workspace ""
mkdir -p a
cat > a/BUILD <<EOF
load("@rules_proto//proto:defs.bzl", "proto_library")
proto_library(name='p', srcs=['p.proto'])
cc_proto_library(name='cp', deps=[':p'])
cc_library(name='c', srcs=['c.cc'], deps=[':cp'])
EOF
cat > a/p.proto <<EOF
syntax = "proto2";
package a;
message A {
optional int32 a = 1;
}
EOF
cat > a/c.cc <<EOF
#include "a/p.pb.h"
void f() {
a::A a;
}
EOF
bazel build //a:c || fail "build failed"
}
function test_cc_proto_library_import_prefix_stripping() {
write_workspace ""
mkdir -p a/dir
cat > a/BUILD <<EOF
load("@rules_proto//proto:defs.bzl", "proto_library")
proto_library(name='p', srcs=['dir/p.proto'], strip_import_prefix='/a')
cc_proto_library(name='cp', deps=[':p'])
cc_library(name='c', srcs=['c.cc'], deps=[':cp'])
EOF
cat > a/dir/p.proto <<EOF
syntax = "proto2";
package a;
message A {
optional int32 a = 1;
}
EOF
cat > a/c.cc <<EOF
#include "dir/p.pb.h"
void f() {
a::A a;
}
EOF
bazel build //a:c || fail "build failed"
}
function test_import_prefix_stripping() {
mkdir -p e
touch e/WORKSPACE
write_workspace ""
cat >> WORKSPACE <<EOF
local_repository(
name = "repo",
path = "e"
)
EOF
mkdir -p e/f/bad
cat > e/f/BUILD <<EOF
load("@rules_proto//proto:defs.bzl", "proto_library")
proto_library(
name = "f",
strip_import_prefix = "bad",
import_prefix = "good",
srcs = ["bad/f.proto"],
visibility = ["//visibility:public"],
)
EOF
cat > e/f/bad/f.proto <<EOF
syntax = "proto2";
package f;
message F {
optional int32 f = 1;
}
EOF
mkdir -p g/bad
cat > g/BUILD << EOF
load("@rules_proto//proto:defs.bzl", "proto_library")
proto_library(
name = 'g',
strip_import_prefix = "/g/bad",
import_prefix = "good",
srcs = ['bad/g.proto'],
visibility = ["//visibility:public"],
)
EOF
cat > g/bad/g.proto <<EOF
syntax = "proto2";
package g;
message G {
optional int32 g = 1;
}
EOF
mkdir -p h
cat > h/BUILD <<EOF
load("@rules_proto//proto:defs.bzl", "proto_library")
proto_library(
name = "h",
srcs = ["h.proto"],
deps = ["//g", "@repo//f"],
)
EOF
cat > h/h.proto <<EOF
syntax = "proto2";
package h;
import "good/f.proto";
import "good/g.proto";
message H {
optional f.F f = 1;
optional g.G g = 2;
}
EOF
bazel build //h || fail "build failed"
}
run_suite "Integration tests for proto_library"