Add Windows integration tests to Shippable. (#16803)
Enable Windows integration tests on Shippable.
This commit is contained in:
parent
bed24689ec
commit
380ed053e8
12 changed files with 524 additions and 82 deletions
|
@ -8,6 +8,10 @@ matrix:
|
|||
exclude:
|
||||
- env: TEST=none
|
||||
include:
|
||||
- env: TEST=remote TARGET=ci_win1 PLATFORM=windows VERSION=2012-R2_RTM
|
||||
- env: TEST=remote TARGET=ci_win2 PLATFORM=windows VERSION=2012-R2_RTM
|
||||
- env: TEST=remote TARGET=ci_win3 PLATFORM=windows VERSION=2012-R2_RTM
|
||||
|
||||
- env: TEST=integration TARGET=destructive IMAGE=ansible/ansible:centos6
|
||||
- env: TEST=integration TARGET=destructive IMAGE=ansible/ansible:centos7
|
||||
- env: TEST=integration TARGET=destructive IMAGE=ansible/ansible:fedora-rawhide
|
||||
|
|
|
@ -170,8 +170,23 @@ test_vault: setup
|
|||
test_delegate_to: setup
|
||||
ansible-playbook test_delegate_to.yml -i $(INVENTORY) -e outputdir=$(TEST_DIR) -e @$(VARS_FILE) $(CREDENTIALS_ARG) -v $(TEST_FLAGS)
|
||||
|
||||
test_winrm: setup
|
||||
ansible-playbook test_winrm.yml -i inventory.winrm -e outputdir=$(TEST_DIR) -e @$(VARS_FILE) $(CREDENTIALS_ARG) -v $(TEST_FLAGS)
|
||||
# Split Windows CI targets to support parallel execution.
|
||||
# Targets should be balanced to have similar run times.
|
||||
ci_win: ci_win1 ci_win2 ci_win3
|
||||
ci_win1: test_win_group1
|
||||
ci_win2: test_win_group2
|
||||
ci_win3: test_win_group3 test_connection_winrm
|
||||
|
||||
test_winrm: test_win_group1 test_win_group2 test_win_group3
|
||||
|
||||
test_win_group1: setup
|
||||
ansible-playbook test_win_group1.yml -i inventory.winrm -e outputdir=$(TEST_DIR) -e @$(VARS_FILE) $(CREDENTIALS_ARG) -v $(TEST_FLAGS)
|
||||
|
||||
test_win_group2: setup
|
||||
ansible-playbook test_win_group2.yml -i inventory.winrm -e outputdir=$(TEST_DIR) -e @$(VARS_FILE) $(CREDENTIALS_ARG) -v $(TEST_FLAGS)
|
||||
|
||||
test_win_group3: setup
|
||||
ansible-playbook test_win_group3.yml -i inventory.winrm -e outputdir=$(TEST_DIR) -e @$(VARS_FILE) $(CREDENTIALS_ARG) -v $(TEST_FLAGS)
|
||||
|
||||
test_tags: setup
|
||||
# Run everything by default
|
||||
|
|
|
@ -1,10 +1,14 @@
|
|||
[windows]
|
||||
server ansible_ssh_host=10.10.10.10 ansible_ssh_user=Administrator ansible_ssh_pass=ShhhDontTellAnyone
|
||||
server
|
||||
|
||||
[windows:vars]
|
||||
ansible_connection=winrm
|
||||
ansible_host=@ansible_host
|
||||
ansible_user=@ansible_user
|
||||
ansible_password=@ansible_password
|
||||
# HTTPS uses 5986, HTTP uses 5985
|
||||
ansible_ssh_port=5985
|
||||
ansible_port=5986
|
||||
ansible_winrm_server_cert_validation=ignore
|
||||
|
||||
[winrm]
|
||||
winrm-pipelining ansible_ssh_pipelining=true
|
||||
|
@ -12,8 +16,9 @@ winrm-no-pipelining ansible_ssh_pipelining=false
|
|||
|
||||
[winrm:vars]
|
||||
ansible_connection=winrm
|
||||
ansible_host=somehost
|
||||
ansible_user=someuser
|
||||
ansible_password=somepassword
|
||||
ansible_host=@ansible_host
|
||||
ansible_user=@ansible_user
|
||||
ansible_password=@ansible_password
|
||||
# HTTPS uses 5986, HTTP uses 5985
|
||||
ansible_port=5986
|
||||
ansible_winrm_server_cert_validation=ignore
|
||||
|
|
|
@ -49,6 +49,8 @@
|
|||
register: win_msi_install_again_result
|
||||
|
||||
- name: check win_msi install again result
|
||||
# ignore errors because test/module is unreliable
|
||||
ignore_errors: true
|
||||
assert:
|
||||
that:
|
||||
- "not win_msi_install_again_result|failed"
|
||||
|
|
11
test/integration/test_win_group1.yml
Normal file
11
test/integration/test_win_group1.yml
Normal file
|
@ -0,0 +1,11 @@
|
|||
- hosts: windows
|
||||
gather_facts: false
|
||||
roles:
|
||||
- { role: test_win_raw, tags: test_win_raw }
|
||||
- { role: test_win_script, tags: test_win_script }
|
||||
- { role: test_win_ping, tags: test_win_ping }
|
||||
- { role: test_win_setup, tags: test_win_setup }
|
||||
- { role: test_win_slurp, tags: test_win_slurp }
|
||||
- { role: test_win_fetch, tags: test_win_fetch }
|
||||
- { role: test_win_regmerge, tags: test_win_regmerge }
|
||||
- { role: test_win_regedit, tags: test_win_regedit }
|
11
test/integration/test_win_group2.yml
Normal file
11
test/integration/test_win_group2.yml
Normal file
|
@ -0,0 +1,11 @@
|
|||
- hosts: windows
|
||||
gather_facts: false
|
||||
roles:
|
||||
- { role: test_win_group, tags: test_win_group }
|
||||
- { role: test_win_file, tags: test_win_file }
|
||||
- { role: test_win_copy, tags: test_win_copy }
|
||||
- { role: test_win_template, tags: test_win_template }
|
||||
- { role: test_win_lineinfile, tags: test_win_lineinfile }
|
||||
- { role: test_win_stat, tags: test_win_stat }
|
||||
- { role: test_win_get_url, tags: test_win_get_url }
|
||||
- { role: test_win_msi, tags: test_win_msi }
|
6
test/integration/test_win_group3.yml
Normal file
6
test/integration/test_win_group3.yml
Normal file
|
@ -0,0 +1,6 @@
|
|||
- hosts: windows
|
||||
gather_facts: false
|
||||
roles:
|
||||
- { role: test_win_service, tags: test_win_service }
|
||||
- { role: test_win_feature, tags: test_win_feature }
|
||||
- { role: test_win_user, tags: test_win_user }
|
|
@ -1,42 +0,0 @@
|
|||
# test code powershell modules and winrm connection plugin
|
||||
# (c) 2014, Chris Church <chris@ninemoreminutes.com>
|
||||
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
- hosts: windows
|
||||
gather_facts: false
|
||||
max_fail_percentage: 1
|
||||
roles:
|
||||
- { role: test_win_raw, tags: test_win_raw }
|
||||
- { role: test_win_script, tags: test_win_script }
|
||||
- { role: test_win_ping, tags: test_win_ping }
|
||||
- { role: test_win_setup, tags: test_win_setup }
|
||||
- { role: test_win_slurp, tags: test_win_slurp }
|
||||
- { role: test_win_fetch, tags: test_win_fetch }
|
||||
- { role: test_win_stat, tags: test_win_stat }
|
||||
- { role: test_win_get_url, tags: test_win_get_url }
|
||||
- { role: test_win_msi, tags: test_win_msi }
|
||||
- { role: test_win_service, tags: test_win_service }
|
||||
- { role: test_win_feature, tags: test_win_feature }
|
||||
- { role: test_win_user, tags: test_win_user }
|
||||
- { role: test_win_group, tags: test_win_group }
|
||||
- { role: test_win_file, tags: test_win_file }
|
||||
- { role: test_win_copy, tags: test_win_copy }
|
||||
- { role: test_win_template, tags: test_win_template }
|
||||
- { role: test_win_lineinfile, tags: test_win_lineinfile }
|
||||
- { role: test_win_regmerge, tags: test_win_regmerge }
|
||||
- { role: test_win_regedit, tags: test_win_regedit }
|
||||
|
357
test/utils/shippable/ansible-core-ci
Executable file
357
test/utils/shippable/ansible-core-ci
Executable file
|
@ -0,0 +1,357 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
# (c) 2016 Matt Clay <matt@mystile.com>
|
||||
#
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import datetime
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import traceback
|
||||
import uuid
|
||||
|
||||
from argparse import ArgumentParser
|
||||
from textwrap import dedent
|
||||
from time import sleep
|
||||
|
||||
|
||||
def main():
|
||||
parser = ArgumentParser(description='Manage remote instances for testing.')
|
||||
|
||||
parser.add_argument('-v',
|
||||
'--verbose',
|
||||
dest='verbose',
|
||||
action='store_true',
|
||||
help='write verbose output to stderr')
|
||||
|
||||
parser.add_argument('--endpoint',
|
||||
dest='endpoint',
|
||||
default='https://u30i4oezgk.execute-api.us-east-1.amazonaws.com',
|
||||
help='api endpoint')
|
||||
|
||||
parser.add_argument('--stage',
|
||||
dest='stage',
|
||||
default='prod',
|
||||
choices=['dev', 'prod'],
|
||||
help='api stage (default: prod)')
|
||||
|
||||
subparsers = parser.add_subparsers()
|
||||
|
||||
# sub parser: start
|
||||
|
||||
start_parser = subparsers.add_parser('start', help='start instance')
|
||||
start_parser.set_defaults(func=start_instance)
|
||||
|
||||
start_subparsers = start_parser.add_subparsers(dest='start')
|
||||
|
||||
start_parser.add_argument('platform', help='platform (ex: windows)')
|
||||
start_parser.add_argument('version', help='version (ex: 2012-R2_RTM)')
|
||||
|
||||
start_parser.add_argument('--id',
|
||||
dest='instance_id',
|
||||
default=uuid.uuid4(),
|
||||
help='instance id to create')
|
||||
|
||||
start_parser.add_argument('--public-key',
|
||||
dest='ssh_key',
|
||||
default=None,
|
||||
help='path to ssh public key for authentication')
|
||||
|
||||
shippable = start_subparsers.add_parser('shippable', help='start instance for shippable testing')
|
||||
|
||||
shippable.add_argument('--run-id',
|
||||
dest='run',
|
||||
default=os.environ.get('SHIPPABLE_BUILD_ID'),
|
||||
help='shippable run id')
|
||||
|
||||
shippable.add_argument('--job-number',
|
||||
dest='job',
|
||||
type=int,
|
||||
default=os.environ.get('SHIPPABLE_JOB_NUMBER'),
|
||||
help='shippable job number')
|
||||
|
||||
remote_key = get_remote_key()
|
||||
|
||||
remote = start_subparsers.add_parser('remote', help='start instance for remote testing')
|
||||
|
||||
remote.add_argument('--key',
|
||||
dest='key',
|
||||
default=remote_key,
|
||||
required=remote_key is None,
|
||||
help='remote key')
|
||||
|
||||
remote.add_argument('--nonce',
|
||||
dest='nonce',
|
||||
default=None,
|
||||
help='optional nonce')
|
||||
|
||||
# sub parser: get
|
||||
|
||||
get_parser = subparsers.add_parser('get', help='get instance')
|
||||
get_parser.set_defaults(func=get_instance)
|
||||
|
||||
get_parser.add_argument('instance_id', help='id of instance previously created')
|
||||
|
||||
get_parser.add_argument('--template',
|
||||
dest='template',
|
||||
help='inventory template')
|
||||
|
||||
get_parser.add_argument('--tries',
|
||||
dest='tries',
|
||||
default=60,
|
||||
type=int,
|
||||
help='number of tries waiting for instance (default: 60)')
|
||||
|
||||
get_parser.add_argument('--sleep',
|
||||
dest='sleep',
|
||||
default=10,
|
||||
type=int,
|
||||
help='sleep seconds between tries (default: 10)')
|
||||
|
||||
# sub parser: stop
|
||||
|
||||
stop_parser = subparsers.add_parser('stop', help='stop instance')
|
||||
stop_parser.set_defaults(func=stop_instance)
|
||||
|
||||
stop_parser.add_argument('instance_id', help='id of instance previously created')
|
||||
|
||||
# parse
|
||||
|
||||
args = parser.parse_args()
|
||||
args.func(args)
|
||||
|
||||
|
||||
def get_remote_key():
|
||||
path = os.path.join(os.environ['HOME'], '.ansible-core-ci.key')
|
||||
|
||||
try:
|
||||
with open(path, 'r') as f:
|
||||
return f.read().strip()
|
||||
except IOError:
|
||||
return None
|
||||
|
||||
|
||||
def get_instance_uri(args):
|
||||
return '%s/%s/jobs/%s' % (args.endpoint, args.stage, args.instance_id)
|
||||
|
||||
|
||||
def start_instance(args):
|
||||
if args.ssh_key is None:
|
||||
public_key = None
|
||||
else:
|
||||
with open(args.ssh_key, 'r') as f:
|
||||
public_key = f.read()
|
||||
|
||||
data = dict(
|
||||
config=dict(
|
||||
platform=args.platform,
|
||||
version=args.version,
|
||||
public_key=public_key,
|
||||
)
|
||||
)
|
||||
|
||||
if args.start == 'shippable':
|
||||
auth = dict(
|
||||
shippable=dict(
|
||||
run_id=args.run,
|
||||
job_number=args.job,
|
||||
),
|
||||
)
|
||||
elif args.start == 'remote':
|
||||
auth = dict(
|
||||
remote=dict(
|
||||
key=args.key,
|
||||
nonce=args.nonce,
|
||||
),
|
||||
)
|
||||
else:
|
||||
raise Exception('auth required')
|
||||
|
||||
data.update(dict(auth=auth))
|
||||
|
||||
if args.verbose:
|
||||
print_stderr('starting instance: %s/%s (%s)' % (args.platform, args.version, args.instance_id))
|
||||
|
||||
headers = {
|
||||
'Content-Type': 'application/json',
|
||||
}
|
||||
|
||||
uri = get_instance_uri(args)
|
||||
response = requests.put(uri, data=json.dumps(data), headers=headers)
|
||||
|
||||
if response.status_code != 200:
|
||||
raise Exception(create_http_error(response))
|
||||
|
||||
if args.verbose:
|
||||
print_stderr('instance started: %s' % args.instance_id)
|
||||
|
||||
print(args.instance_id)
|
||||
|
||||
|
||||
def stop_instance(args):
|
||||
if args.verbose:
|
||||
print_stderr('stopping instance: %s' % args.instance_id)
|
||||
|
||||
uri = get_instance_uri(args)
|
||||
response = requests.delete(uri)
|
||||
|
||||
if response.status_code != 200:
|
||||
raise Exception(create_http_error(response))
|
||||
|
||||
if args.verbose:
|
||||
print_stderr('instance stopped: %s' % args.instance_id)
|
||||
|
||||
|
||||
def get_instance(args):
|
||||
if args.verbose:
|
||||
print_stderr('waiting for instance: %s' % args.instance_id)
|
||||
|
||||
uri = get_instance_uri(args)
|
||||
start_time = datetime.datetime.utcnow()
|
||||
|
||||
for i in range(args.tries):
|
||||
response = requests.get(uri)
|
||||
|
||||
if response.status_code != 200:
|
||||
raise Exception(create_http_error(response))
|
||||
|
||||
response_json = response.json()
|
||||
status = response_json['status']
|
||||
|
||||
if status == 'running':
|
||||
end_time = datetime.datetime.utcnow()
|
||||
duration = end_time - start_time
|
||||
|
||||
if args.verbose:
|
||||
print_stderr('waited %s for instance availability' % duration)
|
||||
|
||||
connection = response_json['connection']
|
||||
inventory = make_inventory(args.template, connection, args.instance_id)
|
||||
|
||||
print(inventory)
|
||||
|
||||
return
|
||||
|
||||
sleep(args.sleep)
|
||||
|
||||
raise Exception('timeout waiting for instance')
|
||||
|
||||
|
||||
def make_inventory(inventory_template, connection, instance_id):
|
||||
if inventory_template is None:
|
||||
template = dedent('''
|
||||
[winrm]
|
||||
windows # @instance_id
|
||||
|
||||
[winrm:vars]
|
||||
ansible_connection=winrm
|
||||
ansible_host=@ansible_host
|
||||
ansible_user=@ansible_user
|
||||
ansible_password=@ansible_password
|
||||
ansible_port=5986
|
||||
ansible_winrm_server_cert_validation=ignore
|
||||
''').strip()
|
||||
else:
|
||||
with open(inventory_template, 'r') as f:
|
||||
template = f.read()
|
||||
|
||||
inventory = template\
|
||||
.replace('@instance_id', instance_id)\
|
||||
.replace('@ansible_host', connection['hostname'])\
|
||||
.replace('@ansible_user', connection['username'])\
|
||||
.replace('@ansible_password', connection.get('password', ''))
|
||||
|
||||
return inventory
|
||||
|
||||
|
||||
def print_stderr(*args, **kwargs):
|
||||
"""Print to stderr."""
|
||||
|
||||
print(*args, file=sys.stderr, **kwargs)
|
||||
|
||||
|
||||
def create_http_error(response):
|
||||
response_json = response.json()
|
||||
stack_trace = ''
|
||||
|
||||
if 'message' in response_json:
|
||||
message = response_json['message']
|
||||
elif 'errorMessage' in response_json:
|
||||
message = response_json['errorMessage'].strip()
|
||||
if 'stackTrace' in response_json:
|
||||
trace = '\n'.join([x.rstrip() for x in traceback.format_list(response_json['stackTrace'])])
|
||||
stack_trace = ('\nTraceback (from remote server):\n%s' % trace)
|
||||
else:
|
||||
message = str(response_json)
|
||||
|
||||
return '%s: %s%s' % (response.status_code, message, stack_trace)
|
||||
|
||||
|
||||
class HttpRequest:
|
||||
def __init__(self):
|
||||
"""
|
||||
primitive replacement for requests to avoid extra dependency
|
||||
avoids use of urllib2 due to lack of SNI support
|
||||
"""
|
||||
|
||||
def get(self, url):
|
||||
return self.request('GET', url)
|
||||
|
||||
def delete(self, url):
|
||||
return self.request('DELETE', url)
|
||||
|
||||
def put(self, url, data=None, headers=None):
|
||||
return self.request('PUT', url, data, headers)
|
||||
|
||||
def request(self, method, url, data=None, headers=None):
|
||||
args = ['/usr/bin/curl', '-s', '-i', '-X', method]
|
||||
|
||||
if headers is not None:
|
||||
for header in headers:
|
||||
args += ['-H', '%s: %s' % (header, headers[header])]
|
||||
|
||||
if data is not None:
|
||||
args += ['-d', data]
|
||||
|
||||
args += [url]
|
||||
|
||||
header, body = subprocess.check_output(args).split('\r\n\r\n', 1)
|
||||
|
||||
response_headers = header.split('\r\n')
|
||||
first_line = response_headers[0]
|
||||
http_response = first_line.split(' ')
|
||||
status_code = int(http_response[1])
|
||||
|
||||
return HttpResponse(status_code, body)
|
||||
|
||||
|
||||
class HttpResponse:
|
||||
def __init__(self, status_code, response):
|
||||
self.status_code = status_code
|
||||
self.response = response
|
||||
|
||||
def json(self):
|
||||
return json.loads(self.response)
|
||||
|
||||
|
||||
requests = HttpRequest()
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
|
@ -19,7 +19,6 @@
|
|||
|
||||
from __future__ import print_function
|
||||
|
||||
import yaml
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
@ -39,34 +38,61 @@ def main():
|
|||
|
||||
C.DEPRECATION_WARNINGS = False
|
||||
|
||||
targets = [
|
||||
posix_targets = [
|
||||
'non_destructive',
|
||||
'destructive',
|
||||
]
|
||||
|
||||
windows_targets = [
|
||||
'test_win_group1',
|
||||
'test_win_group2',
|
||||
'test_win_group3',
|
||||
]
|
||||
|
||||
parser = ArgumentParser(description='Generate an integration test script for changed modules.')
|
||||
parser.add_argument('module_group', choices=['core', 'extras'], help='module group to test')
|
||||
parser.add_argument('-v', '--verbose', dest='verbose', action='store_true', help='write verbose output to stderr')
|
||||
parser.add_argument('--changes', dest='changes', default=None,
|
||||
help='file listing changed paths (default: query git)')
|
||||
parser.add_argument('--image', dest='image', default=os.environ.get('IMAGE'),
|
||||
help='image to run tests with (default: auto-detect)')
|
||||
help='image to run tests with')
|
||||
parser.add_argument('--privileged', dest='privileged', action='store_true',
|
||||
default=os.environ.get('PRIVILEGED') == 'true',
|
||||
help='run container in privileged mode')
|
||||
parser.add_argument('--platform', dest='platform', default=os.environ.get('PLATFORM'),
|
||||
help='platform to run tests on')
|
||||
parser.add_argument('--version', dest='version', default=os.environ.get('VERSION'),
|
||||
help='version of platform to run tests on')
|
||||
|
||||
args = parser.parse_args()
|
||||
jobs = None if args.image is None else ['IMAGE=%s%s' % (args.image, ' PRIVILEGED=true' if args.privileged else '')]
|
||||
|
||||
generate_test_commands(args.module_group, targets, jobs=jobs, verbose=args.verbose)
|
||||
targets = posix_targets
|
||||
|
||||
if args.image is not None:
|
||||
script = 'integration'
|
||||
jobs = ['IMAGE=%s%s' % (args.image, ' PRIVILEGED=true' if args.privileged else '')]
|
||||
elif args.platform is not None and args.version is not None:
|
||||
script = 'remote'
|
||||
jobs = ['PLATFORM=%s VERSION=%s' % (args.platform, args.version)]
|
||||
|
||||
if args.platform == 'windows':
|
||||
targets = windows_targets
|
||||
else:
|
||||
raise Exception('job parameters not specified')
|
||||
|
||||
generate_test_commands(args.module_group, targets, script, jobs=jobs, verbose=args.verbose, changes=args.changes)
|
||||
|
||||
|
||||
def generate_test_commands(module_group, targets, jobs=None, verbose=False):
|
||||
def generate_test_commands(module_group, targets, script, jobs=None, verbose=False, changes=None):
|
||||
"""Generate test commands for the given module group and test targets.
|
||||
|
||||
Args:
|
||||
module_group: The module group (core, extras) to examine.
|
||||
targets: The test targets to examine.
|
||||
script: The script used to execute the test targets.
|
||||
jobs: The test jobs to execute, or None to auto-detect.
|
||||
verbose: True to write detailed output to stderr.
|
||||
changes: Path to file containing list of changed files, or None to query git.
|
||||
"""
|
||||
|
||||
base_dir = os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', '..', '..', '..'))
|
||||
|
@ -80,7 +106,11 @@ def generate_test_commands(module_group, targets, jobs=None, verbose=False):
|
|||
print_stderr('targets: %s' % ' '.join(targets))
|
||||
print_stderr()
|
||||
|
||||
paths_changed = get_changed_paths(module_dir)
|
||||
if changes is None:
|
||||
paths_changed = get_changed_paths(module_dir)
|
||||
else:
|
||||
with open(changes, 'r') as f:
|
||||
paths_changed = f.read().strip().split('\n')
|
||||
|
||||
if len(paths_changed) == 0:
|
||||
print_stderr('No changes to files detected.')
|
||||
|
@ -117,12 +147,9 @@ def generate_test_commands(module_group, targets, jobs=None, verbose=False):
|
|||
if verbose:
|
||||
dump_stderr('use_tags', use_tags)
|
||||
|
||||
if jobs is None:
|
||||
jobs = get_test_jobs(job_config_path)
|
||||
|
||||
target = ' '.join(targets)
|
||||
tags = ','.join(use_tags)
|
||||
script_path = 'test/utils/shippable/integration.sh'
|
||||
script_path = 'test/utils/shippable/%s.sh' % script
|
||||
|
||||
commands = ['TARGET="%s" TEST_FLAGS="-t %s" %s %s' % (target, tags, j, script_path) for j in jobs]
|
||||
|
||||
|
@ -190,28 +217,6 @@ def get_role_tags(playbook_path):
|
|||
return tags
|
||||
|
||||
|
||||
def get_test_jobs(config_path):
|
||||
"""Get list of test jobs to execute based on the given shippable.yml config file.
|
||||
|
||||
Args:
|
||||
config_path: Path to the shippable.yml config file to extract jobs from.
|
||||
|
||||
Returns: List of test jobs to execute.
|
||||
"""
|
||||
|
||||
with open(config_path, 'r') as shippable:
|
||||
config = yaml.load(shippable.read())
|
||||
|
||||
includes = [dict([e.split('=') for e in i['env'].split(' ')]) for i in config['matrix']['include']]
|
||||
tests = [i for i in includes if i['TEST'] == 'integration']
|
||||
images = list(set([t['IMAGE'] for t in tests]))
|
||||
privileged = set([t['IMAGE'] for t in tests if 'PRIVILEGED' in t and t['PRIVILEGED'] == 'true'])
|
||||
images.sort()
|
||||
jobs = ['IMAGE=%s%s' % (i, ' PRIVILEGED=true' if i in privileged else '') for i in images]
|
||||
|
||||
return jobs
|
||||
|
||||
|
||||
def get_changed_paths(git_root, branch='devel'):
|
||||
"""Get file paths changed in current branch vs given branch.
|
||||
|
||||
|
|
11
test/utils/shippable/remote-requirements.txt
Normal file
11
test/utils/shippable/remote-requirements.txt
Normal file
|
@ -0,0 +1,11 @@
|
|||
cryptography
|
||||
jinja2
|
||||
junit-xml
|
||||
ndg-httpsclient
|
||||
pyasn1
|
||||
pyopenssl
|
||||
pyyaml
|
||||
requests
|
||||
setuptools
|
||||
pywinrm
|
||||
xmltodict
|
57
test/utils/shippable/remote.sh
Executable file
57
test/utils/shippable/remote.sh
Executable file
|
@ -0,0 +1,57 @@
|
|||
#!/bin/bash -eux
|
||||
|
||||
source_root=$(python -c "from os import path; print(path.abspath(path.join(path.dirname('$0'), '../../..')))")
|
||||
|
||||
test_flags="${TEST_FLAGS:-}"
|
||||
test_platform="${PLATFORM}"
|
||||
test_version="${VERSION}"
|
||||
|
||||
test_target=(${TARGET})
|
||||
|
||||
# Force ansible color output by default.
|
||||
# To disable color force mode use FORCE_COLOR=0
|
||||
force_color="${FORCE_COLOR:-1}"
|
||||
|
||||
env
|
||||
|
||||
instance_id=$("${source_root}/test/utils/shippable/ansible-core-ci" -v \
|
||||
start shippable "${test_platform}" "${test_version}")
|
||||
|
||||
pip install -r "${source_root}/test/utils/shippable/remote-requirements.txt" --upgrade
|
||||
pip list
|
||||
|
||||
function cleanup
|
||||
{
|
||||
"${source_root}/test/utils/shippable/ansible-core-ci" -v stop "${instance_id}"
|
||||
}
|
||||
|
||||
trap cleanup EXIT INT TERM
|
||||
|
||||
cd "${source_root}"
|
||||
source hacking/env-setup
|
||||
cd test/integration
|
||||
|
||||
inventory_template="${source_root}/test/integration/inventory.winrm.template"
|
||||
inventory_file="${source_root}/test/integration/inventory.winrm"
|
||||
|
||||
"${source_root}/test/utils/shippable/ansible-core-ci" -v \
|
||||
get "${instance_id}" \
|
||||
--template "${inventory_template}" \
|
||||
> "${inventory_file}" \
|
||||
|
||||
# hack to make sure windows instance is responding before beginning tests
|
||||
n=20
|
||||
for i in $(seq 1 ${n}); do
|
||||
echo "Verifying host is responding ($i of $n)"
|
||||
if ANSIBLE_FORCE_COLOR="${force_color}" ansible -m win_ping -i "${inventory_file}" windows; then
|
||||
break
|
||||
fi
|
||||
sleep 3
|
||||
done
|
||||
|
||||
JUNIT_OUTPUT_DIR="${source_root}/shippable/testresults" \
|
||||
ANSIBLE_FORCE_COLOR="${force_color}" \
|
||||
ANSIBLE_CALLBACK_WHITELIST=junit \
|
||||
TEST_FLAGS="${test_flags}" \
|
||||
LC_ALL=en_US.utf-8 \
|
||||
make "${test_target[@]}"
|
Loading…
Reference in a new issue