Skip to content

Commit

Permalink
Polish grpcio_health_checking package
Browse files Browse the repository at this point in the history
-Rename namespace to grpc_health->grpc to match spec
-Proper use of NOT_FOUND status code
-Improve testing
-Add source distribution to artifact build
  • Loading branch information
kpayson64 committed Jul 18, 2016
1 parent 7c46754 commit dd24c1e
Show file tree
Hide file tree
Showing 18 changed files with 187 additions and 90 deletions.
2 changes: 1 addition & 1 deletion include/grpc/impl/codegen/port_platform.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@
// libraries; it should be integrated with the `__linux__` definitions below.
#define GPR_PLATFORM_STRING "manylinux"
#define GPR_POSIX_CRASH_HANDLER 1
#define GPR_CPU_LINUX 1
#define GPR_CPU_POSIX 1
#define GPR_GCC_ATOMIC 1
#define GPR_GCC_TLS 1
#define GPR_LINUX 1
Expand Down
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@ build_base=python_build
[build_ext]
inplace=1

[build_proto_modules]
[build_package_protos]
exclude=.*protoc_plugin/protoc_plugin_test\.proto$
3 changes: 2 additions & 1 deletion src/python/grpcio_health_checking/MANIFEST.in
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
include grpc_version.py
include health_commands.py
graft grpc_health
graft grpc
global-exclude *.pyc
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,4 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.


__import__('pkg_resources').declare_namespace(__name__)
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,12 @@

import threading

from grpc_health.health.v1 import health_pb2
import grpc

from grpc.health.v1 import health_pb2

class HealthServicer(health_pb2.BetaHealthServicer):

class HealthServicer(health_pb2.HealthServicer):
"""Servicer handling RPCs for service statuses."""

def __init__(self):
Expand All @@ -43,14 +45,12 @@ def __init__(self):

def Check(self, request, context):
with self._server_status_lock:
if request.service not in self._server_status:
# TODO(atash): once the Python API has a way of setting the server
# status, bring us into conformance with the health check spec by
# returning the NOT_FOUND status here.
raise NotImplementedError()
status = self._server_status.get(request.service)
if status is None:
context.set_code(grpc.StatusCode.NOT_FOUND)
return health_pb2.HealthCheckResponse()
else:
return health_pb2.HealthCheckResponse(
status=self._server_status[request.service])
return health_pb2.HealthCheckResponse(status=status)

def set(self, service, status):
"""Sets the status of a service.
Expand All @@ -63,4 +63,3 @@ def set(self, service, status):
"""
with self._server_status_lock:
self._server_status[service] = status

32 changes: 32 additions & 0 deletions src/python/grpcio_health_checking/grpc_version.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Copyright 2016, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

# AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_health_checking/grpc_version.py.template`!!!

VERSION='1.0.0rc1'
29 changes: 18 additions & 11 deletions src/python/grpcio_health_checking/health_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,10 @@

"""Provides distutils command classes for the GRPC Python setup process."""

import distutils
import glob
import os
import os.path
import shutil
import subprocess
import sys

import setuptools
from setuptools.command import build_py

ROOT_DIR = os.path.abspath(os.path.dirname(os.path.abspath(__file__)))
HEALTH_PROTO = os.path.join(ROOT_DIR, '../../proto/grpc/health/v1/health.proto')
Expand All @@ -60,12 +54,25 @@ def run(self):
if os.path.isfile(HEALTH_PROTO):
shutil.copyfile(
HEALTH_PROTO,
os.path.join(ROOT_DIR, 'grpc_health/health/v1/health.proto'))
os.path.join(ROOT_DIR, 'grpc/health/v1/health.proto'))


class BuildPy(build_py.build_py):
"""Custom project build command."""
class BuildPackageProtos(setuptools.Command):
"""Command to generate project *_pb2.py modules from proto files."""

description = 'build grpc protobuf modules'
user_options = []

def initialize_options(self):
pass

def finalize_options(self):
pass

def run(self):
self.run_command('build_proto_modules')
build_py.build_py.run(self)
# due to limitations of the proto generator, we require that only *one*
# directory is provided as an 'include' directory. We assume it's the '' key
# to `self.distribution.package_dir` (and get a key error if it's not
# there).
from grpc.tools import command
command.build_package_protos(self.distribution.package_dir[''])
23 changes: 8 additions & 15 deletions src/python/grpcio_health_checking/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,49 +30,42 @@
"""Setup module for the GRPC Python package's optional health checking."""

import os
import os.path
import sys

from distutils import core as _core
import setuptools

import grpc.tools.command

# Ensure we're in the proper directory whether or not we're being used by pip.
os.chdir(os.path.dirname(os.path.abspath(__file__)))

# Break import-style to ensure we can actually find our commands module.
import health_commands

PACKAGES = (
setuptools.find_packages('.')
)
import grpc_version

PACKAGE_DIRECTORIES = {
'': '.',
}

SETUP_REQUIRES = (
'grpcio-tools>=0.14.0',
'grpcio-tools>=0.15.0',
)

INSTALL_REQUIRES = (
'grpcio>=0.13.1',
'grpcio>=0.15.0',
)

COMMAND_CLASS = {
# Run preprocess from the repository *before* doing any packaging!
'preprocess': health_commands.CopyProtoModules,

'build_proto_modules': grpc.tools.command.BuildProtoModules,
'build_py': health_commands.BuildPy,
'build_package_protos': health_commands.BuildPackageProtos,
}

setuptools.setup(
name='grpcio-health-checking',
version='0.14.0',
packages=list(PACKAGES),
version=grpc_version.VERSION,
license='3-clause BSD',
package_dir=PACKAGE_DIRECTORIES,
packages=setuptools.find_packages('.'),
namespace_packages=['grpc'],
install_requires=INSTALL_REQUIRES,
setup_requires=SETUP_REQUIRES,
cmdclass=COMMAND_CLASS
Expand Down
2 changes: 1 addition & 1 deletion src/python/grpcio_tests/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ class BuildPy(build_py.build_py):

def run(self):
try:
self.run_command('build_proto_modules')
self.run_command('build_package_protos')
except CommandError as error:
sys.stderr.write('warning: %s\n' % error.message)
build_py.build_py.run(self)
Expand Down
2 changes: 1 addition & 1 deletion src/python/grpcio_tests/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@
# Run `preprocess` *before* doing any packaging!
'preprocess': commands.GatherProto,

'build_proto_modules': grpc.tools.command.BuildProtoModules,
'build_package_protos': grpc.tools.command.BuildPackageProtos,
'build_py': commands.BuildPy,
'run_interop': commands.RunInterop,
'test_lite': commands.TestLite
Expand Down
58 changes: 39 additions & 19 deletions src/python/grpcio_tests/tests/health_check/_health_servicer_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,48 +27,68 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

"""Tests of grpc_health.health.v1.health."""
"""Tests of grpc.health.v1.health."""

import unittest

from grpc_health.health.v1 import health
from grpc_health.health.v1 import health_pb2
import grpc
from grpc.framework.foundation import logging_pool
from grpc.health.v1 import health
from grpc.health.v1 import health_pb2

from tests.unit.framework.common import test_constants


class HealthServicerTest(unittest.TestCase):

def setUp(self):
self.servicer = health.HealthServicer()
self.servicer.set('', health_pb2.HealthCheckResponse.SERVING)
self.servicer.set('grpc.test.TestServiceServing',
health_pb2.HealthCheckResponse.SERVING)
self.servicer.set('grpc.test.TestServiceUnknown',
health_pb2.HealthCheckResponse.UNKNOWN)
self.servicer.set('grpc.test.TestServiceNotServing',
health_pb2.HealthCheckResponse.NOT_SERVING)
servicer = health.HealthServicer()
servicer.set('', health_pb2.HealthCheckResponse.SERVING)
servicer.set('grpc.test.TestServiceServing',
health_pb2.HealthCheckResponse.SERVING)
servicer.set('grpc.test.TestServiceUnknown',
health_pb2.HealthCheckResponse.UNKNOWN)
servicer.set('grpc.test.TestServiceNotServing',
health_pb2.HealthCheckResponse.NOT_SERVING)
server_pool = logging_pool.pool(test_constants.THREAD_CONCURRENCY)
self._server = grpc.server(server_pool)
port = self._server.add_insecure_port('[::]:0')
health_pb2.add_HealthServicer_to_server(servicer, self._server)
self._server.start()

channel = grpc.insecure_channel('localhost:%d' % port)
self._stub = health_pb2.HealthStub(channel)

def test_empty_service(self):
request = health_pb2.HealthCheckRequest()
resp = self.servicer.Check(request, None)
self.assertEqual(resp.status, health_pb2.HealthCheckResponse.SERVING)
resp = self._stub.Check(request)
self.assertEqual(health_pb2.HealthCheckResponse.SERVING, resp.status)

def test_serving_service(self):
request = health_pb2.HealthCheckRequest(
service='grpc.test.TestServiceServing')
resp = self.servicer.Check(request, None)
self.assertEqual(resp.status, health_pb2.HealthCheckResponse.SERVING)
resp = self._stub.Check(request)
self.assertEqual(health_pb2.HealthCheckResponse.SERVING, resp.status)

def test_unknown_serivce(self):
request = health_pb2.HealthCheckRequest(
service='grpc.test.TestServiceUnknown')
resp = self.servicer.Check(request, None)
self.assertEqual(resp.status, health_pb2.HealthCheckResponse.UNKNOWN)
resp = self._stub.Check(request)
self.assertEqual(health_pb2.HealthCheckResponse.UNKNOWN, resp.status)

def test_not_serving_service(self):
request = health_pb2.HealthCheckRequest(
service='grpc.test.TestServiceNotServing')
resp = self.servicer.Check(request, None)
self.assertEqual(resp.status, health_pb2.HealthCheckResponse.NOT_SERVING)
resp = self._stub.Check(request)
self.assertEqual(health_pb2.HealthCheckResponse.NOT_SERVING, resp.status)

def test_not_found_service(self):
request = health_pb2.HealthCheckRequest(
service='not-found')
with self.assertRaises(grpc.RpcError) as context:
resp = self._stub.Check(request)

self.assertEqual(grpc.StatusCode.NOT_FOUND, context.exception.code())


if __name__ == '__main__':
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
%YAML 1.2
--- |
# Copyright 2016, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

# AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_health_checking/grpc_version.py.template`!!!

VERSION='${settings.python_version.pep440()}'
38 changes: 21 additions & 17 deletions tools/distrib/python/grpcio_tools/grpc/tools/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,26 @@
from grpc.tools import protoc


class BuildProtoModules(setuptools.Command):
def build_package_protos(package_root):
proto_files = []
inclusion_root = os.path.abspath(package_root)
for root, _, files in os.walk(inclusion_root):
for filename in files:
if filename.endswith('.proto'):
proto_files.append(os.path.abspath(os.path.join(root, filename)))

for proto_file in proto_files:
command = [
'grpc.tools.protoc',
'--proto_path={}'.format(inclusion_root),
'--python_out={}'.format(inclusion_root),
'--grpc_python_out={}'.format(inclusion_root),
] + [proto_file]
if protoc.main(command) != 0:
sys.stderr.write('warning: {} failed'.format(command))


class BuildPackageProtos(setuptools.Command):
"""Command to generate project *_pb2.py modules from proto files."""

description = 'build grpc protobuf modules'
Expand All @@ -52,19 +71,4 @@ def run(self):
# directory is provided as an 'include' directory. We assume it's the '' key
# to `self.distribution.package_dir` (and get a key error if it's not
# there).
proto_files = []
inclusion_root = os.path.abspath(self.distribution.package_dir[''])
for root, _, files in os.walk(inclusion_root):
for filename in files:
if filename.endswith('.proto'):
proto_files.append(os.path.abspath(os.path.join(root, filename)))

for proto_file in proto_files:
command = [
'grpc.tools.protoc',
'--proto_path={}'.format(inclusion_root),
'--python_out={}'.format(inclusion_root),
'--grpc_python_out={}'.format(inclusion_root),
] + [proto_file]
if protoc.main(command) != 0:
sys.stderr.write('warning: {} failed'.format(command))
build_package_protos(self.distribution.package_dir[''])
Loading

0 comments on commit dd24c1e

Please sign in to comment.