Add feature examples with continuous integration (#27917)

* Add failing end2end test for inconsistent percent-decoding of URIs

* Add passing h2_local_abstract_uds end2end tests

* Add basic abstract UDS example

* add test runner

* add proper bazel build path

* first attempt at CI configuration

* cleanup

* rename CI files for better readability
pull/28018/head
AJ Heller 3 years ago committed by GitHub
parent f7d4f8e13c
commit c5f1d29b76
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 129
      examples/cpp/features/run_tests.sh
  2. 34
      examples/cpp/features/unix_abstract/BUILD
  3. 63
      examples/cpp/features/unix_abstract/client.cc
  4. 60
      examples/cpp/features/unix_abstract/server.cc
  5. 29
      tools/internal_ci/linux/grpc_feature_example_tests.sh
  6. 29
      tools/internal_ci/linux/pull_request/grpc_feature_examples_test.cfg

@ -0,0 +1,129 @@
#!/usr/bin/env bash
# Copyright 2021 gRPC authors.
#
# 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.
# Test structure borrowed with gratitude from
# https://github.com/grpc/grpc-go/tree/master/examples/features
set -eux
# execute in root dir
SCRIPTPATH="$(
cd -- "$(dirname "$0")" >/dev/null 2>&1
pwd -P
)"
cd ${SCRIPTPATH}/../../..
SERVER_PORT=50051
export TMPDIR=$(mktemp -d)
trap "rm -rf ${TMPDIR}" EXIT
clean() {
# loop a handful of times in case job shutdown is not immediate
for i in {1..5}; do
# kill all jobs
jobs -p | xargs kill &>/dev/null || true
# wait for all jobs to exit
sleep 0.3
if ! jobs | read; then
return
fi
done
echo "ERROR: clean failed to kill tests"
jobs
exit 1
}
fail() {
echo "$@" >&2
clean
exit 1
}
pass() {
echo "SUCCESS: $1"
}
wait_for_server() {
feature=$1
wait_command=${SERVER_WAIT_COMMAND[$feature]:-${SERVER_WAIT_COMMAND["default"]}}
echo "INFO: waiting for server to start"
declare -i i=0
while ! eval "$wait_command"; do
((++i < 10)) || fail "cannot determine if server started"
lsof -U
sleep 1
done
pass "server started"
}
FEATURES=(
"unix_abstract"
)
declare -A SERVER_WAIT_COMMAND=(
["unix_abstract"]="lsof -U | grep '@grpc@abstract'"
["default"]="lsof -i :$SERVER_PORT | grep $SERVER_PORT"
)
declare -A EXPECTED_SERVER_OUTPUT=(
["unix_abstract"]="Server listening on unix-abstract:grpc%00abstract ... Echoing: arst"
)
declare -A EXPECTED_CLIENT_OUTPUT=(
["unix_abstract"]="Sending 'arst' to unix-abstract:grpc%00abstract ... Received: arst"
)
for feature in ${FEATURES[@]}; do
echo "TESTING: $feature"
bazel build --define=use_strict_warning=true //examples/cpp/features/${feature}:all || fail "failed to build $feature"
SERVER_LOG="$(mktemp)"
./bazel-bin/examples/cpp/features/$feature/server &>$SERVER_LOG &
wait_for_server $feature
# TODO(hork): add a timeout to abort client?
CLIENT_LOG="$(mktemp)"
./bazel-bin/examples/cpp/features/$feature/client &>$CLIENT_LOG
if [ -n "${EXPECTED_SERVER_OUTPUT[$feature]}" ]; then
if ! grep -q "${EXPECTED_SERVER_OUTPUT[$feature]}" $SERVER_LOG; then
fail "server log missing output: ${EXPECTED_SERVER_OUTPUT[$feature]}
got server log:
$(cat $SERVER_LOG)
got client log:
$(cat $CLIENT_LOG)
"
else
pass "server log contains expected output: ${EXPECTED_SERVER_OUTPUT[$feature]}"
fi
fi
if [ -n "${EXPECTED_CLIENT_OUTPUT[$feature]}" ]; then
if ! grep -q "${EXPECTED_CLIENT_OUTPUT[$feature]}" $CLIENT_LOG; then
fail "client log missing output: ${EXPECTED_CLIENT_OUTPUT[$feature]}
got server log:
$(cat $SERVER_LOG)
got client log:
$(cat $CLIENT_LOG)
"
else
pass "client log contains expected output: ${EXPECTED_CLIENT_OUTPUT[$feature]}"
fi
fi
clean
done

@ -0,0 +1,34 @@
# Copyright 2021 the gRPC authors.
#
# 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.
licenses(["notice"])
cc_binary(
name = "client",
srcs = ["client.cc"],
deps = [
"//:grpc++",
"//examples/protos:helloworld_cc_grpc",
],
)
cc_binary(
name = "server",
srcs = ["server.cc"],
deps = [
"//:grpc++",
"//:grpc++_reflection",
"//examples/protos:helloworld_cc_grpc",
],
)

@ -0,0 +1,63 @@
// Copyright 2021 the gRPC authors.
//
// 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.
#include <iostream>
#include <memory>
#include <string>
#include "examples/protos/helloworld.grpc.pb.h"
#include <grpcpp/grpcpp.h>
using grpc::Channel;
using grpc::ClientContext;
using grpc::Status;
using helloworld::Greeter;
using helloworld::HelloReply;
using helloworld::HelloRequest;
class GreeterClient {
public:
GreeterClient(std::shared_ptr<Channel> channel)
: stub_(Greeter::NewStub(channel)) {}
std::string SayHello(const std::string& user) {
HelloRequest request;
request.set_name(user);
HelloReply reply;
ClientContext context;
Status status = stub_->SayHello(&context, request, &reply);
if (status.ok()) {
return reply.message();
}
std::cout << status.error_code() << ": " << status.error_message()
<< std::endl;
return "RPC failed";
}
private:
std::unique_ptr<Greeter::Stub> stub_;
};
int main(int argc, char** argv) {
std::string target_str("unix-abstract:grpc%00abstract");
GreeterClient greeter(
grpc::CreateChannel(target_str, grpc::InsecureChannelCredentials()));
std::string user("arst");
std::cout << "Sending '" << user << "' to " << target_str << " ... ";
std::string reply = greeter.SayHello(user);
std::cout << "Received: " << reply << std::endl;
return 0;
}

@ -0,0 +1,60 @@
// Copyright 2021 the gRPC authors.
//
// 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.
#include <iostream>
#include <memory>
#include <string>
#include "examples/protos/helloworld.grpc.pb.h"
#include <grpcpp/ext/proto_server_reflection_plugin.h>
#include <grpcpp/grpcpp.h>
#include <grpcpp/health_check_service_interface.h>
using grpc::Server;
using grpc::ServerBuilder;
using grpc::ServerContext;
using grpc::Status;
using helloworld::Greeter;
using helloworld::HelloReply;
using helloworld::HelloRequest;
// Logic and data behind the server's behavior.
class GreeterServiceImpl final : public Greeter::Service {
Status SayHello(ServerContext* context, const HelloRequest* request,
HelloReply* reply) override {
reply->set_message(request->name());
std::cout << "Echoing: " << request->name() << std::endl;
return Status::OK;
}
};
void RunServer() {
std::string server_address("unix-abstract:grpc%00abstract");
GreeterServiceImpl service;
grpc::EnableDefaultHealthCheckService(true);
grpc::reflection::InitProtoReflectionServerBuilderPlugin();
ServerBuilder builder;
builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
builder.RegisterService(&service);
std::unique_ptr<Server> server(builder.BuildAndStart());
std::cout << "Server listening on " << server_address << " ... ";
server->Wait();
}
int main(int argc, char** argv) {
RunServer();
return 0;
}

@ -0,0 +1,29 @@
#!/bin/bash
# Copyright 2021 The gRPC authors.
#
# 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.
#!/usr/bin/env bash
#
# NOTE: No empty lines should appear in this file before igncr is set!
set -ex -o igncr || set -ex
mkdir -p /var/local/git
git clone /var/local/jenkins/grpc /var/local/git/grpc
(cd /var/local/jenkins/grpc/ && git submodule foreach 'cd /var/local/git/grpc \
&& git submodule update --init --reference /var/local/jenkins/grpc/${name} \
${name}')
cd /var/local/git/grpc
apt-get install -y lsof
./examples/cpp/features/run_tests.sh

@ -0,0 +1,29 @@
# Copyright 2019 The gRPC Authors
#
# 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.
# Config file for the internal CI (in protobuf text format)
# Location of the continuous shell script in repository.
build_file: "grpc/tools/internal_ci/linux/grpc_bazel.sh"
timeout_mins: 30
env_vars {
key: "BAZEL_SCRIPT"
value: "tools/internal_ci/linux/grpc_feature_example_tests.sh"
}
action {
define_artifacts {
regex: "**/*sponge_log.*"
regex: "github/grpc/reports/**"
}
}
Loading…
Cancel
Save