mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
Detect and fix environment tampering in tests.
This commit is contained in:
parent
99d328976d
commit
b8cb3f519b
3 changed files with 109 additions and 4 deletions
|
@ -17,13 +17,24 @@
|
|||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# ============================================================
|
||||
- name: python 2
|
||||
set_fact:
|
||||
python_suffix: ""
|
||||
when: ansible_python_version | version_compare('3', '<')
|
||||
|
||||
- name: python 3
|
||||
set_fact:
|
||||
python_suffix: "-py3"
|
||||
when: ansible_python_version | version_compare('3', '>=')
|
||||
|
||||
- include_vars: '{{ item }}'
|
||||
with_first_found:
|
||||
- files:
|
||||
- '{{ ansible_distribution }}-{{ ansible_distribution_major_version }}.yml'
|
||||
- '{{ ansible_os_family }}-{{ ansible_distribution_major_version }}.yml'
|
||||
- '{{ ansible_distribution }}.yml'
|
||||
- '{{ ansible_os_family }}.yml'
|
||||
- '{{ ansible_distribution }}-{{ ansible_distribution_major_version }}{{ python_suffix }}.yml'
|
||||
- '{{ ansible_os_family }}-{{ ansible_distribution_major_version }}{{ python_suffix }}.yml'
|
||||
- '{{ ansible_distribution }}{{ python_suffix }}.yml'
|
||||
- '{{ ansible_os_family }}{{ python_suffix }}.yml'
|
||||
- 'default{{ python_suffix }}.yml'
|
||||
paths: '../vars'
|
||||
|
||||
- name: install mysqldb_test rpm dependencies
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
mysql_service: 'mysql'
|
||||
|
||||
mysql_packages:
|
||||
- mysql-server
|
||||
- python3-mysqldb
|
||||
- bzip2
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
from __future__ import absolute_import, print_function
|
||||
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import tempfile
|
||||
|
@ -48,6 +49,8 @@ from lib.util import (
|
|||
make_dirs,
|
||||
is_shippable,
|
||||
is_binary_file,
|
||||
find_executable,
|
||||
raw_command,
|
||||
)
|
||||
|
||||
from lib.test import (
|
||||
|
@ -518,6 +521,10 @@ def command_integration_filtered(args, targets):
|
|||
|
||||
cloud_environment = get_cloud_environment(args, target)
|
||||
|
||||
original_environment = EnvironmentDescription()
|
||||
|
||||
display.info('>>> Environment Description\n%s' % original_environment, verbosity=3)
|
||||
|
||||
try:
|
||||
while tries:
|
||||
tries -= 1
|
||||
|
@ -538,11 +545,16 @@ def command_integration_filtered(args, targets):
|
|||
if cloud_environment:
|
||||
cloud_environment.on_failure(target, tries)
|
||||
|
||||
if not original_environment.validate(target.name, throw=False):
|
||||
raise
|
||||
|
||||
if not tries:
|
||||
raise
|
||||
|
||||
display.warning('Retrying test target "%s" with maximum verbosity.' % target.name)
|
||||
display.verbosity = args.verbosity = 6
|
||||
|
||||
original_environment.validate(target.name, throw=True)
|
||||
except:
|
||||
display.notice('To resume at this test target, use the option: --start-at %s' % target.name)
|
||||
|
||||
|
@ -1135,6 +1147,82 @@ def get_integration_remote_filter(args, targets):
|
|||
return exclude
|
||||
|
||||
|
||||
class EnvironmentDescription(object):
|
||||
"""Description of current running environment."""
|
||||
def __init__(self):
|
||||
"""Initialize snapshot of environment configuration."""
|
||||
versions = ['']
|
||||
versions += SUPPORTED_PYTHON_VERSIONS
|
||||
versions += list(set(v.split('.')[0] for v in SUPPORTED_PYTHON_VERSIONS))
|
||||
|
||||
python_paths = dict((v, find_executable('python%s' % v, required=False)) for v in sorted(versions))
|
||||
python_versions = dict((v, self.get_version([python_paths[v], '-V'])) for v in sorted(python_paths) if python_paths[v])
|
||||
|
||||
pip_paths = dict((v, find_executable('pip%s' % v, required=False)) for v in sorted(versions))
|
||||
pip_versions = dict((v, self.get_version([pip_paths[v], '--version'])) for v in sorted(pip_paths) if pip_paths[v])
|
||||
pip_interpreters = dict((v, self.get_shebang(pip_paths[v])) for v in sorted(pip_paths) if pip_paths[v])
|
||||
|
||||
self.data = dict(
|
||||
python_paths=python_paths,
|
||||
python_versions=python_versions,
|
||||
pip_paths=pip_paths,
|
||||
pip_versions=pip_versions,
|
||||
pip_interpreters=pip_interpreters,
|
||||
)
|
||||
|
||||
def __str__(self):
|
||||
"""
|
||||
:rtype: str
|
||||
"""
|
||||
return json.dumps(self.data, sort_keys=True, indent=4)
|
||||
|
||||
def validate(self, target_name, throw):
|
||||
"""
|
||||
:type target_name: str
|
||||
:type throw: bool
|
||||
:rtype: bool
|
||||
"""
|
||||
current = EnvironmentDescription()
|
||||
|
||||
original_json = str(self)
|
||||
current_json = str(current)
|
||||
|
||||
if original_json == current_json:
|
||||
return True
|
||||
|
||||
message = ('Test target "%s" has changed the test environment!\n'
|
||||
'If these changes are necessary, they must be reverted before the test finishes.\n'
|
||||
'>>> Original Environment\n'
|
||||
'%s\n'
|
||||
'>>> Current Environment\n'
|
||||
'%s' % (target_name, original_json, current_json))
|
||||
|
||||
if throw:
|
||||
raise ApplicationError(message)
|
||||
|
||||
display.error(message)
|
||||
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def get_version(command):
|
||||
"""
|
||||
:type command: list[str]
|
||||
:rtype: str
|
||||
"""
|
||||
stdout, stderr = raw_command(command, capture=True)
|
||||
return (stdout or '').strip() + (stderr or '').strip()
|
||||
|
||||
@staticmethod
|
||||
def get_shebang(path):
|
||||
"""
|
||||
:type path: str
|
||||
:rtype: str
|
||||
"""
|
||||
with open(path) as script_fd:
|
||||
return script_fd.readline()
|
||||
|
||||
|
||||
class NoChangesDetected(ApplicationWarning):
|
||||
"""Exception when change detection was performed, but no changes were found."""
|
||||
def __init__(self):
|
||||
|
|
Loading…
Reference in a new issue