blob: c7dce0388375d09c6a0202fb3824b3a2577e3b27 [file] [log] [blame]
#!/usr/bin/env python
# Copyright 2018 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Tests for AppEngine Integration."""
import argparse
import logging
import os
import re
import sys
import factory_common # pylint: disable=unused-import
from cros.factory.utils import file_utils
from cros.factory.utils import process_utils
HOST_TEST_DIR = os.path.dirname(os.path.abspath(__file__))
HOST_APPENGINE_DIR = os.path.dirname(HOST_TEST_DIR)
HOST_FACTORY_DIR = os.path.abspath(
os.path.join(HOST_APPENGINE_DIR, '../../../..'))
HOST_DEPLOY_DIR = os.path.join(HOST_FACTORY_DIR, 'deploy')
GUEST_FACTORY_DIR = '/usr/src/cros/factory'
DEPLOY_SCRIPT = os.path.join(HOST_DEPLOY_DIR, 'cros_hwid_service.sh')
DEFAULT_DOCKER_IMAGE_NAME = 'appengine_integration:latest'
def _PrepareTests(test_names):
"""Lists test paths.
Args:
test_names: A list of test names to run. None for returning all tests.
Returns:
A list a test path in docker image.
"""
def _CanonicalizeTestName(test_name):
test_name = test_name if test_name.endswith('.py') else test_name + '.py'
test_path = os.path.join(HOST_APPENGINE_DIR, test_name)
if not os.path.isfile(test_path):
raise ValueError('Test %s not exists')
return test_path
def _HostToGuest(test_paths):
"""Transform test paths from host to guest."""
return [
path.replace(HOST_FACTORY_DIR, GUEST_FACTORY_DIR) for path in test_paths
]
def _ListAllTests():
return [
_CanonicalizeTestName(tn)
for tn in os.listdir(HOST_APPENGINE_DIR)
if os.path.isfile(os.path.join(HOST_APPENGINE_DIR, tn)) and
tn.endswith('_test.py')
]
if test_names:
return _HostToGuest([_CanonicalizeTestName(tn) for tn in test_names])
else:
return _HostToGuest(_ListAllTests())
def _BuildDockerImage():
"""Builds docker image and returns the image tag."""
out = process_utils.CheckOutput([DEPLOY_SCRIPT, 'build'], log=True)
return re.search(r'^Successfully tagged (\w+:\w+)', out,
re.MULTILINE).group(1)
def RunTest(image, test_names):
"""Runs the given tests.
Args:
image: A string for docker image name.
test_names: A list of test names to run.
Returns:
True if all tests pass.
"""
container_id = process_utils.CheckOutput(
['docker', 'run', '-d', '-it', image], log=True).strip()
failed_tests = []
for tn in test_names:
p = process_utils.Spawn(
['docker', 'exec', container_id, tn],
read_stdout=True,
read_stderr=True,
log=True)
if p.returncode != 0:
with open(file_utils.CreateTemporaryFile(), 'w') as f:
f.write('stdout:\n' + p.stdout_data)
f.write('\nstderr:\n' + p.stderr_data)
failed_tests.append((tn, f.name))
logging.info('[%s/%s] Passed',
len(test_names) - len(failed_tests), len(test_names))
for t in failed_tests:
logging.error('FAILED: %s', t)
process_utils.LogAndCheckCall(['docker', 'stop', container_id])
return not failed_tests
def main():
logging.getLogger().setLevel(int(os.environ.get('LOG_LEVEL') or logging.INFO))
parser = argparse.ArgumentParser(description='AppEngine Interation Test')
parser.add_argument(
'--no-build',
action='store_true',
help='Not building latest docker image, use default image.')
parser.add_argument('test_names', nargs='*', default=[])
args = parser.parse_args()
image = DEFAULT_DOCKER_IMAGE_NAME if args.no_build else _BuildDockerImage()
tests_to_run = _PrepareTests(args.test_names)
if not RunTest(image, tests_to_run):
sys.exit(1)
if __name__ == '__main__':
main()