From 230aa7a89e914cc46c3f76282d9da1f8ed7fdbbe Mon Sep 17 00:00:00 2001 From: finn <finn.ball@codethink.com> Date: Fri, 27 Jul 2018 09:24:48 +0100 Subject: [PATCH] Adding bot_interface unittests --- .gitlab-ci.yml | 2 +- app/commands/cmd_bot.py | 10 ++++-- buildgrid/bot/bot.py | 35 +++++++++---------- tests/integration/bot_interface.py | 54 ++++++++++++++++++++++++++++++ 4 files changed, 78 insertions(+), 23 deletions(-) create mode 100644 tests/integration/bot_interface.py diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 421b5be8d..e898aaa9f 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -30,7 +30,7 @@ before_script: script: - ${BGD} server start & - sleep 1 # Allow server to boot - - ${BGD} bot --host=0.0.0.0 dummy & + - ${BGD} bot --host=0.0.0.0 --continuous dummy & - ${BGD} execute --host=0.0.0.0 request --wait-for-completion tests-debian-stretch: diff --git a/app/commands/cmd_bot.py b/app/commands/cmd_bot.py index c83d60ca2..1ac0f026f 100644 --- a/app/commands/cmd_bot.py +++ b/app/commands/cmd_bot.py @@ -43,15 +43,17 @@ from buildgrid._protos.build.bazel.remote.execution.v2 import remote_execution_p from google.protobuf import any_pb2 @click.group(short_help = 'Create a bot client') +@click.option('--continuous', is_flag=True) @click.option('--parent', default='bgd_test') @click.option('--number-of-leases', default=1) @click.option('--port', default='50051') @click.option('--host', default='localhost') @pass_context -def cli(context, host, port, number_of_leases, parent): +def cli(context, host, port, number_of_leases, parent, continuous): context.logger = logging.getLogger(__name__) context.logger.info("Starting on port {}".format(port)) + context.continuous = continuous context.channel = grpc.insecure_channel('{}:{}'.format(host, port)) context.number_of_leases = number_of_leases context.parent = parent @@ -71,7 +73,8 @@ def dummy(context): context=context, channel=context.channel, parent=context.parent, - number_of_leases=context.number_of_leases) + number_of_leases=context.number_of_leases, + continuous=context.continuous) except KeyboardInterrupt: pass @@ -105,7 +108,8 @@ def _work_buildbox(context, remote, port, server_cert, client_key, client_cert, context=context, channel=context.channel, parent=context.parent, - number_of_leases=context.number_of_leases) + number_of_leases=context.number_of_leases, + continuous=context.continuous) except KeyboardInterrupt: pass diff --git a/buildgrid/bot/bot.py b/buildgrid/bot/bot.py index 5dab86ae9..16d7c1bdd 100644 --- a/buildgrid/bot/bot.py +++ b/buildgrid/bot/bot.py @@ -39,33 +39,31 @@ class Bot(object): Creates a local BotSession. """ - def __init__(self, work, context, channel, parent, number_of_leases): + def __init__(self, work, context, channel, parent, number_of_leases, continuous=True): if not inspect.iscoroutinefunction(work): raise BotError("work function must be async") + print(type(context)) + self.interface = bot_interface.BotInterface(channel) self.logger = logging.getLogger(__name__) self._create_session(parent, number_of_leases) self._work_queue = queue.Queue(maxsize = number_of_leases) - try: - while True: - ## TODO: Leases independently finish - ## Allow leases to queue finished work independently instead - ## of waiting for all to finish - futures = [self._do_work(work, context, lease) for lease in self._get_work()] - if futures: - loop = asyncio.new_event_loop() - leases_complete, _ = loop.run_until_complete(asyncio.wait(futures)) - work_complete = [(lease.result().id, lease.result(),) for lease in leases_complete] - self._work_complete(work_complete) - loop.close() - self._update_bot_session() - time.sleep(2) - except Exception as e: - self.logger.error(e) - raise BotError(e) + while continuous: + ## TODO: Leases independently finish + ## Allow leases to queue finished work independently instead + ## of waiting for all to finish + futures = [self._do_work(work, context, lease) for lease in self._get_work()] + if futures: + loop = asyncio.new_event_loop() + leases_complete, _ = loop.run_until_complete(asyncio.wait(futures)) + work_complete = [(lease.result().id, lease.result(),) for lease in leases_complete] + self._work_complete(work_complete) + loop.close() + self._update_bot_session() + time.sleep(2) @property def bot_session(self): @@ -97,7 +95,6 @@ class Bot(object): def _get_work(self): while not self._work_queue.empty(): yield self._work_queue.get() - self._work_queue.task_done() def _work_complete(self, leases_complete): """ Bot updates itself with any completed work. diff --git a/tests/integration/bot_interface.py b/tests/integration/bot_interface.py new file mode 100644 index 000000000..a3c844b4e --- /dev/null +++ b/tests/integration/bot_interface.py @@ -0,0 +1,54 @@ +# Copyright (C) 2018 Codethink Limited +# +# 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. +# +# Authors: +# Finn Ball <finn.ball@codethink.co.uk> + +import copy +import grpc +import logging +import mock +import pytest +import uuid + +from buildgrid.bot import bot, bot_interface + +async def _work_dummy(context, lease): + return lease + +class ContextMock(): + def __init__(self): + self.logger = logging.getLogger(__name__) + +# GRPC context +@pytest.fixture +def context(): + yield ContextMock() + +# GRPC context +@pytest.fixture +def channel(): + yield mock.MagicMock(spec = grpc.insecure_channel('')) + +@pytest.fixture +def instance(channel): + yield bot.Bot(work=_work_dummy, + context=ContextMock(), + channel=channel, + parent='rach', + number_of_leases=1, + continuous=False) + +def test_create_job(instance): + instance.bot_session() -- GitLab