diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 9cf55e562724..b7dd89dac083 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -212,8 +212,14 @@ Running System Tests $ python system_tests/clear_datastore.py - System tests can also be run against local `emulators`_ that mock - the production services. For example, to run the system tests - with the ``datastore`` emulator, first start the emulator and + the production services. To run the system tests with the + ``datastore`` emulator:: + + $ tox -e datastore-emulator + + This also requires that the ``gcloud`` command line tool is + installed. If you'd like to run them directly (outside of a + ``tox`` environment), first start the emulator and take note of the process ID:: $ gcloud beta emulators datastore start & diff --git a/scripts/datastore_emulator.py b/scripts/datastore_emulator.py new file mode 100644 index 000000000000..761abe7c4b50 --- /dev/null +++ b/scripts/datastore_emulator.py @@ -0,0 +1,65 @@ +# Copyright 2016 Google Inc. 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. + +"""Run datastore system tests locally with the datastore emulator. + +First makes system calls to spawn the datastore emulator and get +the local environment variables needed for it. Then calls the +datastore system tests. +""" + + +import os +import subprocess + +from gcloud.environment_vars import GCD_DATASET +from gcloud.environment_vars import GCD_HOST + + +_START_CMD = ('gcloud', 'beta', 'emulators', 'datastore', 'start') +_ENV_INIT_CMD = ('gcloud', 'beta', 'emulators', 'datastore', 'env-init') +_HOST_VAR_NAME = 'DATASTORE_HOST' +_DATASET_PREFIX = 'export ' + GCD_DATASET + '=' +_HOST_LINE_PREFIX = 'export ' + GCD_HOST + '=' + + +def main(): + """Spawn an emulator instance and run the datastore system tests.""" + # Ignore stdin and stdout, don't pollute the user's output with them. + proc_start = subprocess.Popen(_START_CMD, stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + try: + env_lines = subprocess.check_output( + _ENV_INIT_CMD).strip().split('\n') + dataset, = [line.split(_DATASET_PREFIX, 1)[1] for line in env_lines + if line.startswith(_DATASET_PREFIX)] + host, = [line.split(_HOST_LINE_PREFIX, 1)[1] for line in env_lines + if line.startswith(_HOST_LINE_PREFIX)] + # Set environment variables before running the system tests. + os.environ[GCD_DATASET] = dataset + os.environ[GCD_HOST] = host + os.environ['GCLOUD_NO_PRINT'] = 'true' + # Delay import until after environment variables are set. + from system_tests.run_system_test import run_module_tests + run_module_tests('datastore', + ignore_requirements=True) + finally: + # NOTE: This is mostly defensive. Since ``proc_start`` will be spawned + # by this current process, it should be killed when this process + # exits whether or not we kill it. + proc_start.kill() + + +if __name__ == '__main__': + main() diff --git a/tox.ini b/tox.ini index 31b8ba2789a5..5501e4586bff 100644 --- a/tox.ini +++ b/tox.ini @@ -89,3 +89,9 @@ basepython = commands = python {toxinidir}/scripts/attempt_system_tests.py passenv = {[testenv:system-tests]passenv} + +[testenv:datastore-emulator] +basepython = + python2.7 +commands = + python {toxinidir}/scripts/datastore_emulator.py