You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
o3de/Tests/shared/screenshot_utils.py

204 lines
10 KiB
Python

"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
import os
import botocore.exceptions
import string
import boto3
from test_tools.shared.file_utils import move_file
import test_tools.launchers.phase as phase
import shared.s3_utils as s3_utils
from test_tools.shared.remote_console_commands import get_screenshot_command
from test_tools.shared.waiter import wait_for
from test_tools import HOST_PLATFORM
from test_tools.shared.images.qssim import qssim as compare_screenshots
from test_tools.shared.launcher_testlib import retry_console_command
def take_screenshot(remote_console_instance, launcher, screenshot_name):
"""
Takes an in game screenshot using the remote console instance passed in, validates that the screenshot exists
and then renames that screenshot to something defined by the user of this function.
:param remote_console_instance: Remote console instance that is attached to a specific launcher instance
:param launcher: Launcher instance so we can use the file exists functionality provided by test_tools
:param screenshot_name: Name of the screenshot
:return: None
"""
get_screenshot_command(remote_console_instance)
screenshot_path = os.path.join(launcher.workspace.release.paths.platform_cache(), 'user', 'screenshots')
launcher.run(phase.FileExistsPhase(os.path.join(screenshot_path, 'screenshot0000.jpg')))
wait_for(lambda: rename_screenshot(screenshot_path, screenshot_name),
timeout=120,
exc=AssertionError('Screenshot at path:{} and with name:{} is still in use.'.format(screenshot_path, screenshot_name)))
def rename_screenshot(screenshot_path, screenshot_name):
"""
Tries to rename the screenshot when the file is done being written to
:param screenshot_path: Path to the Screenshot folder
:param screenshot_name: Name we wish to change the screenshot to
:return: True when operation is completed, False if the file is still in use
"""
try:
print 'Trying to rename {} to {}.'.format(os.path.join(screenshot_path, 'screenshot0000.jpg'), os.path.join(screenshot_path, '{}.jpg'.format(screenshot_name)))
os.rename(os.path.join(screenshot_path, 'screenshot0000.jpg'),
os.path.join(screenshot_path, '{}.jpg'.format(screenshot_name)))
return True
except OSError as e:
print ('Found error {0} when trying to rename screenshot. {1}'.format(str(e), str(e.message)))
return False
def move_screenshots(screenshot_path, file_type, logs_path):
"""
Moves screenshots of a specific file type to the flume location so we can gather all of the screenshots we took.
:param screenshot_path: Path to the screenshot folder
:param file_type: Types of Files to look for. IE .jpg, .tif, etc
:param logs_path: Path where flume gathers logs to be upload
"""
for file_name in os.listdir(screenshot_path):
if file_name.endswith(file_type):
move_file(screenshot_path, logs_path, file_name)
def screenshot_command(remote_console_instance, command_to_run, expected_log_line):
"""
This is just a helper function to help send and validate against screenshot console commands.
:param remote_console_instance: Remote console instance
:param command_to_run: The Screenshot command that you wish to run
:param expected_log_line: The console log line to expect in order to set the event to true
:return:
"""
return retry_console_command(remote_console_instance, command_to_run, expected_log_line)
def get_screenshot_command_with_retries(remote_console_instance):
"""
Used for an in-game screenshot
:param remote_console_instance: Remote console instance
:return: None
"""
if (HOST_PLATFORM == 'win_x64'):
command = 'Screenshot: @user@\screenshots/'
else:
command = 'Screenshot: @user@/screenshots/'
wait_for(lambda: screenshot_command(remote_console_instance, 'r_GetScreenShot 1', command), timeout=240,
exc=AssertionError('Screenshot command failed'))
def take_screenshot_with_retries(remote_console_instance, launcher, screenshot_name):
"""
Takes an in game screenshot using the remote console instance passed in, validates that the screenshot exists
and then renames that screenshot to something defined by the user of this function.
:param remote_console_instance: Remote console instance that is attached to a specific launcher instance
:param launcher: Launcher instance so we can use the file exists functionality provided by test_tools
:param screenshot_name: Name of the screenshot
:return: None
"""
get_screenshot_command_with_retries(remote_console_instance)
screenshot_path = os.path.join(launcher.workspace.release.paths.platform_cache(), 'user', 'screenshots')
launcher.run(phase.FileExistsPhase(os.path.join(screenshot_path, 'screenshot0000.jpg')))
wait_for(lambda: rename_screenshot(screenshot_path, screenshot_name),
timeout=120,
exc=AssertionError('Screenshot taken is still in use'))
def compare_golden_image(similarity_threshold, screenshot, screenshot_path, golden_image_name,
golden_image_path=None):
"""
This function assumes that your golden image filename contains the same base screenshot name and the word "golden"
ex. pc_gamelobby_golden
:param similarity_threshold: A float from 0.0 - 1.0 that determines how similar images must be or an asserts
:param screenshot: A string that is the full name of the screenshot (ex. 'gamelobby_host.jpg')
:param screenshot_path: A string that contains the path to the screenshots
:param golden_image_path: A string that contains the path to the golden images, defaults to the screenshot_path
:return:
"""
if golden_image_path is None:
golden_image_path = screenshot_path
mean_similarity = compare_screenshots('{}\{}'.format(screenshot_path, screenshot),
'{}\{}'.format(golden_image_path, golden_image_name))
assert mean_similarity > similarity_threshold, \
'{} screenshot comparison failed! Mean similarity value is: {}'\
.format(screenshot, mean_similarity)
def take_screenshot_and_compare(remote_console, launcher, screenshot, similarity_threshold,
golden_image_name, screenshot_path=None, file_type='.jpg'):
"""
Takes a screenshot and compares it with its golden image. This utilizes the take_screenshot_with_retries function
which is only used for PC. There are some assumptions with the golden image naming convention that is explained in
the compare_golden_image function. This also assumes it is a jpg file.
This function enforces a naming convention such that the golden image and screenshot share part of the same name.
Also, the screenshot will be appended with the screenshot_key as shown below.
The screenshot name will be screenshot_base + screenshot_key + filetype
(ex. 'gamelobby_host.jpg', 'MultiplayerSampleClient_1.png')
:param screenshot_base: A string that is the base name of the screenshot (ex. 'gamelobby')
:param screenshot_key: A string that acts as a key identifier for the screenshot.
:param similarity_threshold: A float from 0.0 - 1.0 that determines how similar images must be or it asserts
:param screenshot_path: A string for the screenshot path. Defaults to user/screenshots
:param file_type: A string for the screenshot filetype. Defaults to '.jpg'
:return:
"""
if screenshot_path is None:
screenshot_path = r'{}\user\screenshots'.format(launcher.workspace.release.paths.platform_cache())
take_screenshot_with_retries(remote_console, launcher, screenshot)
compare_golden_image(similarity_threshold, '{}{}'.format(screenshot, file_type),
screenshot_path, golden_image_name)
def download_qa_golden_images(project_name, destination_dir, platform):
"""
Downloads the golden images for a specified project from s3. The project_name, platform, and filetype are used to
filter which images will be downloaded as the golden images.
https://s3.console.aws.amazon.com/s3/buckets/ly-qae-jenkins-configs/golden-images/?region=us-west-1&tab=overview
:param project_name: a string of the project name of the folder in s3. ex: 'MultiplayerSample'
:param destination_dir: a string of where the images will be downloaded to
:param platform: a string for the platform type ('pc', 'android', 'ios', 'darwin')
:param filetype: a string for the file type. ex: '.jpg', '.png'
:return:
"""
bucket_name = 'ly-qae-jenkins-configs'
path = 'golden-images/{}/{}/'.format(project_name, platform)
if not s3_utils.key_exists_in_bucket(bucket_name, path):
raise s3_utils.KeyDoesNotExistError("Key '{}' does not exist in S3 bucket {}".format(path, bucket_name))
for image in s3_utils.s3.Bucket(bucket_name).objects.filter(Prefix=path):
file_name = string.replace(image.key, path, '')
if file_name != '':
s3_utils.download_from_bucket(bucket_name, image.key, destination_dir, file_name)
def prepare_for_screenshot_compare(remote_console_instance):
"""
Prepares launcher for screenshot comparison. Removes any debug text and antialiasing that may result in interference
with the comparison.
:param remote_console_instance: Remote console instance that is attached to a specific launcher instance
:return:
"""
wait_for(lambda: retry_console_command(remote_console_instance, 'r_displayinfo 0',
'$3r_DisplayInfo = $60 $5[DUMPTODISK, RESTRICTEDMODE]$4'), timeout=120)
wait_for(lambda: retry_console_command(remote_console_instance, 'r_antialiasingmode 0',
'$3r_AntialiasingMode = $60 $5[]$4'), timeout=120)