Merge branch 'main' into limit_max_scale

main
greerdv 5 years ago
commit 10ab7666db

@ -1,709 +0,0 @@
#!/usr/bin/env groovy
/*
* 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.
*
*/
PIPELINE_CONFIG_FILE = 'AutomatedReview/lumberyard.json'
INCREMENTAL_BUILD_SCRIPT_PATH = 'scripts/build/bootstrap/incremental_build_util.py'
EMPTY_JSON = readJSON text: '{}'
ENGINE_REPOSITORY_NAME = 'o3de'
def pipelineProperties = []
def pipelineParameters = [
// Build/clean Parameters
// The CLEAN_OUTPUT_DIRECTORY is used by ci_build scripts. Creating the parameter here passes it as an environment variable to jobs and is consumed that way
booleanParam(defaultValue: false, description: 'Deletes the contents of the output directory before building. This will cause a \"clean\" build. NOTE: does not imply CLEAN_ASSETS', name: 'CLEAN_OUTPUT_DIRECTORY'),
booleanParam(defaultValue: false, description: 'Deletes the contents of the output directories of the AssetProcessor before building.', name: 'CLEAN_ASSETS'),
booleanParam(defaultValue: false, description: 'Deletes the contents of the workspace and forces a complete pull.', name: 'CLEAN_WORKSPACE'),
booleanParam(defaultValue: false, description: 'Recreates the volume used for the workspace. The volume will be created out of a snapshot taken from main.', name: 'RECREATE_VOLUME'),
string(defaultValue: '', description: 'Filters and overrides the list of jobs to run for each of the below platforms (comma-separated). Can\'t be used during a pull request.', name: 'JOB_LIST_OVERRIDE'),
// Pull Request Parameters
string(defaultValue: '', description: '', name: 'DESTINATION_BRANCH'),
string(defaultValue: '', description: '', name: 'DESTINATION_COMMIT'),
string(defaultValue: '', description: '', name: 'PULL_REQUEST_ID'),
string(defaultValue: '', description: '', name: 'REPOSITORY_NAME'),
string(defaultValue: '', description: '', name: 'SOURCE_BRANCH'),
string(defaultValue: '', description: '', name: 'SOURCE_COMMIT')
]
def palSh(cmd, lbl = '', winSlashReplacement = true) {
if (env.IS_UNIX) {
sh label: lbl,
script: cmd
} else if (winSlashReplacement) {
bat label: lbl,
script: cmd.replace('/','\\')
} else {
bat label: lbl,
script: cmd
}
}
def palMkdir(path) {
if (env.IS_UNIX) {
sh label: "Making directories ${path}",
script: "mkdir -p ${path}"
} else {
def win_path = path.replace('/','\\')
bat label: "Making directories ${win_path}",
script: "mkdir ${win_path}."
}
}
def palRm(path) {
if (env.IS_UNIX) {
sh label: "Removing ${path}",
script: "rm ${path}"
} else {
def win_path = path.replace('/','\\')
bat label: "Removing ${win_path}",
script: "del ${win_path}"
}
}
def palRmDir(path) {
if (env.IS_UNIX) {
sh label: "Removing ${path}",
script: "rm -rf ${path}"
} else {
def win_path = path.replace('/','\\')
bat label: "Removing ${win_path}",
script: "rd /s /q ${win_path}"
}
}
def IsJobEnabled(buildTypeMap, pipelineName, platformName) {
def job_list_override = params.JOB_LIST_OVERRIDE.tokenize(',')
if(params.PULL_REQUEST_ID) { // dont allow pull requests to filter platforms/jobs
if(buildTypeMap.value.TAGS) {
return buildTypeMap.value.TAGS.contains(pipelineName)
}
} else if (!job_list_override.isEmpty()) {
return params[platformName] && job_list_override.contains(buildTypeMap.key);
} else {
if (params[platformName]) {
if(buildTypeMap.value.TAGS) {
return buildTypeMap.value.TAGS.contains(pipelineName)
}
}
}
return false
}
def GetRunningPipelineName(JENKINS_JOB_NAME) {
// If the job name has an underscore
def job_parts = JENKINS_JOB_NAME.tokenize('/')[0].tokenize('_')
if (job_parts.size() > 1) {
return [job_parts.take(job_parts.size() - 1).join('_'), job_parts[job_parts.size()-1]]
}
return [job_parts[0], 'default']
}
@NonCPS
def RegexMatcher(str, regex) {
def matcher = (str =~ regex)
return matcher ? matcher.group(1) : null
}
def LoadPipelineConfig(String pipelineName, String branchName, String scmType) {
echo 'Loading pipeline config'
if (scmType == 'codecommit') {
PullFilesFromGit(PIPELINE_CONFIG_FILE, branchName, true, ENGINE_REPOSITORY_NAME)
}
def pipelineConfig = {}
pipelineConfig = readJSON file: PIPELINE_CONFIG_FILE
palRm(PIPELINE_CONFIG_FILE)
pipelineConfig.platforms = EMPTY_JSON
// Load the pipeline configs per platform
pipelineConfig.PIPELINE_CONFIGS.each { pipeline_config ->
def platform_regex = pipeline_config.replace('.','\\.').replace('*', '(.*)')
if (!env.IS_UNIX) {
platform_regex = platform_regex.replace('/','\\\\')
}
echo "Downloading platform pipeline configs ${pipeline_config}"
if (scmType == 'codecommit') {
PullFilesFromGit(pipeline_config, branchName, false, ENGINE_REPOSITORY_NAME)
}
echo "Searching platform pipeline configs in ${pipeline_config} using ${platform_regex}"
for (pipeline_config_path in findFiles(glob: pipeline_config)) {
echo "\tFound platform pipeline config ${pipeline_config_path}"
def platform = RegexMatcher(pipeline_config_path, platform_regex)
if(platform) {
pipelineConfig.platforms[platform] = EMPTY_JSON
pipelineConfig.platforms[platform].PIPELINE_ENV = readJSON file: pipeline_config_path.toString()
}
palRm(pipeline_config_path.toString())
}
}
// Load the build configs
pipelineConfig.BUILD_CONFIGS.each { build_config ->
def platform_regex = build_config.replace('.','\\.').replace('*', '(.*)')
if (!env.IS_UNIX) {
platform_regex = platform_regex.replace('/','\\\\')
}
echo "Downloading configs ${build_config}"
if (scmType == 'codecommit') {
PullFilesFromGit(build_config, branchName, false, ENGINE_REPOSITORY_NAME)
}
echo "Searching configs in ${build_config} using ${platform_regex}"
for (build_config_path in findFiles(glob: build_config)) {
echo "\tFound config ${build_config_path}"
def platform = RegexMatcher(build_config_path, platform_regex)
if(platform) {
pipelineConfig.platforms[platform].build_types = readJSON file: build_config_path.toString()
}
}
}
return pipelineConfig
}
def GetSCMType() {
def gitUrl = scm.getUserRemoteConfigs()[0].getUrl()
if (gitUrl ==~ /https:\/\/git-codecommit.*/) {
return 'codecommit'
} else if (gitUrl ==~ /https:\/\/github.com.*/) {
return 'github'
}
return 'unknown'
}
def GetBuildEnvVars(Map platformEnv, Map buildTypeEnv, String pipelineName) {
def envVarMap = [:]
platformPipelineEnv = platformEnv['ENV'] ?: [:]
platformPipelineEnv.each { var ->
envVarMap[var.key] = var.value
}
platformEnvOverride = platformEnv['PIPELINE_ENV_OVERRIDE'] ?: [:]
platformPipelineEnvOverride = platformEnvOverride[pipelineName] ?: [:]
platformPipelineEnvOverride.each { var ->
envVarMap[var.key] = var.value
}
buildTypeEnv.each { var ->
// This may override the above one if there is an entry defined by the job
envVarMap[var.key] = var.value
}
// Environment that only applies to to Jenkins tweaks.
// For 3rdParty downloads, we store them in the EBS volume so we can reuse them across node
// instances. This allow us to scale up and down without having to re-download 3rdParty
envVarMap['LY_PACKAGE_DOWNLOAD_CACHE_LOCATION'] = "${envVarMap['WORKSPACE']}/3rdParty/downloaded_packages"
envVarMap['LY_PACKAGE_UNPACK_LOCATION'] = "${envVarMap['WORKSPACE']}/3rdParty/packages"
return envVarMap
}
def GetEnvStringList(Map envVarMap) {
def strList = []
envVarMap.each { var ->
strList.add("${var.key}=${var.value}")
}
return strList
}
// Pulls/downloads files from the repo through codecommit. Despite Glob matching is NOT supported, '*' is supported
// as a folder or filename (not a portion, it has to be the whole folder or filename)
def PullFilesFromGit(String filenamePath, String branchName, boolean failIfNotFound = true, String repositoryName = env.DEFAULT_REPOSITORY_NAME) {
echo "PullFilesFromGit filenamePath=${filenamePath} branchName=${branchName} repositoryName=${repositoryName}"
def folderPathParts = filenamePath.tokenize('/')
def filename = folderPathParts[folderPathParts.size()-1]
folderPathParts.remove(folderPathParts.size()-1) // remove the filename
def folderPath = folderPathParts.join('/')
if (folderPath.contains('*')) {
def currentPath = ''
for (int i = 0; i < folderPathParts.size(); i++) {
if (folderPathParts[i] == '*') {
palMkdir(currentPath)
retry(3) { palSh("aws codecommit get-folder --repository-name ${repositoryName} --commit-specifier ${branchName} --folder-path ${currentPath} > ${currentPath}/.codecommit", "GetFolder ${currentPath}") }
def folderInfo = readJSON file: "${currentPath}/.codecommit"
folderInfo.subFolders.each { folder ->
def newSubPath = currentPath + '/' + folder.relativePath
for (int j = i+1; j < folderPathParts.size(); j++) {
newSubPath = newSubPath + '/' + folderPathParts[j]
}
newSubPath = newSubPath + '/' + filename
PullFilesFromGit(newSubPath, branchName, false, repositoryName)
}
palRm("${currentPath}/.codecommit")
}
if (i == 0) {
currentPath = folderPathParts[i]
} else {
currentPath = currentPath + '/' + folderPathParts[i]
}
}
} else if (filename.contains('*')) {
palMkdir(folderPath)
retry(3) { palSh("aws codecommit get-folder --repository-name ${repositoryName} --commit-specifier ${branchName} --folder-path ${folderPath} > ${folderPath}/.codecommit", "GetFolder ${folderPath}") }
def folderInfo = readJSON file: "${folderPath}/.codecommit"
folderInfo.files.each { file ->
PullFilesFromGit("${folderPath}/${filename}", branchName, false, repositoryName)
}
palRm("${folderPath}/.codecommit")
} else {
def errorFile = "${folderPath}/error.txt"
palMkdir(folderPath)
retry(3) {
try {
if(env.IS_UNIX) {
sh label: "Downloading ${filenamePath}",
script: "aws codecommit get-file --repository-name ${repositoryName} --commit-specifier ${branchName} --file-path ${filenamePath} --query fileContent --output text 2>${errorFile} > ${filenamePath}_encoded"
sh label: 'Decoding',
script: "base64 --decode ${filenamePath}_encoded > ${filenamePath}"
} else {
errorFile = errorFile.replace('/','\\')
win_filenamePath = filenamePath.replace('/', '\\')
bat label: "Downloading ${win_filenamePath}",
script: "aws codecommit get-file --repository-name ${repositoryName} --commit-specifier ${branchName} --file-path ${filenamePath} --query fileContent --output text 2>${errorFile} > ${win_filenamePath}_encoded"
bat label: 'Decoding',
script: "certutil -decode ${win_filenamePath}_encoded ${win_filenamePath}"
}
palRm("${filenamePath}_encoded")
} catch (Exception ex) {
def error = ''
if(fileExists(errorFile)) {
error = readFile errorFile
}
if (!error || !(!failIfNotFound && error.contains('FileDoesNotExistException'))) {
palRm("${errorFile} ${filenamePath}.encoded ${filenamePath}")
throw new Exception("Could not get file: ${filenamePath}, ex: ${ex}, stderr: ${error}")
}
}
palRm(errorFile)
}
}
}
def SetLfsCredentials(cmd, lbl = '') {
if (env.IS_UNIX) {
sh label: lbl,
script: cmd
} else {
bat label: lbl,
script: cmd
}
}
def CheckoutBootstrapScripts(String branchName) {
checkout([$class: "GitSCM",
branches: [[name: "*/${branchName}"]],
doGenerateSubmoduleConfigurations: false,
extensions: [
[
$class: "SparseCheckoutPaths",
sparseCheckoutPaths: [
[ $class: "SparseCheckoutPath", path: "AutomatedReview/" ],
[ $class: "SparseCheckoutPath", path: "scripts/build/bootstrap/" ],
[ $class: "SparseCheckoutPath", path: "Tools/build/JenkinsScripts/build/Platform" ]
]
],
[
$class: "CloneOption", depth: 1, noTags: false, reference: "", shallow: true
]
],
submoduleCfg: [],
userRemoteConfigs: scm.userRemoteConfigs
])
}
def CheckoutRepo(boolean disableSubmodules = false) {
dir(ENGINE_REPOSITORY_NAME) {
palSh('git lfs uninstall', 'Git LFS Uninstall') // Prevent git from pulling lfs objects during checkout
if(fileExists('.git')) {
// If the repository after checkout is locked, likely we took a snapshot while git was running,
// to leave the repo in a usable state, garbagecollect. This also helps in situations where
def indexLockFile = '.git/index.lock'
if(fileExists(indexLockFile)) {
palSh('git gc', 'Git GarbageCollect')
}
if(fileExists(indexLockFile)) { // if it is still there, remove it
palRm(indexLockFile)
}
}
}
def random = new Random()
def retryAttempt = 0
retry(5) {
if (retryAttempt > 0) {
sleep random.nextInt(60 * retryAttempt) // Stagger checkouts to prevent HTTP 429 (Too Many Requests) response from CodeCommit
}
retryAttempt = retryAttempt + 1
if(params.PULL_REQUEST_ID) {
// This is a pull request build. Perform merge with destination branch before building.
dir(ENGINE_REPOSITORY_NAME) {
checkout scm: [
$class: 'GitSCM',
branches: scm.branches,
extensions: [
[$class: 'PreBuildMerge', options: [mergeRemote: 'origin', mergeTarget: params.DESTINATION_BRANCH]],
[$class: 'SubmoduleOption', disableSubmodules: disableSubmodules, recursiveSubmodules: true],
[$class: 'CheckoutOption', timeout: 60]
],
userRemoteConfigs: scm.userRemoteConfigs
]
}
} else {
dir(ENGINE_REPOSITORY_NAME) {
checkout scm: [
$class: 'GitSCM',
branches: scm.branches,
extensions: [
[$class: 'SubmoduleOption', disableSubmodules: disableSubmodules, recursiveSubmodules: true],
[$class: 'CheckoutOption', timeout: 60]
],
userRemoteConfigs: scm.userRemoteConfigs
]
}
}
}
// Add folder where we will store the 3rdParty downloads and packages
if(!fileExists('3rdParty')) {
palMkdir('3rdParty')
}
dir(ENGINE_REPOSITORY_NAME) {
// Run lfs in a separate step. Jenkins is unable to load the credentials for the custom LFS endpoint
withCredentials([usernamePassword(credentialsId: "${env.GITHUB_USER}", passwordVariable: 'accesstoken', usernameVariable: 'username')]) {
SetLfsCredentials("git config -f .lfsconfig lfs.url https://${username}:${accesstoken}@${env.LFS_URL}", 'Set credentials')
}
palSh('git lfs install', 'Git LFS Install')
palSh('git lfs pull', 'Git LFS Pull')
// CHANGE_ID is used by some scripts to identify uniquely the current change (usually metric jobs)
palSh('git rev-parse HEAD > commitid', 'Getting commit id')
env.CHANGE_ID = readFile file: 'commitid'
env.CHANGE_ID = env.CHANGE_ID.trim()
palRm('commitid')
}
}
def PreBuildCommonSteps(Map pipelineConfig, String projectName, String pipeline, String branchName, String platform, String buildType, String workspace, boolean mount = true, boolean disableSubmodules = false) {
echo 'Starting pre-build common steps...'
if (mount) {
unstash name: 'incremental_build_script'
def pythonCmd = ''
if(env.IS_UNIX) pythonCmd = 'sudo -E python -u '
else pythonCmd = 'python -u '
if(env.RECREATE_VOLUME.toBoolean()) {
palSh("${pythonCmd} ${INCREMENTAL_BUILD_SCRIPT_PATH} --action delete --project ${projectName} --pipeline ${pipeline} --branch ${branchName} --platform ${platform} --build_type ${buildType}", 'Deleting volume')
}
timeout(5) {
palSh("${pythonCmd} ${INCREMENTAL_BUILD_SCRIPT_PATH} --action mount --project ${projectName} --pipeline ${pipeline} --branch ${branchName} --platform ${platform} --build_type ${buildType}", 'Mounting volume')
}
if(env.IS_UNIX) {
sh label: 'Setting volume\'s ownership',
script: """
if sudo test ! -d "${workspace}"; then
sudo mkdir -p ${workspace}
cd ${workspace}/..
sudo chown -R lybuilder:root .
fi
"""
}
}
// Cleanup previous repo location, we are currently at the root of the workspace, if we have a .git folder
// we need to cleanup. Once all branches take this relocation, we can remove this
if(env.CLEAN_WORKSPACE.toBoolean() || fileExists("${workspace}/.git")) {
if(fileExists(workspace)) {
palRmDir(workspace)
}
}
dir(workspace) {
CheckoutRepo(disableSubmodules)
// Get python
dir(ENGINE_REPOSITORY_NAME) {
if(env.IS_UNIX) {
sh label: 'Getting python',
script: 'python/get_python.sh'
} else {
bat label: 'Getting python',
script: 'python/get_python.bat'
}
if(env.CLEAN_OUTPUT_DIRECTORY.toBoolean() || env.CLEAN_ASSETS.toBoolean()) {
def command = "${pipelineConfig.BUILD_ENTRY_POINT} --platform ${platform} --type clean"
if (env.IS_UNIX) {
sh label: "Running ${platform} clean",
script: "${pipelineConfig.PYTHON_DIR}/python.sh -u ${command}"
} else {
bat label: "Running ${platform} clean",
script: "${pipelineConfig.PYTHON_DIR}/python.cmd -u ${command}".replace('/','\\')
}
}
}
}
}
def Build(Map options, String platform, String type, String workspace) {
def command = "${options.BUILD_ENTRY_POINT} --platform ${platform} --type ${type}"
dir("${workspace}/${ENGINE_REPOSITORY_NAME}") {
if (env.IS_UNIX) {
sh label: "Running ${platform} ${type}",
script: "${options.PYTHON_DIR}/python.sh -u ${command}"
} else {
bat label: "Running ${platform} ${type}",
script: "${options.PYTHON_DIR}/python.cmd -u ${command}".replace('/','\\')
}
}
}
def TestMetrics(Map options, String workspace, String branchName, String repoName, String buildJobName, String outputDirectory, String configuration) {
catchError(buildResult: null, stageResult: null) {
def cmakeBuildDir = [workspace, ENGINE_REPOSITORY_NAME, outputDirectory].join('/')
dir("${workspace}/${ENGINE_REPOSITORY_NAME}") {
checkout scm: [
$class: 'GitSCM',
branches: [[name: '*/main']],
extensions: [[$class: 'RelativeTargetDirectory', relativeTargetDir: 'mars']],
userRemoteConfigs: [[url: "${env.MARS_REPO}", name: 'mars', credentialsId: "${env.GITHUB_USER}"]]
]
withCredentials([usernamePassword(credentialsId: "${env.SERVICE_USER}", passwordVariable: 'apitoken', usernameVariable: 'username')]) {
def command = "${options.PYTHON_DIR}/python.cmd -u mars/scripts/python/ctest_test_metric_scraper.py -e jenkins.creds.user ${username} -e jenkins.creds.pass ${apitoken} ${cmakeBuildDir} ${branchName} %BUILD_NUMBER% AR ${configuration} ${repoName} "
bat label: "Publishing ${buildJobName} Test Metrics",
script: command
}
}
}
}
def PostBuildCommonSteps(String workspace, boolean mount = true) {
echo 'Starting post-build common steps...'
if(params.PULL_REQUEST_ID) {
dir("${workspace}/${ENGINE_REPOSITORY_NAME}") {
if(fileExists('.git')) {
palSh('git reset --hard HEAD', 'Discard PR merge, git reset')
}
}
}
if (mount) {
def pythonCmd = ''
if(env.IS_UNIX) pythonCmd = 'sudo -E python -u '
else pythonCmd = 'python -u '
try {
timeout(5) {
palSh("${pythonCmd} ${INCREMENTAL_BUILD_SCRIPT_PATH} --action unmount", 'Unmounting volume')
}
} catch (Exception e) {
echo "Unmount script error ${e}"
}
}
}
def CreateSetupStage(Map pipelineConfig, String projectName, String pipelineName, String branchName, String platformName, String jobName, Map environmentVars) {
return {
stage("Setup") {
PreBuildCommonSteps(pipelineConfig, projectName, pipelineName, branchName, platformName, jobName, environmentVars['WORKSPACE'], environmentVars['MOUNT_VOLUME'])
}
}
}
def CreateBuildStage(Map pipelineConfig, String platformName, String jobName, Map environmentVars) {
return {
stage("${jobName}") {
Build(pipelineConfig, platformName, jobName, environmentVars['WORKSPACE'])
}
}
}
def CreateTestMetricsStage(Map pipelineConfig, String branchName, Map environmentVars, String buildJobName, String outputDirectory, String configuration) {
return {
stage("${buildJobName}_metrics") {
TestMetrics(pipelineConfig, environmentVars['WORKSPACE'], branchName, env.DEFAULT_REPOSITORY_NAME, buildJobName, outputDirectory, configuration)
}
}
}
def CreateTeardownStage(Map environmentVars) {
return {
stage("Teardown") {
PostBuildCommonSteps(environmentVars['WORKSPACE'], environmentVars['MOUNT_VOLUME'])
}
}
}
def projectName = ''
def pipelineName = ''
def branchName = ''
def pipelineConfig = {}
// Start Pipeline
try {
stage('Setup Pipeline') {
node('controller') {
def envVarList = []
if(isUnix()) {
envVarList.add('IS_UNIX=1')
}
withEnv(envVarList) {
timestamps {
(projectName, pipelineName) = GetRunningPipelineName(env.JOB_NAME) // env.JOB_NAME is the name of the job given by Jenkins
scmType = GetSCMType()
if(env.BRANCH_NAME) {
branchName = env.BRANCH_NAME
} else {
branchName = scm.branches[0].name // for non-multibranch pipelines
env.BRANCH_NAME = branchName // so scripts that read this environment have it (e.g. incremental_build_util.py)
}
pipelineProperties.add(disableConcurrentBuilds())
echo "Running \"${pipelineName}\" for \"${branchName}\"..."
if (scmType == 'github') {
CheckoutBootstrapScripts(branchName)
}
// Load configs
pipelineConfig = LoadPipelineConfig(pipelineName, branchName, scmType)
// Add each platform as a parameter that the user can disable if needed
pipelineConfig.platforms.each { platform ->
pipelineParameters.add(booleanParam(defaultValue: true, description: '', name: platform.key))
}
pipelineProperties.add(parameters(pipelineParameters))
properties(pipelineProperties)
// Stash the INCREMENTAL_BUILD_SCRIPT_PATH since all nodes will use it
if (scmType == 'codecommit') {
PullFilesFromGit(INCREMENTAL_BUILD_SCRIPT_PATH, branchName, true, ENGINE_REPOSITORY_NAME)
}
stash name: 'incremental_build_script',
includes: INCREMENTAL_BUILD_SCRIPT_PATH
}
}
}
}
if(env.BUILD_NUMBER == '1') {
// Exit pipeline early on the intial build. This allows Jenkins to load the pipeline for the branch and enables users
// to select build parameters on their first actual build. See https://issues.jenkins.io/browse/JENKINS-41929
currentBuild.result = 'SUCCESS'
return
}
// Build and Post-Build Testing Stage
def buildConfigs = [:]
// Platform Builds run on EC2
pipelineConfig.platforms.each { platform ->
platform.value.build_types.each { build_job ->
if (IsJobEnabled(build_job, pipelineName, platform.key)) { // User can filter jobs, jobs are tagged by pipeline
def envVars = GetBuildEnvVars(platform.value.PIPELINE_ENV ?: EMPTY_JSON, build_job.value.PIPELINE_ENV ?: EMPTY_JSON, pipelineName)
envVars['JOB_NAME'] = "${branchName}_${platform.key}_${build_job.key}" // backwards compatibility, some scripts rely on this
def nodeLabel = envVars['NODE_LABEL']
buildConfigs["${platform.key} [${build_job.key}]"] = {
node("${nodeLabel}") {
if(isUnix()) { // Has to happen inside a node
envVars['IS_UNIX'] = 1
}
withEnv(GetEnvStringList(envVars)) {
timeout(time: envVars['TIMEOUT'], unit: 'MINUTES', activity: true) {
try {
def build_job_name = build_job.key
CreateSetupStage(pipelineConfig, projectName, pipelineName, branchName, platform.key, build_job.key, envVars).call()
if(build_job.value.steps) { //this is a pipe with many steps so create all the build stages
build_job.value.steps.each { build_step ->
build_job_name = build_step
CreateBuildStage(pipelineConfig, platform.key, build_step, envVars).call()
}
} else {
CreateBuildStage(pipelineConfig, platform.key, build_job.key, envVars).call()
}
if (env.MARS_REPO && platform.key == 'Windows' && build_job_name.startsWith('test')) {
def output_directory = platform.value.build_types[build_job_name].PARAMETERS.OUTPUT_DIRECTORY
def configuration = platform.value.build_types[build_job_name].PARAMETERS.CONFIGURATION
CreateTestMetricsStage(pipelineConfig, branchName, envVars, build_job_name, output_directory, configuration).call()
}
}
catch(Exception e) {
// https://github.com/jenkinsci/jenkins/blob/master/core/src/main/java/hudson/model/Result.java
// {SUCCESS,UNSTABLE,FAILURE,NOT_BUILT,ABORTED}
def currentResult = envVars['ON_FAILURE_MARK'] ?: 'FAILURE'
if (currentResult == 'FAILURE') {
currentBuild.result = 'FAILURE'
error "FAILURE: ${e}"
} else if (currentResult == 'UNSTABLE') {
currentBuild.result = 'UNSTABLE'
unstable(message: "UNSTABLE: ${e}")
}
}
finally {
CreateTeardownStage(envVars).call()
}
}
}
}
}
}
}
}
timestamps {
stage('Build') {
parallel buildConfigs // Run parallel builds
}
echo 'All builds successful'
}
}
catch(Exception e) {
error "Exception: ${e}"
}
finally {
try {
if(env.SNS_TOPIC) {
snsPublish(
topicArn: env.SNS_TOPIC,
subject:'Build Result',
message:"${currentBuild.currentResult}:${params.REPOSITORY_NAME}:${params.SOURCE_BRANCH}:${params.SOURCE_COMMIT}:${params.DESTINATION_COMMIT}:${params.PULL_REQUEST_ID}:${BUILD_URL}:${env.RECREATE_VOLUME}:${env.CLEAN_OUTPUT_DIRECTORY}:${env.CLEAN_ASSETS}"
)
}
step([
$class: 'Mailer',
notifyEveryUnstableBuild: true,
sendToIndividuals: true,
recipients: emailextrecipients([
[$class: 'CulpritsRecipientProvider'],
[$class: 'RequesterRecipientProvider']
])
])
} catch(Exception e) {
}
}

@ -1,12 +0,0 @@
{
"BUILD_ENTRY_POINT": "Tools/build/JenkinsScripts/build/ci_build.py",
"PIPELINE_CONFIGS": [
"Tools/build/JenkinsScripts/build/Platform/*/pipeline.json",
"restricted/*/Tools/build/JenkinsScripts/build/pipeline.json"
],
"BUILD_CONFIGS": [
"Tools/build/JenkinsScripts/build/Platform/*/build_config.json",
"restricted/*/Tools/build/JenkinsScripts/build/build_config.json"
],
"PYTHON_DIR": "python"
}

@ -0,0 +1,14 @@
{
"Amazon": {
"AssetProcessor": {
"Settings": {
"RC cgf": {
"ignore": true
},
"RC fbx": {
"ignore": true
}
}
}
}
}

@ -9,12 +9,38 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
file(READ "${CMAKE_CURRENT_LIST_DIR}/project.json" project_json)
#! Adds the --project-path argument to the VS IDE debugger command arguments
function(add_vs_debugger_arguments)
# Inject the project root into the --project-path argument into the Visual Studio Debugger arguments by defaults
list(APPEND app_targets AutomatedTesting.GameLauncher AutomatedTesting.ServerLauncher)
list(APPEND app_targets AssetBuilder AssetProcessor AssetProcessorBatch Editor)
foreach(app_target IN LISTS app_targets)
if (TARGET ${app_target})
set_property(TARGET ${app_target} APPEND PROPERTY VS_DEBUGGER_COMMAND_ARGUMENTS "--project-path=\"${CMAKE_CURRENT_LIST_DIR}\"")
endif()
endforeach()
endfunction()
string(JSON project_target_name ERROR_VARIABLE json_error GET ${project_json} "project_name")
if(${json_error})
message(FATAL_ERROR "Unable to read key 'project_name' from 'project.json'")
endif()
if(NOT PROJECT_NAME)
cmake_minimum_required(VERSION 3.19)
project(AutomatedTesting
LANGUAGES C CXX
VERSION 1.0.0.0
)
include(EngineFinder.cmake OPTIONAL)
find_package(o3de REQUIRED)
o3de_initialize()
add_vs_debugger_arguments()
else()
# Add the project_name to global LY_PROJECTS_TARGET_NAME property
file(READ "${CMAKE_CURRENT_LIST_DIR}/project.json" project_json)
set_property(GLOBAL APPEND PROPERTY LY_PROJECTS_TARGET_NAME ${project_target_name})
add_subdirectory(Gem)
string(JSON project_target_name ERROR_VARIABLE json_error GET ${project_json} "project_name")
if(json_error)
message(FATAL_ERROR "Unable to read key 'project_name' from 'project.json'")
endif()
set_property(GLOBAL APPEND PROPERTY LY_PROJECTS_TARGET_NAME ${project_target_name})
add_subdirectory(Gem)
endif()

@ -0,0 +1,18 @@
{
"Type": "JsonSerialization",
"Version": 1,
"ClassName": "MultiplatformPresetSettings",
"ClassData": {
"DefaultPreset": {
"UUID": "{9E5BBFB4-BDDA-4759-AB74-D047EE25A35D}",
"Name": "Test_Linear_to_Auto",
"SourceColor": "Linear",
"DestColor": "Auto",
"FileMasks": [
"_linear-to-auto"
],
"PixelFormat": "R8G8B8X8",
"DiscardAlpha": true
}
}
}

@ -0,0 +1,18 @@
{
"Type": "JsonSerialization",
"Version": 1,
"ClassName": "MultiplatformPresetSettings",
"ClassData": {
"DefaultPreset": {
"UUID": "{31199710-5B61-4A30-99F0-18DF724EC308}",
"Name": "Test_Linear_to_Linear",
"SourceColor": "Linear",
"DestColor": "Linear",
"FileMasks": [
"_linear-to-linear"
],
"PixelFormat": "R8G8B8X8",
"DiscardAlpha": true
}
}
}

@ -0,0 +1,18 @@
{
"Type": "JsonSerialization",
"Version": 1,
"ClassName": "MultiplatformPresetSettings",
"ClassData": {
"DefaultPreset": {
"UUID": "{F0E6BE7F-376E-4F1B-9244-70E01C1CABD6}",
"Name": "Test_Linear_to_sRGB",
"SourceColor": "Linear",
"DestColor": "sRGB",
"FileMasks": [
"_linear-to-srgb"
],
"PixelFormat": "R8G8B8X8",
"DiscardAlpha": true
}
}
}

@ -0,0 +1,18 @@
{
"Type": "JsonSerialization",
"Version": 1,
"ClassName": "MultiplatformPresetSettings",
"ClassData": {
"DefaultPreset": {
"UUID": "{EE397A40-4430-437F-B0EF-9EC8B6E35176}",
"Name": "Test_sRGB_to_Auto",
"SourceColor": "sRGB",
"DestColor": "Auto",
"FileMasks": [
"_srgb-to-auto"
],
"PixelFormat": "R8G8B8X8",
"DiscardAlpha": true
}
}
}

@ -0,0 +1,18 @@
{
"Type": "JsonSerialization",
"Version": 1,
"ClassName": "MultiplatformPresetSettings",
"ClassData": {
"DefaultPreset": {
"UUID": "{2865D7A5-B75D-4D9C-9591-47BD2FF93377}",
"Name": "Test_sRGB_to_Linear",
"SourceColor": "sRGB",
"DestColor": "Linear",
"FileMasks": [
"_srgb-to-linear"
],
"PixelFormat": "R8G8B8X8",
"DiscardAlpha": true
}
}
}

@ -0,0 +1,18 @@
{
"Type": "JsonSerialization",
"Version": 1,
"ClassName": "MultiplatformPresetSettings",
"ClassData": {
"DefaultPreset": {
"UUID": "{9FBA54D5-EF6F-4728-AF92-B0176B8308C5}",
"Name": "Test_sRGB_to_sRGB",
"SourceColor": "sRGB",
"DestColor": "sRGB",
"FileMasks": [
"_srgb-to-srgb"
],
"PixelFormat": "R8G8B8X8",
"DiscardAlpha": true
}
}
}

@ -0,0 +1,11 @@
{
"Type": "JsonSerialization",
"Version": 1,
"ClassName": "GlobalBuildOptions",
"ClassData": {
"ShaderCompilerArguments" : {
"DefaultMatrixOrder" : "Row",
"AzslcAdditionalFreeArguments" : "--strip-unused-srgs"
}
}
}

@ -25,6 +25,7 @@ ly_add_target(
BUILD_DEPENDENCIES
PRIVATE
AZ::AzCore
Gem::Atom_AtomBridge.Static
)
################################################################################
@ -37,6 +38,7 @@ ly_add_project_dependencies(
AutomatedTesting.GameLauncher
DEPENDENCIES_FILES
runtime_dependencies.cmake
${pal_dir}/runtime_dependencies.cmake
)
if(PAL_TRAIT_BUILD_HOST_TOOLS)

@ -8,4 +8,3 @@
# 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.
#

@ -7,4 +7,4 @@
# 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.
#
#

@ -7,4 +7,4 @@
# 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.
#
#

@ -9,5 +9,7 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
set (PAL_TRAIT_BUILD_ASSETPROCESSOR_APPLICATION_TYPE APPLICATION)
set(GEM_DEPENDENCIES
Gem::Atom_RHI_Vulkan.Private
Gem::Atom_RHI_DX12.Private
)

@ -11,4 +11,9 @@
set(GEM_DEPENDENCIES
Gem::QtForPython.Editor
Gem::Atom_RHI_Vulkan.Private
Gem::Atom_RHI_Vulkan.Builders
Gem::Atom_RHI_DX12.Private
Gem::Atom_RHI_DX12.Builders
Gem::Atom_RHI_Metal.Builders
)

@ -0,0 +1,10 @@
#
# 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.
#

@ -0,0 +1,10 @@
#
# 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.
#

@ -21,7 +21,6 @@ set(GEM_DEPENDENCIES
Gem::Gestures
Gem::CertificateManager
Gem::DebugDraw
Gem::GameLift
Gem::AudioSystem
Gem::InAppPurchases
Gem::AutomatedTesting
@ -43,4 +42,16 @@ set(GEM_DEPENDENCIES
Gem::SurfaceData
Gem::GradientSignal
Gem::Vegetation
Gem::Atom_RHI.Private
Gem::Atom_RPI.Private
Gem::Atom_Feature_Common
Gem::Atom_Bootstrap
Gem::Atom_Component_DebugCamera
Gem::AtomImGuiTools
Gem::AtomLyIntegration_CommonFeatures
Gem::EMotionFX_Atom
Gem::ImguiAtom
Gem::Atom_AtomBridge
Gem::AtomFont
)

@ -21,7 +21,6 @@ set(GEM_DEPENDENCIES
Gem::Gestures
Gem::CertificateManager
Gem::DebugDraw.Editor
Gem::GameLift
Gem::SceneProcessing.Editor
Gem::GraphCanvas.Editor
Gem::InAppPurchases
@ -30,7 +29,6 @@ set(GEM_DEPENDENCIES
Gem::PythonAssetBuilder.Editor
Gem::Metastream
Gem::AudioSystem.Editor
Gem::ImageProcessing.Editor
Gem::Camera.Editor
Gem::EMotionFX.Editor
Gem::PhysX.Editor
@ -52,4 +50,22 @@ set(GEM_DEPENDENCIES
Gem::Vegetation.Editor
Gem::GraphModel.Editor
Gem::LandscapeCanvas.Editor
Gem::Atom_RHI.Private
Gem::EMotionFX.Editor
Gem::Atom_RPI.Builders
Gem::Atom_RPI.Editor
Gem::Atom_Feature_Common.Builders
Gem::Atom_Feature_Common.Editor
Gem::ImGui.Editor
Gem::Atom_Bootstrap
Gem::Atom_Asset_Shader.Builders
Gem::Atom_Component_DebugCamera
Gem::AtomImGuiTools
Gem::AtomLyIntegration_CommonFeatures.Editor
Gem::EMotionFX_Atom.Editor
Gem::ImageProcessingAtom.Editor
Gem::Atom_AtomBridge.Editor
Gem::ImguiAtom
Gem::AtomFont
Gem::AtomToolsFramework.Editor
)

@ -18,36 +18,37 @@ ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${P
add_subdirectory(assetpipeline)
## Physics ##
if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS)
ly_add_pytest(
NAME AutomatedTesting::PhysicsTests
TEST_SUITE sandbox
TEST_SERIAL
PATH ${CMAKE_CURRENT_LIST_DIR}/physics/TestSuite_Active.py
TIMEOUT 3600
RUNTIME_DEPENDENCIES
Legacy::Editor
Legacy::CryRenderNULL
AZ::AssetProcessor
AutomatedTesting.Assets
COMPONENT
Physics
)
ly_add_pytest(
NAME AutomatedTesting::PhysicsTests_Sandbox
TEST_SUITE sandbox
TEST_SERIAL
PATH ${CMAKE_CURRENT_LIST_DIR}/physics/TestSuite_Sandbox.py
TIMEOUT 3600
RUNTIME_DEPENDENCIES
Legacy::Editor
Legacy::CryRenderNULL
AZ::AssetProcessor
AutomatedTesting.Assets
COMPONENT
Physics
)
endif()
# DISABLED - see LYN-2536
#if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS)
# ly_add_pytest(
# NAME AutomatedTesting::PhysicsTests
# TEST_SUITE main
# TEST_SERIAL
# PATH ${CMAKE_CURRENT_LIST_DIR}/physics/TestSuite_Active.py
# TIMEOUT 3600
# RUNTIME_DEPENDENCIES
# Legacy::Editor
# Legacy::CryRenderNULL
# AZ::AssetProcessor
# AutomatedTesting.Assets
# COMPONENT
# Physics
# )
# ly_add_pytest(
# NAME AutomatedTesting::PhysicsTests_Sandbox
# TEST_SUITE sandbox
# TEST_SERIAL
# PATH ${CMAKE_CURRENT_LIST_DIR}/physics/TestSuite_Sandbox.py
# TIMEOUT 3600
# RUNTIME_DEPENDENCIES
# Legacy::Editor
# Legacy::CryRenderNULL
# AZ::AssetProcessor
# AutomatedTesting.Assets
# COMPONENT
# Physics
# )
#endif()
## ScriptCanvas ##
if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS)
@ -80,22 +81,23 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS)
endif()
## White Box ##
if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS)
ly_add_pytest(
NAME AutomatedTesting::WhiteBoxTests
TEST_SUITE main
TEST_SERIAL
PATH ${CMAKE_CURRENT_LIST_DIR}/WhiteBox/TestSuite_Active.py
TIMEOUT 3600
RUNTIME_DEPENDENCIES
Legacy::Editor
Legacy::CryRenderNULL
AZ::AssetProcessor
AutomatedTesting.Assets
COMPONENT
WhiteBox
)
endif()
# DISABLED - See LYN-2663
#if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS)
# ly_add_pytest(
# NAME AutomatedTesting::WhiteBoxTests
# TEST_SUITE main
# TEST_SERIAL
# PATH ${CMAKE_CURRENT_LIST_DIR}/WhiteBox/TestSuite_Active.py
# TIMEOUT 3600
# RUNTIME_DEPENDENCIES
# Legacy::Editor
# Legacy::CryRenderNULL
# AZ::AssetProcessor
# AutomatedTesting.Assets
# COMPONENT
# WhiteBox
# )
#endif()
## NvCloth ##
# [TODO LYN-1928] Enable when AutomatedTesting runs with Atom
@ -157,51 +159,51 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_
## DynVeg ##
ly_add_pytest(
NAME DynamicVegetationTests_Main_NoGPU
NAME DynamicVegetationTests_Main_GPU
TEST_REQUIRES gpu
TEST_SERIAL
TEST_SUITE main
PATH ${CMAKE_CURRENT_LIST_DIR}/largeworlds/dyn_veg
PYTEST_MARKS "not REQUIRES_gpu"
PYTEST_MARKS "not SUITE_sandbox and not SUITE_periodic and not SUITE_benchmark"
TIMEOUT 36000
RUNTIME_DEPENDENCIES
AZ::AssetProcessor
Legacy::Editor
AutomatedTesting.GameLauncher
AutomatedTesting.Assets
Legacy::CryRenderNULL
COMPONENT
LargeWorlds
)
ly_add_pytest(
NAME DynamicVegetationTests_Sandbox_NoGPU
NAME DynamicVegetationTests_Sandbox_GPU
TEST_REQUIRES gpu
TEST_SERIAL
TEST_SUITE sandbox
PATH ${CMAKE_CURRENT_LIST_DIR}/largeworlds/dyn_veg
PYTEST_MARKS "not REQUIRES_gpu"
PYTEST_MARKS "SUITE_sandbox"
TIMEOUT 36000
RUNTIME_DEPENDENCIES
AZ::AssetProcessor
Legacy::Editor
AutomatedTesting.GameLauncher
AutomatedTesting.Assets
Legacy::CryRenderNULL
COMPONENT
LargeWorlds
)
ly_add_pytest(
NAME DynamicVegetationTests_Periodic_NoGPU
NAME DynamicVegetationTests_Periodic_GPU
TEST_REQUIRES gpu
TEST_SERIAL
TEST_SUITE periodic
PATH ${CMAKE_CURRENT_LIST_DIR}/largeworlds/dyn_veg
PYTEST_MARKS "not REQUIRES_gpu"
PYTEST_MARKS "SUITE_periodic"
TIMEOUT 3600
RUNTIME_DEPENDENCIES
AZ::AssetProcessor
Legacy::Editor
AutomatedTesting.Assets
Legacy::CryRenderNULL
COMPONENT
LargeWorlds
)
@ -209,38 +211,40 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_
## LandscapeCanvas ##
ly_add_pytest(
NAME LandscapeCanvasTests_Main
TEST_REQUIRES gpu
TEST_SERIAL
TEST_SUITE main
PATH ${CMAKE_CURRENT_LIST_DIR}/largeworlds/landscape_canvas
PYTEST_MARKS "not SUITE_sandbox and not SUITE_periodic and not SUITE_benchmark"
TIMEOUT 3600
RUNTIME_DEPENDENCIES
AZ::AssetProcessor
Legacy::Editor
AutomatedTesting.Assets
Legacy::CryRenderNULL
COMPONENT
LargeWorlds
)
## GradientSignal ##
ly_add_pytest(
NAME GradientSignalTests_Main
NAME LandscapeCanvasTests_Periodic
TEST_REQUIRES gpu
TEST_SERIAL
TEST_SUITE main
PATH ${CMAKE_CURRENT_LIST_DIR}/largeworlds/gradient_signal
TEST_SUITE periodic
PATH ${CMAKE_CURRENT_LIST_DIR}/largeworlds/landscape_canvas
PYTEST_MARKS "SUITE_periodic"
TIMEOUT 3600
RUNTIME_DEPENDENCIES
AZ::AssetProcessor
Legacy::Editor
AutomatedTesting.Assets
Legacy::CryRenderNULL
AZ::AssetProcessor
Legacy::Editor
AutomatedTesting.Assets
COMPONENT
LargeWorlds
)
## GradientSignal ##
ly_add_pytest(
NAME GradientSignalTests_Periodic
TEST_REQUIRES gpu
TEST_SERIAL
TEST_SUITE periodic
PATH ${CMAKE_CURRENT_LIST_DIR}/largeworlds/gradient_signal
@ -249,7 +253,6 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_
AZ::AssetProcessor
Legacy::Editor
AutomatedTesting.Assets
Legacy::CryRenderNULL
COMPONENT
LargeWorlds
)

@ -35,14 +35,10 @@ class TestGradientRequiresShape(object):
"New entity with no parent created: SUCCESS",
"Mesh component added to entity: SUCCESS",
"Entity has a Mesh component: SUCCESS",
"GetSetCompare Test MeshComponentRenderNode|Mesh asset: SUCCESS",
"GetSetCompare Clear MeshComponentRenderNode|Mesh asset: SUCCESS",
"PTE Test MeshComponentRenderNode|Mesh asset: SUCCESS",
"PTE Clear MeshComponentRenderNode|Mesh asset: SUCCESS",
"GetSetCompare Test MeshComponentRenderNode|Material override: SUCCESS",
"GetSetCompare Clear MeshComponentRenderNode|Material override: SUCCESS",
"PTE Test MeshComponentRenderNode|Material override: SUCCESS",
"PTE Clear MeshComponentRenderNode|Material override: SUCCESS",
"GetSetCompare Test Controller|Configuration|Mesh Asset: SUCCESS",
"GetSetCompare Clear Controller|Configuration|Mesh Asset: SUCCESS",
"PTE Test Controller|Configuration|Mesh Asset: SUCCESS",
"PTE Clear Controller|Configuration|Mesh Asset: SUCCESS",
]
test_case_file = os.path.join(os.path.dirname(__file__), 'ComponentAssetCommands_test_case.py')

@ -129,13 +129,8 @@ if(pteObj.IsSuccess()):
pte = pteObj.GetValue()
# Tests for the Asset<> case
cubeId = asset.AssetCatalogRequestBus(bus.Broadcast, 'GetAssetIdByPath', 'objects/default/primitive_cube.cgf', math.Uuid(), False)
GetSetCompareTest(component, "MeshComponentRenderNode|Mesh asset", cubeId)
PteTest(pte, "MeshComponentRenderNode|Mesh asset", cubeId)
# Tests for the SimpleAssetReference case
materialId = asset.AssetCatalogRequestBus(bus.Broadcast, 'GetAssetIdByPath', 'engineassets/texturemsg/defaultsolids.mtl', math.Uuid(), False)
GetSetCompareTest(component, "MeshComponentRenderNode|Material override", materialId)
PteTest(pte, "MeshComponentRenderNode|Material override", materialId)
testAssetId = asset.AssetCatalogRequestBus(bus.Broadcast, 'GetAssetIdByPath', 'assets/objects/foliage/cedar.azmodel', math.Uuid(), False)
GetSetCompareTest(component, "Controller|Configuration|Mesh Asset", testAssetId)
PteTest(pte, "Controller|Configuration|Mesh Asset", testAssetId)
editor.EditorToolsApplicationRequestBus(bus.Broadcast, 'ExitNoPrompt')

@ -9,27 +9,38 @@ remove or modify any license notices. This file is distributed on an "AS IS" BAS
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
#
# This is a pytest module to test the in-Editor Python API from PythonEditorFuncs
#
import os
import pytest
pytest.importorskip('ly_test_tools')
import logging
import sys
import os
sys.path.append(os.path.dirname(__file__))
from hydra_utils import launch_test_case
# Bail on the test if ly_test_tools doesn't exist.
pytest.importorskip("ly_test_tools")
import ly_test_tools.environment.file_system as file_system
import automatedtesting_shared.hydra_test_utils as hydra
logger = logging.getLogger(__name__)
test_directory = os.path.join(os.path.dirname(__file__), "EditorScripts")
@pytest.mark.SUITE_sandbox
@pytest.mark.parametrize('launcher_platform', ['windows_editor'])
@pytest.mark.parametrize('project', ['AutomatedTesting'])
@pytest.mark.parametrize('level', ['Simple'])
class TestComponentAssetAutomation(object):
@pytest.mark.parametrize("project", ["AutomatedTesting"])
@pytest.mark.parametrize("level", ["tmp_level"])
@pytest.mark.usefixtures("automatic_process_killer")
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
class TestComponentAssetListAutomation(object):
@pytest.fixture(autouse=True)
def setup_teardown(self, request, workspace, project, level):
# Cleanup our temp level
file_system.delete([os.path.join(workspace.paths.dev(), project, "Levels", level)], True, True)
def teardown():
# Cleanup our temp level
file_system.delete([os.path.join(workspace.paths.dev(), project, "Levels", level)], True, True)
request.addfinalizer(teardown)
def test_ComponentAsset(self, request, editor, level, launcher_platform):
def test_ComponentAssetList(self, request, editor, level, launcher_platform):
unexpected_lines=[]
expected_lines = [
'Set EditorDescriptorListComponent Embedded Assets as List',
'Set EditorDescriptorListComponent Embedded Assets 0 Descriptor Mesh Asset ID',
@ -37,7 +48,12 @@ class TestComponentAssetAutomation(object):
'Set EditorDescriptorListComponent Embedded Assets 2 Descriptor Mesh Asset ID',
'Set EditorDescriptorListComponent Embedded Assets 3 Descriptor Mesh Asset ID'
]
test_case_file = os.path.join(os.path.dirname(__file__), 'ComponentUpdateListProperty_test_case.py')
launch_test_case(editor, test_case_file, expected_lines, unexpected_lines)
hydra.launch_and_validate_results(
request,
test_directory,
editor,
"ComponentUpdateListProperty_test_case.py",
expected_lines=expected_lines,
cfg_args=[level]
)

@ -1,78 +0,0 @@
"""
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 azlmbr.object as object
import azlmbr.legacy.general as general
import azlmbr.editor as editor
import azlmbr.bus as bus
import azlmbr.entity as entity
import azlmbr.math as math
import azlmbr.asset as asset
def add_component_with_uuid(entityId, typeId):
componentOutcome = editor.EditorComponentAPIBus(bus.Broadcast, 'AddComponentsOfType', entityId, [typeId])
if (componentOutcome.IsSuccess()):
return componentOutcome.GetValue()[0]
def set_component_property(component, path, value):
outcome = editor.EditorComponentAPIBus(bus.Broadcast, 'SetComponentProperty', component, path, value)
return outcome.IsSuccess()
def get_component_property(component, path):
outcome = editor.EditorComponentAPIBus(bus.Broadcast, 'GetComponentProperty', component, path)
if (outcome.IsSuccess()):
return outcome.GetValue()
return None
try:
# Open a level
print ('Test started')
general.open_level_no_prompt('auto_test')
newEntityId = editor.ToolsApplicationRequestBus(bus.Broadcast, 'CreateNewEntity', entity.EntityId())
editorDescriptorListComponentId = math.Uuid_CreateString('{3AF9BE58-6D2D-44FB-AB4D-CA1182F6C78F}', 0)
descListComponent = add_component_with_uuid(newEntityId, editorDescriptorListComponentId)
print ('descListComponent added')
primitiveCubeId = asset.AssetCatalogRequestBus(bus.Broadcast, 'GetAssetIdByPath', 'objects/default/primitive_cube.cgf', math.Uuid(), False)
primitiveSphereId = asset.AssetCatalogRequestBus(bus.Broadcast, 'GetAssetIdByPath', 'objects/default/primitive_sphere.cgf', math.Uuid(), False)
primitiveCapsuleId = asset.AssetCatalogRequestBus(bus.Broadcast, 'GetAssetIdByPath', 'objects/default/primitive_capsule.cgf', math.Uuid(), False)
primitivePlaneId = asset.AssetCatalogRequestBus(bus.Broadcast, 'GetAssetIdByPath', 'objects/default/primitive_plane.cgf', math.Uuid(), False)
print ('fetched asset ids')
# expand the list of veg descriptors to 4 elements
descList = get_component_property(descListComponent, 'Configuration|Embedded Assets')
print('Got the veg descriptor list')
descElem = descList[0]
descList.append(descElem)
descList.append(descElem)
descList.append(descElem)
set_component_property(descListComponent, 'Configuration|Embedded Assets', descList)
print('Set EditorDescriptorListComponent Embedded Assets as List')
set_component_property(descListComponent, 'Configuration|Embedded Assets|[0]|Instance|Mesh Asset', primitiveCubeId)
print('Set EditorDescriptorListComponent Embedded Assets 0 Descriptor Mesh Asset ID')
set_component_property(descListComponent, 'Configuration|Embedded Assets|[1]|Instance|Mesh Asset', primitiveSphereId)
print('Set EditorDescriptorListComponent Embedded Assets 1 Descriptor Mesh Asset ID')
set_component_property(descListComponent, 'Configuration|Embedded Assets|[2]|Instance|Mesh Asset', primitiveCapsuleId)
print('Set EditorDescriptorListComponent Embedded Assets 2 Descriptor Mesh Asset ID')
set_component_property(descListComponent, 'Configuration|Embedded Assets|[3]|Instance|Mesh Asset', primitivePlaneId)
print('Set EditorDescriptorListComponent Embedded Assets 3 Descriptor Mesh Asset ID')
except:
print ('Test failed.')
finally:
print ('Test done.')
general.exit_no_prompt()

@ -0,0 +1,87 @@
"""
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 sys
import azlmbr.asset as asset
import azlmbr.bus as bus
import azlmbr.editor as editor
import azlmbr.entity as entity
import azlmbr.math as math
import azlmbr.paths
sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests'))
from automatedtesting_shared.editor_test_helper import EditorTestHelper
def add_component_with_uuid(entityId, typeId):
componentOutcome = editor.EditorComponentAPIBus(bus.Broadcast, 'AddComponentsOfType', entityId, [typeId])
if (componentOutcome.IsSuccess()):
return componentOutcome.GetValue()[0]
def set_component_property(component, path, value):
outcome = editor.EditorComponentAPIBus(bus.Broadcast, 'SetComponentProperty', component, path, value)
return outcome.IsSuccess()
def get_component_property(component, path):
outcome = editor.EditorComponentAPIBus(bus.Broadcast, 'GetComponentProperty', component, path)
if (outcome.IsSuccess()):
return outcome.GetValue()
return None
class TestComponentUpdateListProperty(EditorTestHelper):
def __init__(self):
EditorTestHelper.__init__(self, log_prefix="ComponentUpdateListProperty", args=["level"])
def run_test(self):
"""
Test configuring an asset descriptor list.
"""
# Create a new level
self.test_success = self.create_level(
self.args["level"],
)
newEntityId = editor.ToolsApplicationRequestBus(bus.Broadcast, 'CreateNewEntity', entity.EntityId())
editorDescriptorListComponentId = math.Uuid_CreateString('{3AF9BE58-6D2D-44FB-AB4D-CA1182F6C78F}', 0)
descListComponent = add_component_with_uuid(newEntityId, editorDescriptorListComponentId)
primitiveCubeId = asset.AssetCatalogRequestBus(bus.Broadcast, 'GetAssetIdByPath', 'objects/default/primitive_cube.cgf', math.Uuid(), False)
primitiveSphereId = asset.AssetCatalogRequestBus(bus.Broadcast, 'GetAssetIdByPath', 'objects/default/primitive_sphere.cgf', math.Uuid(), False)
primitiveCapsuleId = asset.AssetCatalogRequestBus(bus.Broadcast, 'GetAssetIdByPath', 'objects/default/primitive_capsule.cgf', math.Uuid(), False)
primitivePlaneId = asset.AssetCatalogRequestBus(bus.Broadcast, 'GetAssetIdByPath', 'objects/default/primitive_plane.cgf', math.Uuid(), False)
# expand the list of veg descriptors to 4 elements
descList = get_component_property(descListComponent, 'Configuration|Embedded Assets')
descElem = descList[0]
descList.append(descElem)
descList.append(descElem)
descList.append(descElem)
self.test_success = set_component_property(descListComponent, 'Configuration|Embedded Assets', descList) and self.test_success
print('Set EditorDescriptorListComponent Embedded Assets as List')
self.test_success = set_component_property(descListComponent, 'Configuration|Embedded Assets|[0]|Instance|Mesh Asset', primitiveCubeId) and self.test_success
print('Set EditorDescriptorListComponent Embedded Assets 0 Descriptor Mesh Asset ID')
self.test_success = set_component_property(descListComponent, 'Configuration|Embedded Assets|[1]|Instance|Mesh Asset', primitiveSphereId) and self.test_success
print('Set EditorDescriptorListComponent Embedded Assets 1 Descriptor Mesh Asset ID')
self.test_success = set_component_property(descListComponent, 'Configuration|Embedded Assets|[2]|Instance|Mesh Asset', primitiveCapsuleId) and self.test_success
print('Set EditorDescriptorListComponent Embedded Assets 2 Descriptor Mesh Asset ID')
self.test_success = set_component_property(descListComponent, 'Configuration|Embedded Assets|[3]|Instance|Mesh Asset', primitivePlaneId) and self.test_success
print('Set EditorDescriptorListComponent Embedded Assets 3 Descriptor Mesh Asset ID')
test = TestComponentUpdateListProperty()
test.run()

@ -36,10 +36,10 @@ class TestViewPaneAutomation(object):
"get_viewport_expansion_policy works",
"set_viewport_expansion_policy works",
"get_view_pane_layout works",
"set_view_pane_layout works",
"get_viewport_count works",
"get_active_viewport works",
"set_active_viewport works"
"set_view_pane_layout works"
# "get_viewport_count works",
# "get_active_viewport works",
# "set_active_viewport works"
]
test_case_file = os.path.join(os.path.dirname(__file__), 'ViewPaneCommands_test_case.py')

@ -73,31 +73,32 @@ if (set_and_validate_viewport_size(150, 300)):
# Set different view pane layouts and verify it works
success = True
general.set_view_pane_layout(0)
#general.set_view_pane_layout(0)
general.idle_wait(0.5)
success = success and (general.get_view_pane_layout() == 0)
success = success and (general.get_viewport_count() == 1)
general.set_view_pane_layout(1)
general.idle_wait(0.5)
success = success and (general.get_view_pane_layout() == 1)
success = success and (general.get_viewport_count() == 2)
# general.set_view_pane_layout(1)
# general.idle_wait(0.5)
# success = success and (general.get_view_pane_layout() == 1)
# success = success and (general.get_viewport_count() == 2)
if success:
print("get_view_pane_layout works")
print("set_view_pane_layout works")
print("get_viewport_count works")
success = True
general.set_active_viewport(0)
general.idle_wait(0.5)
success = success and (general.get_active_viewport() == 0)
general.set_active_viewport(1)
general.idle_wait(0.5)
success = success and (general.get_active_viewport() == 1)
if success:
print("get_active_viewport works")
print("set_active_viewport works")
general.set_view_pane_layout(0)
#success = True
#general.set_active_viewport(0)
#general.idle_wait(0.5)
#success = success and (general.get_active_viewport() == 0)
#general.set_active_viewport(1)
#general.idle_wait(0.5)
#success = success and (general.get_active_viewport() == 1)
#if success:
# print("get_active_viewport works")
# print("set_active_viewport works")
#general.set_view_pane_layout(0)
general.idle_wait(0.5)
editor.EditorToolsApplicationRequestBus(bus.Broadcast, 'ExitNoPrompt')

@ -264,7 +264,7 @@ class FileManagement:
"""
root_path = parent_path
if root_path is not None:
root_path = os.path.join(workspace.paths.dev(), root_path)
root_path = os.path.join(workspace.paths.engine_root(), root_path)
else:
# Default to project folder (AutomatedTesting)
root_path = workspace.paths.project()
@ -325,7 +325,7 @@ class FileManagement:
"""
root_path = parent_path
if root_path is not None:
root_path = os.path.join(workspace.paths.dev(), root_path)
root_path = os.path.join(workspace.paths.engine_root(), root_path)
else:
# Default to project folder (AutomatedTesting)
root_path = workspace.paths.project()

@ -23,7 +23,7 @@ from . import ap_setup_fixture as ap_setup_fixture
@pytest.fixture
def ap_all_platforms_setup_fixture(request, workspace, ap_setup_fixture) -> Dict[str, str]:
dev_dir = os.path.join(workspace.paths.dev())
dev_dir = os.path.join(workspace.paths.engine_root())
cache_dir = workspace.paths.cache()
# add some useful locations

@ -10,7 +10,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Pytest fixture for standardizing key external project file locations.
Houses a mock workspace for the external project. Only has enough information
to satisfy a ly_test_tools.lumberyard.asset_processor.AssetProcessor object.
to satisfy a ly_test_tools.o3de.asset_processor.AssetProcessor object.
"""

@ -19,8 +19,8 @@ import logging
# ly-shared import
from automatedtesting_shared.platform_setting import PlatformSetting
from ly_test_tools.lumberyard.pipeline_utils import AP_FASTSCAN_KEY as fast_scan_key
from ly_test_tools.lumberyard.pipeline_utils import AP_FASTSCAN_SUBKEY as fast_scan_subkey
from ly_test_tools.o3de.pipeline_utils import AP_FASTSCAN_KEY as fast_scan_key
from ly_test_tools.o3de.pipeline_utils import AP_FASTSCAN_SUBKEY as fast_scan_subkey
logger = logging.getLogger(__name__)

@ -21,7 +21,7 @@ from . import ap_setup_fixture
# Import LyTestTools
import ly_test_tools.environment.waiter as waiter
from ly_test_tools.lumberyard.ap_log_parser import APLogParser
from ly_test_tools.o3de.ap_log_parser import APLogParser
@pytest.mark.usefixtures("test_assets")

@ -21,7 +21,7 @@ from typing import Dict, List, Tuple, Any, Set
from ly_test_tools.environment.file_system import create_backup, restore_backup, unlock_file
from automatedtesting_shared import asset_database_utils as db_utils
from ly_test_tools.lumberyard.ap_log_parser import APLogParser
from ly_test_tools.o3de.ap_log_parser import APLogParser
from . import ap_setup_fixture as ap_setup_fixture

@ -16,7 +16,7 @@ import os
import time
import pytest
from typing import Dict
from ly_test_tools.lumberyard.asset_processor import ASSET_PROCESSOR_PLATFORM_MAP
from ly_test_tools.o3de.asset_processor import ASSET_PROCESSOR_PLATFORM_MAP
@pytest.fixture
def ap_setup_fixture(request, workspace) -> Dict:
@ -42,8 +42,8 @@ def ap_setup_fixture(request, workspace) -> Dict:
"ap_batch_log_file": workspace.paths.ap_batch_log(),
# Path to AP_GUI.log
"ap_logFile": workspace.paths.ap_gui_log(),
# Path to the dev directory
"dev_dir": workspace.paths.dev(),
# Path to the engine root directory
"engine_dir": workspace.paths.engine_root(),
# Path to the current project directory
"project_dir": workspace.paths.project(),
# Path to AP Batch file
@ -56,7 +56,7 @@ def ap_setup_fixture(request, workspace) -> Dict:
# Changing modtime of UserSettings.xml so it is always processed by AssetProcessorBatch
# to prevent unexpected processing
user_settings_file = os.path.join(workspace.paths.dev(), "UserSettings.xml")
user_settings_file = os.path.join(workspace.paths.project(), "user", "UserSettings.xml")
if os.path.exists(user_settings_file):
timestamp = time.time()
os.utime(user_settings_file, (timestamp, timestamp))

@ -18,7 +18,7 @@ import pytest
import logging
# Import LyTestTools
import ly_test_tools.lumberyard.asset_processor as asset_processor_commands
import ly_test_tools.o3de.asset_processor as asset_processor_commands
logger = logging.getLogger(__name__)
@ -28,7 +28,7 @@ def asset_processor(request: pytest.fixture, workspace: pytest.fixture) -> asset
"""
Sets up usage of the asset proc
:param request:
:return: ly_test_tools.lumberyard.asset_processor.AssetProcessor
:return: ly_test_tools.03de.asset_processor.AssetProcessor
"""
# Initialize the Asset Processor

@ -26,8 +26,8 @@ from . import timeout_option_fixture as timeout
from . import ap_config_backup_fixture as config_backup
import ly_test_tools.environment.file_system as fs
import ly_test_tools.lumberyard.pipeline_utils as utils
from ly_test_tools.lumberyard.asset_processor import ASSET_PROCESSOR_PLATFORM_MAP
import ly_test_tools.o3de.pipeline_utils as utils
from ly_test_tools.o3de.asset_processor import ASSET_PROCESSOR_PLATFORM_MAP
logger = logging.getLogger(__name__)
@ -66,7 +66,7 @@ def bundler_batch_setup_fixture(request, workspace, asset_processor, timeout) ->
self.bundler_batch = os.path.join(self.bin_dir, "AssetBundlerBatch")
self.test_dir = tempDir
self.asset_alias = workspace.paths.platform_cache()
self.tools_dir = os.path.join(workspace.paths.dev(), "Tools")
self.tools_dir = os.path.join(workspace.paths.engine_root(), "Tools")
self.seed_list_file_name = "testSeedListFile.seed"
self.seed_list_file = os.path.join(self.test_dir, self.seed_list_file_name)
self.asset_info_file_name = "assetFileInfo.assetlist"
@ -297,7 +297,7 @@ def bundler_batch_setup_fixture(request, workspace, asset_processor, timeout) ->
Note: the platform's are bit flags, so their values are powers of 2: 1 << position_in_file
"""
platform_declaration_file = os.path.join(
workspace.paths.dev(),
workspace.paths.engine_root(),
"Code",
"Framework",
"AzFramework",

@ -15,14 +15,14 @@ Fixture for clearing out 'MoveOutput' folders from \dev and \dev\PROJECT
import pytest
# Import ly_shared
import ly_test_tools.lumberyard.pipeline_utils as pipeline_utils
import ly_test_tools.o3de.pipeline_utils as pipeline_utils
@pytest.fixture
def clear_moveoutput_fixture(request, workspace) -> None:
pipeline_utils.delete_MoveOutput_folders([workspace.paths.dev(), workspace.paths.project()])
pipeline_utils.delete_MoveOutput_folders([workspace.paths.engine_root(), workspace.paths.project()])
def teardown():
pipeline_utils.delete_MoveOutput_folders([workspace.paths.dev(), workspace.paths.project()])
pipeline_utils.delete_MoveOutput_folders([workspace.paths.engine_root(), workspace.paths.project()])
request.addfinalizer(teardown)

@ -26,6 +26,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS)
NAME AssetPipelineTests.Batch_2_Main
TEST_SUITE main
PATH ${CMAKE_CURRENT_LIST_DIR}/asset_processor_batch_tests_2.py
PYTEST_MARKS "not SUITE_sandbox" # don't run sandbox tests in this file
EXCLUDE_TEST_RUN_TARGET_FROM_IDE
RUNTIME_DEPENDENCIES
AZ::AssetProcessorBatch
@ -36,6 +37,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS)
NAME AssetPipelineTests.Batch_2_Sandbox
TEST_SUITE sandbox
PATH ${CMAKE_CURRENT_LIST_DIR}/asset_processor_batch_tests_2.py
PYTEST_MARKS "SUITE_sandbox" # run only sandbox tests in this file
EXCLUDE_TEST_RUN_TARGET_FROM_IDE
RUNTIME_DEPENDENCIES
AZ::AssetProcessorBatch
@ -75,6 +77,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS)
NAME AssetPipelineTests.Gui_2_Main
TEST_SUITE main
PATH ${CMAKE_CURRENT_LIST_DIR}/asset_processor_gui_tests_2.py
PYTEST_MARKS "not SUITE_sandbox" # don't run sandbox tests in this file
EXCLUDE_TEST_RUN_TARGET_FROM_IDE
RUNTIME_DEPENDENCIES
AZ::AssetProcessorBatch
@ -85,6 +88,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS)
NAME AssetPipelineTests.Gui_2_Sandbox
TEST_SUITE sandbox
PATH ${CMAKE_CURRENT_LIST_DIR}/asset_processor_gui_tests_2.py
PYTEST_MARKS "SUITE_sandbox" # run only sandbox tests in this file
EXCLUDE_TEST_RUN_TARGET_FROM_IDE
RUNTIME_DEPENDENCIES
AZ::AssetProcessorBatch

@ -25,8 +25,8 @@ from ..ap_fixtures.asset_processor_fixture import asset_processor as asset_proce
from ..ap_fixtures.ap_setup_fixture import ap_setup_fixture as ap_setup_fixture
# Import LyShared
import ly_test_tools.lumberyard.pipeline_utils as utils
from ly_test_tools.lumberyard.asset_processor import ASSET_PROCESSOR_PLATFORM_MAP
import ly_test_tools.o3de.pipeline_utils as utils
from ly_test_tools.o3de.asset_processor import ASSET_PROCESSOR_PLATFORM_MAP
# Use the following logging pattern to hook all test logging together:
logger = logging.getLogger(__name__)
# Configuring the logging is done in ly_test_tools at the following location:

@ -36,8 +36,8 @@ from ..ap_fixtures.bundler_batch_setup_fixture \
from ..ap_fixtures.ap_config_backup_fixture import ap_config_backup_fixture as config_backup
# Import LyShared
import ly_test_tools.lumberyard.pipeline_utils as utils
from ly_test_tools.lumberyard.asset_processor import ASSET_PROCESSOR_PLATFORM_MAP
import ly_test_tools.o3de.pipeline_utils as utils
from ly_test_tools.o3de.asset_processor import ASSET_PROCESSOR_PLATFORM_MAP
win_and_mac_platforms = [ASSET_PROCESSOR_PLATFORM_MAP['windows'],
ASSET_PROCESSOR_PLATFORM_MAP['mac']]
@ -302,7 +302,7 @@ class TestsAssetBundlerBatch_WindowsAndMac(object):
that generating debug information does not affect asset list creation
"""
helper = bundler_batch_helper
seed_list = os.path.join(workspace.paths.dev(), "Engine", "SeedAssetList.seed") # Engine seed list
seed_list = os.path.join(workspace.paths.engine_root(), "Engine", "SeedAssetList.seed") # Engine seed list
asset = r"levels\testdependencieslevel\level.pak"
# Create Asset list
@ -377,7 +377,7 @@ class TestsAssetBundlerBatch_WindowsAndMac(object):
subcommands.
"""
helper = bundler_batch_helper
seed_list = os.path.join(workspace.paths.dev(), "Engine", "SeedAssetList.seed") # Engine seed list
seed_list = os.path.join(workspace.paths.engine_root(), "Engine", "SeedAssetList.seed") # Engine seed list
asset = r"levels\testdependencieslevel\level.pak"
# Useful bundle locations / names (2 for comparing contents)
@ -465,7 +465,7 @@ class TestsAssetBundlerBatch_WindowsAndMac(object):
"Please rerun with commandline option: '--bundle_platforms=pc,osx_gl'"
# fmt:on
seed_list = os.path.join(workspace.paths.dev(), "Engine", "SeedAssetList.seed") # Engine seed list
seed_list = os.path.join(workspace.paths.engine_root(), "Engine", "SeedAssetList.seed") # Engine seed list
# Useful bundle / asset list locations
bundle_dir = os.path.dirname(helper["bundle_file"])
@ -1109,7 +1109,7 @@ class TestsAssetBundlerBatch_WindowsAndMac(object):
# Make sure file gets deleted on teardown
request.addfinalizer(lambda: fs.delete([bundle_result_path], True, False))
bundles_folder = os.path.join(workspace.paths.dev(), workspace.project, "Bundles")
bundles_folder = os.path.join(workspace.paths.engine_root(), workspace.project, "Bundles")
level_pak = r"levels\testdependencieslevel\level.pak"
bundle_request_path = os.path.join(bundles_folder, "bundle.pak")
bundle_result_path = os.path.join(bundles_folder,

@ -24,8 +24,8 @@ from ..ap_fixtures.ap_setup_fixture import ap_setup_fixture as ap_setup_fixture
# Import LyShared
from automatedtesting_shared import file_utils as file_utils
from ly_test_tools.lumberyard.ap_log_parser import APLogParser, APOutputParser
import ly_test_tools.lumberyard.pipeline_utils as utils
from ly_test_tools.o3de.ap_log_parser import APLogParser, APOutputParser
import ly_test_tools.o3de.pipeline_utils as utils
# Use the following logging pattern to hook all test logging together:
logger = logging.getLogger(__name__)

@ -24,8 +24,8 @@ from ..ap_fixtures.ap_setup_fixture import ap_setup_fixture as ap_setup_fixture
# Import LyShared
from automatedtesting_shared import file_utils as file_utils
from ly_test_tools.lumberyard.ap_log_parser import APLogParser, APOutputParser
import ly_test_tools.lumberyard.pipeline_utils as utils
from ly_test_tools.o3de.ap_log_parser import APLogParser, APOutputParser
import ly_test_tools.o3de.pipeline_utils as utils
# Use the following logging pattern to hook all test logging together:
logger = logging.getLogger(__name__)
@ -69,7 +69,7 @@ class TestsAssetProcessorBatch_DependenycyTests(object):
asset_processor.add_scan_folder("Gems/LyShineExamples/Assets")
gem_asset_path = "Gems/CertificateManager/Assets"
asset_processor.add_scan_folder(gem_asset_path)
engine_schema_path = os.path.join(workspace.paths.dev(), "Engine", "Schema")
engine_schema_path = os.path.join(workspace.paths.engine_root(), "Engine", "Schema")
gem_schema_path = os.path.join(asset_processor.temp_asset_root(), gem_asset_path, "Schema")
# EXPECT Assets process successfully

@ -18,7 +18,7 @@ import os
import stat
# Import LyTestTools
from ly_test_tools.lumberyard import asset_processor as asset_processor_utils
from ly_test_tools.o3de import asset_processor as asset_processor_utils
# Import fixtures
from ..ap_fixtures.asset_processor_fixture import asset_processor as asset_processor
@ -26,8 +26,8 @@ from ..ap_fixtures.ap_setup_fixture import ap_setup_fixture as ap_setup_fixture
# Import LyShared
from ly_test_tools.lumberyard.ap_log_parser import APLogParser, APOutputParser
import ly_test_tools.lumberyard.pipeline_utils as utils
from ly_test_tools.o3de.ap_log_parser import APLogParser, APOutputParser
import ly_test_tools.o3de.pipeline_utils as utils
# Use the following logging pattern to hook all test logging together:
logger = logging.getLogger(__name__)

@ -19,8 +19,8 @@ import subprocess
# Import LyTestTools
from ly_test_tools.lumberyard.asset_processor import AssetProcessor
from ly_test_tools.lumberyard import asset_processor as asset_processor_utils
from ly_test_tools.o3de.asset_processor import AssetProcessor
from ly_test_tools.o3de import asset_processor as asset_processor_utils
import ly_test_tools.environment.file_system as fs
# Import fixtures
@ -29,8 +29,8 @@ from ..ap_fixtures.ap_setup_fixture import ap_setup_fixture as ap_setup_fixture
# Import LyShared
from ly_test_tools.lumberyard.ap_log_parser import APLogParser, APOutputParser
import ly_test_tools.lumberyard.pipeline_utils as utils
from ly_test_tools.o3de.ap_log_parser import APLogParser, APOutputParser
import ly_test_tools.o3de.pipeline_utils as utils
# Use the following logging pattern to hook all test logging together:
logger = logging.getLogger(__name__)

@ -25,8 +25,8 @@ import ly_test_tools.environment.waiter as waiter
import ly_test_tools.environment.file_system as fs
import ly_test_tools.environment.process_utils as process_utils
import ly_test_tools.launchers.launcher_helper as launcher_helper
from ly_test_tools.lumberyard.asset_processor import ASSET_PROCESSOR_PLATFORM_MAP
from ly_test_tools.lumberyard.asset_processor import AssetProcessorError
from ly_test_tools.o3de.asset_processor import ASSET_PROCESSOR_PLATFORM_MAP
from ly_test_tools.o3de.asset_processor import AssetProcessorError
# Import fixtures
from ..ap_fixtures.asset_processor_fixture import asset_processor as asset_processor
@ -38,7 +38,7 @@ from ..ap_fixtures.ap_fast_scan_setting_backup_fixture import (
# Import LyShared
import ly_test_tools.lumberyard.pipeline_utils as utils
import ly_test_tools.o3de.pipeline_utils as utils
# Use the following logging pattern to hook all test logging together:
logger = logging.getLogger(__name__)

@ -25,7 +25,7 @@ import ly_test_tools.environment.waiter as waiter
import ly_test_tools.environment.file_system as fs
import ly_test_tools.environment.process_utils as process_utils
import ly_test_tools.launchers.launcher_helper as launcher_helper
from ly_test_tools.lumberyard.asset_processor import ASSET_PROCESSOR_PLATFORM_MAP, ASSET_PROCESSOR_SETTINGS_ROOT_KEY
from ly_test_tools.o3de.asset_processor import ASSET_PROCESSOR_PLATFORM_MAP, ASSET_PROCESSOR_SETTINGS_ROOT_KEY
# Import fixtures
from ..ap_fixtures.asset_processor_fixture import asset_processor as asset_processor
@ -37,7 +37,7 @@ from ..ap_fixtures.ap_fast_scan_setting_backup_fixture import (
# Import LyShared
import ly_test_tools.lumberyard.pipeline_utils as utils
import ly_test_tools.o3de.pipeline_utils as utils
# Use the following logging pattern to hook all test logging together:
logger = logging.getLogger(__name__)

@ -26,8 +26,8 @@ from typing import List
import ly_test_tools.builtin.helpers as helpers
import ly_test_tools.environment.file_system as fs
import ly_test_tools.environment.process_utils as process_utils
from ly_test_tools.lumberyard import asset_processor as asset_processor_utils
from ly_test_tools.lumberyard.asset_processor import ASSET_PROCESSOR_PLATFORM_MAP
from ly_test_tools.o3de import asset_processor as asset_processor_utils
from ly_test_tools.o3de.asset_processor import ASSET_PROCESSOR_PLATFORM_MAP
# Import fixtures
from ..ap_fixtures.asset_processor_fixture import asset_processor as asset_processor
@ -37,7 +37,7 @@ from ..ap_fixtures.clear_moveoutput_fixture import clear_moveoutput_fixture as c
from ..ap_fixtures.clear_testingAssets_dir import clear_testingAssets_dir as clear_testingAssets_dir
# Import LyShared
import ly_test_tools.lumberyard.pipeline_utils as utils
import ly_test_tools.o3de.pipeline_utils as utils
# Use the following logging pattern to hook all test logging together:
logger = logging.getLogger(__name__)

@ -1,223 +1,222 @@
<ObjectStream version="3">
<Class name="AZ::Entity" version="2" type="{75651658-8663-478D-9090-2432DFCAFA44}">
<Class name="EntityId" field="Id" version="1" type="{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}">
<Class name="AZ::u64" field="id" value="269594828358" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
<Class name="AZ::Entity" type="{75651658-8663-478D-9090-2432DFCAFA44}" version="2">
<Class field="Id" name="EntityId" type="{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}" version="1">
<Class field="id" name="AZ::u64" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}" value="269594828358" />
</Class>
<Class name="AZStd::string" field="Name" value="Slice" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
<Class name="AZStd::vector" field="Components" type="{13D58FF9-1088-5C69-9A1F-C2A144B57B78}">
<Class name="SliceComponent" field="element" version="3" type="{AFD304E4-1773-47C8-855A-8B622398934F}">
<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
<Class name="AZ::u64" field="Id" value="13642727600084297375" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
<Class field="Name" name="AZStd::string" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}" value="Slice" />
<Class field="Components" name="AZStd::vector" type="{13D58FF9-1088-5C69-9A1F-C2A144B57B78}">
<Class field="element" name="SliceComponent" type="{AFD304E4-1773-47C8-855A-8B622398934F}" version="3">
<Class field="BaseClass1" name="AZ::Component" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
<Class field="Id" name="AZ::u64" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}" value="13642727600084297375" />
</Class>
<Class name="AZStd::vector" field="Entities" type="{21786AF0-2606-5B9A-86EB-0892E2820E6C}">
<Class name="AZ::Entity" field="element" version="2" type="{75651658-8663-478D-9090-2432DFCAFA44}">
<Class name="EntityId" field="Id" version="1" type="{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}">
<Class name="AZ::u64" field="id" value="278184762950" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
<Class field="Entities" name="AZStd::vector" type="{21786AF0-2606-5B9A-86EB-0892E2820E6C}">
<Class field="element" name="AZ::Entity" type="{75651658-8663-478D-9090-2432DFCAFA44}" version="2">
<Class field="Id" name="EntityId" type="{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}" version="1">
<Class field="id" name="AZ::u64" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}" value="278184762950" />
</Class>
<Class name="AZStd::string" field="Name" value="TestE" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
<Class name="AZStd::vector" field="Components" type="{13D58FF9-1088-5C69-9A1F-C2A144B57B78}">
<Class name="EditorOnlyEntityComponent" field="element" type="{22A16F1D-6D49-422D-AAE9-91AE45B5D3E7}">
<Class name="EditorComponentBase" field="BaseClass1" version="1" type="{D5346BD4-7F20-444E-B370-327ACD03D4A0}">
<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
<Class name="AZ::u64" field="Id" value="16738199190794244171" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
<Class field="Name" name="AZStd::string" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}" value="TestE" />
<Class field="Components" name="AZStd::vector" type="{13D58FF9-1088-5C69-9A1F-C2A144B57B78}">
<Class field="element" name="EditorOnlyEntityComponent" type="{22A16F1D-6D49-422D-AAE9-91AE45B5D3E7}">
<Class field="BaseClass1" name="EditorComponentBase" type="{D5346BD4-7F20-444E-B370-327ACD03D4A0}" version="1">
<Class field="BaseClass1" name="AZ::Component" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
<Class field="Id" name="AZ::u64" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}" value="16738199190794244171" />
</Class>
</Class>
<Class name="bool" field="IsEditorOnly" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
<Class field="IsEditorOnly" name="bool" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}" value="false" />
</Class>
<Class name="TransformComponent" field="element" version="9" type="{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0}">
<Class name="EditorComponentBase" field="BaseClass1" version="1" type="{D5346BD4-7F20-444E-B370-327ACD03D4A0}">
<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
<Class name="AZ::u64" field="Id" value="16210900323787785224" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
</Class>
</Class>
<Class name="EntityId" field="Parent Entity" version="1" type="{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}">
<Class name="AZ::u64" field="id" value="4294967295" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
</Class>
<Class name="EditorTransform" field="Transform Data" version="2" type="{B02B7063-D238-4F40-A724-405F7A6D68CB}">
<Class name="Vector3" field="Translate" value="0.0000000 0.0000000 0.0000000" type="{8379EB7D-01FA-4538-B64B-A6543B4BE73D}"/>
<Class name="Vector3" field="Rotate" value="0.0000000 0.0000000 0.0000000" type="{8379EB7D-01FA-4538-B64B-A6543B4BE73D}"/>
<Class name="Vector3" field="Scale" value="1.0000000 1.0000000 1.0000000" type="{8379EB7D-01FA-4538-B64B-A6543B4BE73D}"/>
<Class name="bool" field="Locked" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
</Class>
<Class name="Transform" field="Cached World Transform" value="1.0000000 0.0000000 0.0000000 0.0000000 1.0000000 0.0000000 0.0000000 0.0000000 1.0000000 0.0000000 0.0000000 0.0000000" type="{5D9958E9-9F1E-4985-B532-FFFDE75FEDFD}"/>
<Class name="EntityId" field="Cached World Transform Parent" version="1" type="{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}">
<Class name="AZ::u64" field="id" value="4294967295" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
</Class>
<Class name="unsigned int" field="Parent Activation Transform Mode" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="bool" field="IsStatic" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
<Class name="bool" field="Sync Enabled" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
<Class name="unsigned int" field="InterpolatePosition" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="unsigned int" field="InterpolateRotation" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class field="element" name="TransformComponent" type="{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0}" version="9">
<Class field="BaseClass1" name="EditorComponentBase" type="{D5346BD4-7F20-444E-B370-327ACD03D4A0}" version="1">
<Class field="BaseClass1" name="AZ::Component" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
<Class field="Id" name="AZ::u64" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}" value="16210900323787785224" />
</Class>
</Class>
<Class field="Parent Entity" name="EntityId" type="{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}" version="1">
<Class field="id" name="AZ::u64" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}" value="4294967295" />
</Class>
<Class field="Transform Data" name="EditorTransform" type="{B02B7063-D238-4F40-A724-405F7A6D68CB}" version="2">
<Class field="Translate" name="Vector3" type="{8379EB7D-01FA-4538-B64B-A6543B4BE73D}" value="0.0000000 0.0000000 0.0000000" />
<Class field="Rotate" name="Vector3" type="{8379EB7D-01FA-4538-B64B-A6543B4BE73D}" value="0.0000000 0.0000000 0.0000000" />
<Class field="Scale" name="Vector3" type="{8379EB7D-01FA-4538-B64B-A6543B4BE73D}" value="1.0000000 1.0000000 1.0000000" />
<Class field="Locked" name="bool" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}" value="false" />
</Class>
<Class field="Cached World Transform" name="Transform" type="{5D9958E9-9F1E-4985-B532-FFFDE75FEDFD}" value="1.0000000 0.0000000 0.0000000 0.0000000 1.0000000 0.0000000 0.0000000 0.0000000 1.0000000 0.0000000 0.0000000 0.0000000" />
<Class field="Cached World Transform Parent" name="EntityId" type="{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}" version="1">
<Class field="id" name="AZ::u64" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}" value="4294967295" />
</Class>
<Class field="Parent Activation Transform Mode" name="unsigned int" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}" value="0" />
<Class field="IsStatic" name="bool" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}" value="false" />
<Class field="Sync Enabled" name="bool" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}" value="false" />
<Class field="InterpolatePosition" name="unsigned int" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}" value="0" />
<Class field="InterpolateRotation" name="unsigned int" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}" value="0" />
</Class>
<Class name="EditorInspectorComponent" field="element" version="2" type="{47DE3DDA-50C5-4F50-B1DB-BA4AE66AB056}">
<Class name="EditorComponentBase" field="BaseClass1" version="1" type="{D5346BD4-7F20-444E-B370-327ACD03D4A0}">
<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
<Class name="AZ::u64" field="Id" value="7735546012552452863" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
<Class field="element" name="EditorInspectorComponent" type="{47DE3DDA-50C5-4F50-B1DB-BA4AE66AB056}" version="2">
<Class field="BaseClass1" name="EditorComponentBase" type="{D5346BD4-7F20-444E-B370-327ACD03D4A0}" version="1">
<Class field="BaseClass1" name="AZ::Component" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
<Class field="Id" name="AZ::u64" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}" value="7735546012552452863" />
</Class>
</Class>
<Class name="AZStd::vector" field="ComponentOrderEntryArray" type="{B6EFED5B-19B4-5084-9D92-42DECCE83872}">
<Class name="ComponentOrderEntry" field="element" version="1" type="{335C5861-5197-4DD5-A766-EF2B551B0D9D}">
<Class name="AZ::u64" field="ComponentId" value="16210900323787785224" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
<Class name="AZ::u64" field="SortIndex" value="0" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
<Class field="ComponentOrderEntryArray" name="AZStd::vector" type="{B6EFED5B-19B4-5084-9D92-42DECCE83872}">
<Class field="element" name="ComponentOrderEntry" type="{335C5861-5197-4DD5-A766-EF2B551B0D9D}" version="1">
<Class field="ComponentId" name="AZ::u64" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}" value="16210900323787785224" />
<Class field="SortIndex" name="AZ::u64" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}" value="0" />
</Class>
<Class name="ComponentOrderEntry" field="element" version="1" type="{335C5861-5197-4DD5-A766-EF2B551B0D9D}">
<Class name="AZ::u64" field="ComponentId" value="4070968465717414181" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
<Class name="AZ::u64" field="SortIndex" value="1" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
<Class field="element" name="ComponentOrderEntry" type="{335C5861-5197-4DD5-A766-EF2B551B0D9D}" version="1">
<Class field="ComponentId" name="AZ::u64" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}" value="4070968465717414181" />
<Class field="SortIndex" name="AZ::u64" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}" value="1" />
</Class>
<Class name="ComponentOrderEntry" field="element" version="1" type="{335C5861-5197-4DD5-A766-EF2B551B0D9D}">
<Class name="AZ::u64" field="ComponentId" value="8906495340202656540" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
<Class name="AZ::u64" field="SortIndex" value="2" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
<Class field="element" name="ComponentOrderEntry" type="{335C5861-5197-4DD5-A766-EF2B551B0D9D}" version="1">
<Class field="ComponentId" name="AZ::u64" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}" value="8906495340202656540" />
<Class field="SortIndex" name="AZ::u64" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}" value="2" />
</Class>
</Class>
</Class>
<Class name="EditorEntitySortComponent" field="element" version="2" type="{6EA1E03D-68B2-466D-97F7-83998C8C27F0}">
<Class name="EditorComponentBase" field="BaseClass1" version="1" type="{D5346BD4-7F20-444E-B370-327ACD03D4A0}">
<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
<Class name="AZ::u64" field="Id" value="9760814841523354339" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
<Class field="element" name="EditorEntitySortComponent" type="{6EA1E03D-68B2-466D-97F7-83998C8C27F0}" version="2">
<Class field="BaseClass1" name="EditorComponentBase" type="{D5346BD4-7F20-444E-B370-327ACD03D4A0}" version="1">
<Class field="BaseClass1" name="AZ::Component" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
<Class field="Id" name="AZ::u64" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}" value="9760814841523354339" />
</Class>
</Class>
<Class name="AZStd::vector" field="ChildEntityOrderEntryArray" type="{BE163120-C1ED-5F69-A650-DC2528A8FF94}"/>
<Class field="ChildEntityOrderEntryArray" name="AZStd::vector" type="{BE163120-C1ED-5F69-A650-DC2528A8FF94}" />
</Class>
<Class name="SelectionComponent" field="element" type="{73B724FC-43D1-4C75-ACF5-79AA8A3BF89D}">
<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
<Class name="AZ::u64" field="Id" value="8339376805608654145" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
<Class field="element" name="SelectionComponent" type="{73B724FC-43D1-4C75-ACF5-79AA8A3BF89D}">
<Class field="BaseClass1" name="AZ::Component" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
<Class field="Id" name="AZ::u64" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}" value="8339376805608654145" />
</Class>
</Class>
<Class name="EditorSpawnerComponent" field="element" version="1" type="{77CDE991-EC1A-B7C1-B112-7456ABAC81A1}">
<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
<Class name="AZ::u64" field="Id" value="4070968465717414181" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
<Class field="element" name="EditorSpawnerComponent" type="{77CDE991-EC1A-B7C1-B112-7456ABAC81A1}" version="1">
<Class field="BaseClass1" name="AZ::Component" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
<Class field="Id" name="AZ::u64" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}" value="4070968465717414181" />
</Class>
<Class name="Asset" field="Slice" value="id={F6621671-E624-53B1-BEB8-EB028B777B4C}:2,type={78802ABF-9595-463A-8D2B-D022F906F9B1},hint={assets_with_nested_preload_dependency/testd.dynamicslice}" version="1" type="{77A19D40-8731-4D3C-9041-1B43047366A4}"/>
<Class name="bool" field="SpawnOnActivate" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
<Class name="bool" field="DestroyOnDeactivate" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
<Class field="Slice" name="Asset" type="{77A19D40-8731-4D3C-9041-1B43047366A4}" value="id={F6621671-E624-53B1-BEB8-EB028B777B4C}:2,type={78802ABF-9595-463A-8D2B-D022F906F9B1},hint={assets_with_nested_preload_dependency/testd.dynamicslice}" version="1" />
<Class field="SpawnOnActivate" name="bool" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}" value="false" />
<Class field="DestroyOnDeactivate" name="bool" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}" value="false" />
</Class>
<Class name="EditorVisibilityComponent" field="element" type="{88E08E78-5C2F-4943-9F73-C115E6FFAB43}">
<Class name="EditorComponentBase" field="BaseClass1" version="1" type="{D5346BD4-7F20-444E-B370-327ACD03D4A0}">
<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
<Class name="AZ::u64" field="Id" value="10678724437556014335" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
<Class field="element" name="EditorVisibilityComponent" type="{88E08E78-5C2F-4943-9F73-C115E6FFAB43}">
<Class field="BaseClass1" name="EditorComponentBase" type="{D5346BD4-7F20-444E-B370-327ACD03D4A0}" version="1">
<Class field="BaseClass1" name="AZ::Component" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
<Class field="Id" name="AZ::u64" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}" value="10678724437556014335" />
</Class>
</Class>
<Class name="bool" field="VisibilityFlag" value="true" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
<Class field="VisibilityFlag" name="bool" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}" value="true" />
</Class>
<Class name="EditorActorComponent" field="element" version="4" type="{A863EE1B-8CFD-4EDD-BA0D-1CEC2879AD44}">
<Class name="EditorComponentBase" field="BaseClass1" version="1" type="{D5346BD4-7F20-444E-B370-327ACD03D4A0}">
<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
<Class name="AZ::u64" field="Id" value="8906495340202656540" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
<Class field="element" name="EditorActorComponent" type="{A863EE1B-8CFD-4EDD-BA0D-1CEC2879AD44}" version="4">
<Class field="BaseClass1" name="EditorComponentBase" type="{D5346BD4-7F20-444E-B370-327ACD03D4A0}" version="1">
<Class field="BaseClass1" name="AZ::Component" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
<Class field="Id" name="AZ::u64" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}" value="8906495340202656540" />
</Class>
</Class>
<Class name="Asset" field="ActorAsset" value="id={58BE9DA5-1F17-53B9-8CEE-EEB10E63454D}:914f19b7,type={F67CC648-EA51-464C-9F5D-4A9CE41A7F86},hint={objects/characters/jack/jack.actor}" version="1" type="{77A19D40-8731-4D3C-9041-1B43047366A4}"/>
<Class name="AZStd::vector" field="MaterialPerLOD" type="{BB800BD1-3E2D-5089-8423-F400597960FF}">
<Class name="AzFramework::SimpleAssetReference&lt;LmbrCentral::MaterialAsset&gt;" field="element" version="1" type="{B7B8ECC7-FF89-4A76-A50E-4C6CA2B6E6B4}">
<Class name="SimpleAssetReferenceBase" field="BaseClass1" version="1" type="{E16CA6C5-5C78-4AD9-8E9B-F8C1FB4D1DB8}">
<Class name="AZStd::string" field="AssetPath" value="objects/characters/jack/jack.mtl" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
<Class field="ActorAsset" name="Asset" type="{77A19D40-8731-4D3C-9041-1B43047366A4}" value="id={58BE9DA5-1F17-53B9-8CEE-EEB10E63454D}:914f19b7,type={F67CC648-EA51-464C-9F5D-4A9CE41A7F86},hint={objects/characters/jack/jack.actor}" version="1" />
<Class field="MaterialPerLOD" name="AZStd::vector" type="{BB800BD1-3E2D-5089-8423-F400597960FF}">
<Class field="element" name="AzFramework::SimpleAssetReference&lt;LmbrCentral::MaterialAsset&gt;" type="{B7B8ECC7-FF89-4A76-A50E-4C6CA2B6E6B4}" version="1">
<Class field="BaseClass1" name="SimpleAssetReferenceBase" type="{E16CA6C5-5C78-4AD9-8E9B-F8C1FB4D1DB8}" version="1">
<Class field="AssetPath" name="AZStd::string" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}" value="objects/characters/jack/jack.mtl" />
</Class>
</Class>
<Class name="AzFramework::SimpleAssetReference&lt;LmbrCentral::MaterialAsset&gt;" field="element" version="1" type="{B7B8ECC7-FF89-4A76-A50E-4C6CA2B6E6B4}">
<Class name="SimpleAssetReferenceBase" field="BaseClass1" version="1" type="{E16CA6C5-5C78-4AD9-8E9B-F8C1FB4D1DB8}">
<Class name="AZStd::string" field="AssetPath" value="objects/characters/jack/jack.mtl" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
<Class field="element" name="AzFramework::SimpleAssetReference&lt;LmbrCentral::MaterialAsset&gt;" type="{B7B8ECC7-FF89-4A76-A50E-4C6CA2B6E6B4}" version="1">
<Class field="BaseClass1" name="SimpleAssetReferenceBase" type="{E16CA6C5-5C78-4AD9-8E9B-F8C1FB4D1DB8}" version="1">
<Class field="AssetPath" name="AZStd::string" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}" value="objects/characters/jack/jack.mtl" />
</Class>
</Class>
<Class name="AzFramework::SimpleAssetReference&lt;LmbrCentral::MaterialAsset&gt;" field="element" version="1" type="{B7B8ECC7-FF89-4A76-A50E-4C6CA2B6E6B4}">
<Class name="SimpleAssetReferenceBase" field="BaseClass1" version="1" type="{E16CA6C5-5C78-4AD9-8E9B-F8C1FB4D1DB8}">
<Class name="AZStd::string" field="AssetPath" value="objects/characters/jack/jack.mtl" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
<Class field="element" name="AzFramework::SimpleAssetReference&lt;LmbrCentral::MaterialAsset&gt;" type="{B7B8ECC7-FF89-4A76-A50E-4C6CA2B6E6B4}" version="1">
<Class field="BaseClass1" name="SimpleAssetReferenceBase" type="{E16CA6C5-5C78-4AD9-8E9B-F8C1FB4D1DB8}" version="1">
<Class field="AssetPath" name="AZStd::string" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}" value="objects/characters/jack/jack.mtl" />
</Class>
</Class>
<Class name="AzFramework::SimpleAssetReference&lt;LmbrCentral::MaterialAsset&gt;" field="element" version="1" type="{B7B8ECC7-FF89-4A76-A50E-4C6CA2B6E6B4}">
<Class name="SimpleAssetReferenceBase" field="BaseClass1" version="1" type="{E16CA6C5-5C78-4AD9-8E9B-F8C1FB4D1DB8}">
<Class name="AZStd::string" field="AssetPath" value="objects/characters/jack/jack.mtl" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
<Class field="element" name="AzFramework::SimpleAssetReference&lt;LmbrCentral::MaterialAsset&gt;" type="{B7B8ECC7-FF89-4A76-A50E-4C6CA2B6E6B4}" version="1">
<Class field="BaseClass1" name="SimpleAssetReferenceBase" type="{E16CA6C5-5C78-4AD9-8E9B-F8C1FB4D1DB8}" version="1">
<Class field="AssetPath" name="AZStd::string" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}" value="objects/characters/jack/jack.mtl" />
</Class>
</Class>
</Class>
<Class name="AzFramework::SimpleAssetReference&lt;LmbrCentral::MaterialAsset&gt;" field="MaterialPerActor" version="1" type="{B7B8ECC7-FF89-4A76-A50E-4C6CA2B6E6B4}">
<Class name="SimpleAssetReferenceBase" field="BaseClass1" version="1" type="{E16CA6C5-5C78-4AD9-8E9B-F8C1FB4D1DB8}">
<Class name="AZStd::string" field="AssetPath" value="objects/characters/jack/jack.mtl" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
<Class field="MaterialPerActor" name="AzFramework::SimpleAssetReference&lt;LmbrCentral::MaterialAsset&gt;" type="{B7B8ECC7-FF89-4A76-A50E-4C6CA2B6E6B4}" version="1">
<Class field="BaseClass1" name="SimpleAssetReferenceBase" type="{E16CA6C5-5C78-4AD9-8E9B-F8C1FB4D1DB8}" version="1">
<Class field="AssetPath" name="AZStd::string" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}" value="objects/characters/jack/jack.mtl" />
</Class>
</Class>
<Class name="unsigned int" field="AttachmentType" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="EntityId" field="AttachmentTarget" version="1" type="{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}">
<Class name="AZ::u64" field="id" value="4294967295" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
<Class field="AttachmentType" name="unsigned int" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}" value="0" />
<Class field="AttachmentTarget" name="EntityId" type="{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}" version="1">
<Class field="id" name="AZ::u64" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}" value="4294967295" />
</Class>
<Class name="bool" field="RenderSkeleton" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
<Class name="bool" field="RenderCharacter" value="true" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
<Class name="bool" field="RenderBounds" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
<Class name="unsigned int" field="SkinningMethod" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="bool" field="UpdateJointTransformsWhenOutOfView" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
<Class name="unsigned int" field="LodLevel" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class field="RenderSkeleton" name="bool" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}" value="false" />
<Class field="RenderCharacter" name="bool" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}" value="true" />
<Class field="RenderBounds" name="bool" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}" value="false" />
<Class field="SkinningMethod" name="unsigned int" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}" value="0" />
<Class field="UpdateJointTransformsWhenOutOfView" name="bool" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}" value="false" />
<Class field="LodLevel" name="unsigned int" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}" value="0" />
</Class>
<Class name="EditorLockComponent" field="element" type="{C3A169C9-7EFB-4D6C-8710-3591680D0936}">
<Class name="EditorComponentBase" field="BaseClass1" version="1" type="{D5346BD4-7F20-444E-B370-327ACD03D4A0}">
<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
<Class name="AZ::u64" field="Id" value="2755228366872136502" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
<Class field="element" name="EditorLockComponent" type="{C3A169C9-7EFB-4D6C-8710-3591680D0936}">
<Class field="BaseClass1" name="EditorComponentBase" type="{D5346BD4-7F20-444E-B370-327ACD03D4A0}" version="1">
<Class field="BaseClass1" name="AZ::Component" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
<Class field="Id" name="AZ::u64" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}" value="2755228366872136502" />
</Class>
</Class>
<Class name="bool" field="Locked" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
<Class field="Locked" name="bool" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}" value="false" />
</Class>
<Class name="EditorPendingCompositionComponent" field="element" type="{D40FCB35-153D-45B3-AF6D-7BA576D8AFBB}">
<Class name="EditorComponentBase" field="BaseClass1" version="1" type="{D5346BD4-7F20-444E-B370-327ACD03D4A0}">
<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
<Class name="AZ::u64" field="Id" value="2364131805451940550" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
<Class field="element" name="EditorPendingCompositionComponent" type="{D40FCB35-153D-45B3-AF6D-7BA576D8AFBB}">
<Class field="BaseClass1" name="EditorComponentBase" type="{D5346BD4-7F20-444E-B370-327ACD03D4A0}" version="1">
<Class field="BaseClass1" name="AZ::Component" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
<Class field="Id" name="AZ::u64" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}" value="2364131805451940550" />
</Class>
</Class>
<Class name="AZStd::vector" field="PendingComponents" type="{13D58FF9-1088-5C69-9A1F-C2A144B57B78}"/>
<Class field="PendingComponents" name="AZStd::vector" type="{13D58FF9-1088-5C69-9A1F-C2A144B57B78}" />
</Class>
<Class name="EditorEntityIconComponent" field="element" type="{E15D42C2-912D-466F-9547-E7E948CE2D7D}">
<Class name="EditorComponentBase" field="BaseClass1" version="1" type="{D5346BD4-7F20-444E-B370-327ACD03D4A0}">
<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
<Class name="AZ::u64" field="Id" value="15019118415351685531" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
<Class field="element" name="EditorEntityIconComponent" type="{E15D42C2-912D-466F-9547-E7E948CE2D7D}">
<Class field="BaseClass1" name="EditorComponentBase" type="{D5346BD4-7F20-444E-B370-327ACD03D4A0}" version="1">
<Class field="BaseClass1" name="AZ::Component" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
<Class field="Id" name="AZ::u64" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}" value="15019118415351685531" />
</Class>
</Class>
<Class name="AssetId" field="EntityIconAssetId" version="1" type="{652ED536-3402-439B-AEBE-4A5DBC554085}">
<Class name="AZ::Uuid" field="guid" value="{00000000-0000-0000-0000-000000000000}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
<Class name="unsigned int" field="subId" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class field="EntityIconAssetId" name="AssetId" type="{652ED536-3402-439B-AEBE-4A5DBC554085}" version="1">
<Class field="guid" name="AZ::Uuid" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}" value="{00000000-0000-0000-0000-000000000000}" />
<Class field="subId" name="unsigned int" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}" value="0" />
</Class>
</Class>
<Class name="EditorDisabledCompositionComponent" field="element" type="{E77AE6AC-897D-4035-8353-637449B6DCFB}">
<Class name="EditorComponentBase" field="BaseClass1" version="1" type="{D5346BD4-7F20-444E-B370-327ACD03D4A0}">
<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
<Class name="AZ::u64" field="Id" value="12728572968760191789" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
<Class field="element" name="EditorDisabledCompositionComponent" type="{E77AE6AC-897D-4035-8353-637449B6DCFB}">
<Class field="BaseClass1" name="EditorComponentBase" type="{D5346BD4-7F20-444E-B370-327ACD03D4A0}" version="1">
<Class field="BaseClass1" name="AZ::Component" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
<Class field="Id" name="AZ::u64" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}" value="12728572968760191789" />
</Class>
</Class>
<Class name="AZStd::vector" field="DisabledComponents" type="{13D58FF9-1088-5C69-9A1F-C2A144B57B78}"/>
<Class field="DisabledComponents" name="AZStd::vector" type="{13D58FF9-1088-5C69-9A1F-C2A144B57B78}" />
</Class>
</Class>
<Class name="bool" field="IsDependencyReady" value="true" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
<Class name="bool" field="IsRuntimeActive" value="true" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
<Class field="IsDependencyReady" name="bool" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}" value="true" />
<Class field="IsRuntimeActive" name="bool" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}" value="true" />
</Class>
</Class>
<Class name="AZStd::list" field="Prefabs" type="{DAD45EB6-5853-5645-B762-3A37F8775E12}"/>
<Class name="bool" field="IsDynamic" value="true" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
<Class name="AZ::Entity" field="MetadataEntity" version="2" type="{75651658-8663-478D-9090-2432DFCAFA44}">
<Class name="EntityId" field="Id" version="1" type="{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}">
<Class name="AZ::u64" field="id" value="273889795654" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
<Class field="Prefabs" name="AZStd::list" type="{DAD45EB6-5853-5645-B762-3A37F8775E12}" />
<Class field="IsDynamic" name="bool" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}" value="true" />
<Class field="MetadataEntity" name="AZ::Entity" type="{75651658-8663-478D-9090-2432DFCAFA44}" version="2">
<Class field="Id" name="EntityId" type="{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}" version="1">
<Class field="id" name="AZ::u64" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}" value="273889795654" />
</Class>
<Class name="AZStd::string" field="Name" value="No Asset Association" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
<Class name="AZStd::vector" field="Components" type="{13D58FF9-1088-5C69-9A1F-C2A144B57B78}">
<Class name="SliceMetadataInfoComponent" field="element" version="2" type="{25EE4D75-8A17-4449-81F4-E561005BAABD}">
<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
<Class name="AZ::u64" field="Id" value="1605466577178627956" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
<Class field="Name" name="AZStd::string" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}" value="No Asset Association" />
<Class field="Components" name="AZStd::vector" type="{13D58FF9-1088-5C69-9A1F-C2A144B57B78}">
<Class field="element" name="SliceMetadataInfoComponent" type="{25EE4D75-8A17-4449-81F4-E561005BAABD}" version="2">
<Class field="BaseClass1" name="AZ::Component" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
<Class field="Id" name="AZ::u64" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}" value="1605466577178627956" />
</Class>
<Class name="AZStd::set" field="AssociatedIds" type="{78E024C3-0143-53FC-B393-0675227839AF}">
<Class name="EntityId" field="element" version="1" type="{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}">
<Class name="AZ::u64" field="id" value="278184762950" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
<Class field="AssociatedIds" name="AZStd::set" type="{78E024C3-0143-53FC-B393-0675227839AF}">
<Class field="element" name="EntityId" type="{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}" version="1">
<Class field="id" name="AZ::u64" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}" value="278184762950" />
</Class>
</Class>
<Class name="EntityId" field="ParentId" version="1" type="{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}">
<Class name="AZ::u64" field="id" value="4294967295" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
<Class field="ParentId" name="EntityId" type="{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}" version="1">
<Class field="id" name="AZ::u64" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}" value="4294967295" />
</Class>
<Class name="AZStd::unordered_set" field="ChildrenIds" type="{6C8F8E52-AB4A-5C1F-8E56-9AC390290B94}"/>
<Class name="bool" field="PersistenceFlag" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
<Class field="ChildrenIds" name="AZStd::unordered_set" type="{6C8F8E52-AB4A-5C1F-8E56-9AC390290B94}" />
<Class field="PersistenceFlag" name="bool" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}" value="false" />
</Class>
</Class>
<Class name="bool" field="IsDependencyReady" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
<Class name="bool" field="IsRuntimeActive" value="true" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
<Class field="IsDependencyReady" name="bool" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}" value="false" />
<Class field="IsRuntimeActive" name="bool" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}" value="true" />
</Class>
<Class name="DataFlagsPerEntity" field="DataFlagsForNewEntities" version="1" type="{57FE7B9E-B2AF-4F6F-9F8D-87F671E91C99}">
<Class name="AZStd::unordered_map" field="EntityToDataFlags" type="{CAB9E1F5-761E-54B8-916E-E7FB597E5EDE}"/>
<Class field="DataFlagsForNewEntities" name="DataFlagsPerEntity" type="{57FE7B9E-B2AF-4F6F-9F8D-87F671E91C99}" version="1">
<Class field="EntityToDataFlags" name="AZStd::unordered_map" type="{CAB9E1F5-761E-54B8-916E-E7FB597E5EDE}" />
</Class>
</Class>
</Class>
<Class name="bool" field="IsDependencyReady" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
<Class name="bool" field="IsRuntimeActive" value="true" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
<Class field="IsDependencyReady" name="bool" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}" value="false" />
<Class field="IsRuntimeActive" name="bool" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}" value="true" />
</Class>
</ObjectStream>
</ObjectStream>

@ -20,8 +20,8 @@ from typing import List, Tuple
from ..ap_fixtures.asset_processor_fixture import asset_processor
from ..ap_fixtures.ap_setup_fixture import ap_setup_fixture
from ly_test_tools.lumberyard.asset_processor import ASSET_PROCESSOR_PLATFORM_MAP
from ly_test_tools.lumberyard import asset_processor as asset_processor_utils
from ly_test_tools.o3de.asset_processor import ASSET_PROCESSOR_PLATFORM_MAP
from ly_test_tools.o3de import asset_processor as asset_processor_utils
# fmt:off
from ..ap_fixtures.ap_missing_dependency_fixture \
@ -32,7 +32,7 @@ from ..ap_fixtures.ap_missing_dependency_fixture \
import ly_test_tools.builtin.helpers as helpers
# Import LyShared
import ly_test_tools.lumberyard.pipeline_utils as utils
import ly_test_tools.o3de.pipeline_utils as utils
from automatedtesting_shared import asset_database_utils as db_utils
# Use the following logging pattern to hook all test logging together:
@ -71,8 +71,6 @@ class TestsMissingDependencies_WindowsAndMac(object):
self._asset_processor.add_source_folder_assets(f"{self._workspace.project}\\textures")
self._asset_processor.add_source_folder_assets(f"{self._workspace.project}\\UI")
self._asset_processor.add_source_folder_assets(f"{self._workspace.project}\\libs\\particles")
asset_processor.copy_assets_to_project(['Game.xml'], os.path.join(self._workspace.paths.dev(), self._workspace.project, 'Config'),
os.path.join(self._asset_processor.temp_asset_root(), self._workspace.project, 'Config'))
def do_missing_dependency_test(self, source_product, expected_dependencies,
dsp_param,

@ -19,7 +19,7 @@ import subprocess
import glob
from ly_test_tools.builtin.helpers import *
from ly_test_tools.environment.process_utils import *
from ly_test_tools.lumberyard.asset_processor import ASSET_PROCESSOR_PLATFORM_MAP
from ly_test_tools.o3de.asset_processor import ASSET_PROCESSOR_PLATFORM_MAP
logger = logging.getLogger(__name__)
@ -30,7 +30,7 @@ project_list = ['AutomatedTesting']
class TestAuxiliaryContent:
@pytest.fixture(autouse=True)
def setup_teardown(self, request, workspace, project):
path_to_dev = workspace.paths.dev()
path_to_dev = workspace.paths.engine_root()
os.chdir(path_to_dev)
auxiliaryContentDirName = str.lower(project) + f"_{ASSET_PROCESSOR_PLATFORM_MAP[workspace.asset_processor_platform]}_paks"
self.auxiliaryContentPath = os.path.join(path_to_dev, auxiliaryContentDirName)
@ -53,14 +53,14 @@ class TestAuxiliaryContent:
This test ensure that Auxiliary Content contain level.pak files
"""
path_to_dev = workspace.paths.dev()
path_to_dev = workspace.paths.engine_root()
bin_path = workspace.paths.build_directory()
auxiliaryContentScriptPath = os.path.join(path_to_dev, 'BuildReleaseAuxiliaryContent.py')
subprocess.check_call(['python', auxiliaryContentScriptPath,
"--buildFolder={0}".format(bin_path),
"--platforms=pc",
f"--project={workspace.project}"])
f"--project-path={workspace.project}"])
assert os.path.exists(self.auxiliaryContentPath)
assert not self.scanForLevelPak(self.auxiliaryContentPath) == 0
@ -72,7 +72,7 @@ class TestAuxiliaryContent:
This test ensure that Auxiliary Content contain no level.pak file
"""
path_to_dev = workspace.paths.dev()
path_to_dev = workspace.paths.engine_root()
bin_path = workspace.paths.build_directory()
auxiliaryContentScriptPath = os.path.join(path_to_dev, 'BuildReleaseAuxiliaryContent.py')
@ -80,7 +80,7 @@ class TestAuxiliaryContent:
"--buildFolder={0}".format(bin_path),
"--platforms=pc",
"--skiplevelPaks",
f"--project={workspace.project}"])
f"--project-path={workspace.project}"])
assert os.path.exists(self.auxiliaryContentPath)
assert self.scanForLevelPak(self.auxiliaryContentPath) == 0

@ -18,8 +18,8 @@ from typing import List
# Import LyTestTools
import ly_test_tools.builtin.helpers as helpers
from ly_test_tools.lumberyard import asset_processor as asset_processor_utils
from ly_test_tools.lumberyard.asset_processor import ASSET_PROCESSOR_PLATFORM_MAP
from ly_test_tools.o3de import asset_processor as asset_processor_utils
from ly_test_tools.o3de.asset_processor import ASSET_PROCESSOR_PLATFORM_MAP
# Import fixtures
from ..ap_fixtures.asset_processor_fixture import asset_processor as asset_processor
@ -29,7 +29,7 @@ from ..ap_fixtures.ap_config_default_platform_fixture import ap_config_default_p
# Import LyShared
import ly_test_tools.lumberyard.pipeline_utils as utils
import ly_test_tools.o3de.pipeline_utils as utils
from automatedtesting_shared import asset_database_utils as asset_db_utils
logger = logging.getLogger(__name__)

@ -67,7 +67,7 @@ def success_case_test(test_folder, expected_dependencies_dict, bank_info, expect
def get_bank_info(workspace):
sys.path.append(
os.path.join(workspace.paths.dev(), 'Gems', 'AudioEngineWwise', 'Tools'))
os.path.join(workspace.paths.engine_root(), 'Gems', 'AudioEngineWwise', 'Tools'))
from WwiseAuthoringScripts import bank_info_parser as bank_info_module
return bank_info_module

@ -16,7 +16,7 @@ import sqlite3
import os
from typing import List
import ly_test_tools.lumberyard.pipeline_utils as pipeline_utils
import ly_test_tools.o3de.pipeline_utils as pipeline_utils
# Index for ProductID in Products table in DB
PRODUCT_ID_INDEX = 0

@ -12,7 +12,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# Built-in Imports
from __future__ import annotations
# Lumberyard Imports
# Open 3D Engine Imports
import azlmbr.bus as bus
import azlmbr.asset as azasset
import azlmbr.math as math

@ -20,7 +20,7 @@ import ly_test_tools.environment.file_system as file_system
import ly_test_tools.environment.process_utils as process_utils
import ly_test_tools.environment.waiter as waiter
from ly_test_tools.lumberyard.asset_processor import AssetProcessor
from ly_test_tools.o3de.asset_processor import AssetProcessor
from ly_test_tools.launchers.exceptions import WaitTimeoutError
from ly_test_tools.log.log_monitor import LogMonitor, LogMonitorException

@ -16,7 +16,7 @@ from typing import List, Tuple, Union
# Helper file Imports
import utils
# Lumberyard Imports
# Open 3D Engine Imports
import azlmbr
import azlmbr.bus as bus
import azlmbr.editor as editor

@ -17,7 +17,7 @@ import time
from typing import Sequence
from .report import Report
# Lumberyard specific imports
# Open 3D Engine specific imports
import azlmbr.legacy.general as general
import azlmbr.legacy.settings as settings
@ -119,7 +119,6 @@ class EditorTestHelper:
general.set_viewport_expansion_policy("AutoExpand")
general.set_view_pane_layout(self.viewport_layout)
general.update_viewport()
general.idle_wait(1.0)
self.log("test finished")
@ -162,10 +161,10 @@ class EditorTestHelper:
def create_level(
self,
level_name: str,
heightmap_resolution: int,
heightmap_meters_per_pixel: int,
terrain_texture_resolution: int,
use_terrain: bool,
heightmap_resolution: int = 1024,
heightmap_meters_per_pixel: int = 1,
terrain_texture_resolution: int = 4096,
use_terrain: bool = False,
bypass_viewport_resize: bool = False,
) -> bool:
self.log(f"Creating level {level_name}")

@ -88,6 +88,13 @@ def add_component(componentName, entityId):
return componentOutcome.GetValue()[0]
def add_component_of_type(componentTypeId, entityId):
typeIdsList = [componentTypeId]
componentOutcome = editor.EditorComponentAPIBus(
azlmbr.bus.Broadcast, 'AddComponentsOfType', entityId, typeIdsList)
return componentOutcome.GetValue()[0]
def remove_component(component_name, entity_id):
"""
Removes the specified component from the specified entity.
@ -213,6 +220,10 @@ class Entity:
new_component = add_component(component, self.id)
self.components.append(new_component)
def add_component_of_type(self, componentTypeId):
new_component = add_component_of_type(componentTypeId, self.id)
self.components.append(new_component)
def remove_component(self, component):
removed_component = remove_component(component, self.id)
if removed_component is not None:
@ -285,8 +296,8 @@ def get_set_test(entity: object, component_index: int, path: str, value: object)
def get_set_property_test(ly_object: object, attribute_name: str, value: object, expected_result: object = None) -> bool:
"""
Used to set and validate BehaviorContext property changes in Lumberyard objects
:param ly_object: The lumberyard object to test
Used to set and validate BehaviorContext property changes in Open 3D Engine objects
:param ly_object: The Open 3D Engine object to test
:param attribute_name: property (attribute) name in the BehaviorContext
:param value: new value for the variable being changed in the component
:param expected_result: (optional) check the result against a specific expected value other than the one set
@ -399,7 +410,7 @@ def set_editor_settings_by_path(path, value, is_bool = False):
def get_component_type_id_map(component_name_list):
"""
Given a list of component names, returns a map of component name -> component type id
:param component_name_list: The lumberyard object to test
:param component_name_list: The Open 3D Engine object to test
:return: Dictionary of component name -> component type id pairs
"""
# Remove any duplicates so we don't have to query for the same TypeId

@ -32,7 +32,7 @@ def teardown_editor(editor):
def launch_and_validate_results(request, test_directory, editor, editor_script, expected_lines, unexpected_lines=[],
halt_on_unexpected=False, run_python="--runpythontest", auto_test_mode=True, null_renderer=True, cfg_args=[],
halt_on_unexpected=False, run_python="--runpythontest", auto_test_mode=True, null_renderer=False, cfg_args=[],
timeout=300):
"""
Runs the Editor with the specified script, and monitors for expected log lines.

@ -16,7 +16,7 @@ import pytest
import logging
from typing import Optional, Any
import ly_test_tools.lumberyard.pipeline_utils as utils
import ly_test_tools.o3de.pipeline_utils as utils
logger = logging.getLogger(__name__)

@ -27,9 +27,9 @@ from automatedtesting_shared.editor_test_helper import EditorTestHelper
import automatedtesting_shared.pyside_utils as pyside_utils
class TestAssetBrowserSearchFiltering(EditorTestHelper):
class AssetBrowserSearchFilteringTest(EditorTestHelper):
def __init__(self):
EditorTestHelper.__init__(self, log_prefix="SearchFiltering_Asset_Browser_Filtering", args=["level"])
EditorTestHelper.__init__(self, log_prefix="AssetBrowser_SearchFiltering", args=["level"])
@pyside_utils.wrap_async
async def run_test(self):
@ -57,7 +57,7 @@ class TestAssetBrowserSearchFiltering(EditorTestHelper):
Note:
- This test file must be called from the Lumberyard Editor command terminal
- This test file must be called from the Open 3D Engine Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.
@ -161,5 +161,5 @@ class TestAssetBrowserSearchFiltering(EditorTestHelper):
asset_browser.close()
test = TestAssetBrowserSearchFiltering()
test = AssetBrowserSearchFilteringTest()
test.run()

@ -27,7 +27,7 @@ import automatedtesting_shared.pyside_utils as pyside_utils
class AssetBrowserTreeNavigationTest(EditorTestHelper):
def __init__(self):
EditorTestHelper.__init__(self, log_prefix="TreeNavigation_Asset_Browser", args=["level"])
EditorTestHelper.__init__(self, log_prefix="AssetBrowser_TreeNavigation", args=["level"])
def run_test(self):
"""
@ -49,7 +49,7 @@ class AssetBrowserTreeNavigationTest(EditorTestHelper):
6) Verify if the ScrollBar appears after expanding the tree
Note:
- This test file must be called from the Lumberyard Editor command terminal
- This test file must be called from the Open 3D Engine Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.

@ -0,0 +1,262 @@
"""
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.
"""
"""
C13751579: Asset Picker UI/UX
"""
import os
import sys
from PySide2 import QtWidgets, QtTest, QtCore
from PySide2.QtCore import Qt
import azlmbr.asset as asset
import azlmbr.bus as bus
import azlmbr.legacy.general as general
import azlmbr.paths
import azlmbr.math as math
sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests'))
import automatedtesting_shared.hydra_editor_utils as hydra
from automatedtesting_shared.editor_test_helper import EditorTestHelper
import automatedtesting_shared.pyside_utils as pyside_utils
class AssetPickerUIUXTest(EditorTestHelper):
def __init__(self):
EditorTestHelper.__init__(self, log_prefix="AssetPicker_UI_UX", args=["level"])
@pyside_utils.wrap_async
async def run_test(self):
"""
Summary:
Verify the functionality of Asset Picker and UI/UX properties
Expected Behavior:
The asset picker opens and is labeled appropriately ("Pick Model Asset" in this instance).
The Asset Picker window can be resized and moved around the screen.
The file tree expands/retracts appropriately and a scroll bar is present when the menus extend
beyond the length of the window.
The assets are limited to a valid type for the field selected (mesh assets in this instance)
The asset picker is closed and the selected asset is assigned to the mesh component.
Test Steps:
1) Open a new level
2) Create entity and add Mesh component
3) Access Entity Inspector
4) Click Asset Picker (Mesh Asset)
a) Collapse all the files initially and verify if scroll bar is not visible
b) Expand/Verify Top folder of file path
c) Expand/Verify Nested folder of file path
d) Verify if the ScrollBar appears after expanding folders
e) Collapse Nested and Top Level folders and verify if collapsed
f) Verify if the correct files are appearing in the Asset Picker
g) Move the widget and verify position
h) Resize the widget
g) Assign Mesh asset
5) Verify if Mesh Asset is assigned via both OK/Enter options
Note:
- This test file must be called from the Lumberyard Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.
:return: None
"""
self.file_path = ["AutomatedTesting", "Assets", "Objects", "Foliage"]
self.incorrect_file_found = False
self.mesh_asset = "cedar.azmodel"
self.prefix = ""
def is_asset_assigned(component, interaction_option):
path = os.path.join("assets", "objects", "foliage", "cedar.azmodel")
expected_asset_id = asset.AssetCatalogRequestBus(bus.Broadcast, 'GetAssetIdByPath', path, math.Uuid(),
False)
result = hydra.get_component_property_value(component, "Controller|Configuration|Mesh Asset")
expected_asset_str = expected_asset_id.invoke("ToString")
result_str = result.invoke("ToString")
print(f"Asset assigned for {interaction_option} option: {expected_asset_str == result_str}")
return expected_asset_str == result_str
def move_and_resize_widget(widget):
# Move the widget and verify position
initial_position = widget.pos()
x, y = initial_position.x() + 5, initial_position.y() + 5
widget.move(x, y)
curr_position = widget.pos()
move_success = curr_position.x() == x and curr_position.y() == y
self.test_success = move_success and self.test_success
self.log(f"Widget Move Test: {move_success}")
# Resize the widget and verify size
width, height = (
widget.geometry().width() + 10,
widget.geometry().height() + 10,
)
widget.resize(width, height)
resize_success = widget.geometry().width() == width and widget.geometry().height() == height
self.test_success = resize_success and self.test_success
self.log(f"Widget Resize Test: {resize_success}")
def verify_files_appeared(model, allowed_asset_extensions, parent_index=QtCore.QModelIndex()):
indices = [parent_index]
while len(indices) > 0:
parent_index = indices.pop(0)
for row in range(model.rowCount(parent_index)):
cur_index = model.index(row, 0, parent_index)
cur_data = cur_index.data(Qt.DisplayRole)
if (
"." in cur_data
and (cur_data.lower().split(".")[-1] not in allowed_asset_extensions)
and not cur_data[-1] == ")"
):
print(f"Incorrect file found: {cur_data}")
self.incorrect_file_found = True
indices = list()
break
indices.append(cur_index)
self.test_success = not self.incorrect_file_found and self.test_success
def print_message_prefix(message):
print(f"{self.prefix}: {message}")
async def asset_picker(prefix, allowed_asset_extensions, asset, interaction_option):
active_modal_widget = await pyside_utils.wait_for_modal_widget()
if active_modal_widget and self.prefix == "":
self.prefix = prefix
dialog = active_modal_widget.findChildren(QtWidgets.QDialog, "AssetPickerDialogClass")[0]
print_message_prefix(f"Asset Picker title for Mesh: {dialog.windowTitle()}")
tree = dialog.findChildren(QtWidgets.QTreeView, "m_assetBrowserTreeViewWidget")[0]
scroll_area = tree.findChild(QtWidgets.QWidget, "qt_scrollarea_vcontainer")
scroll_bar = scroll_area.findChild(QtWidgets.QScrollBar)
# a) Collapse all the files initially and verify if scroll bar is not visible
tree.collapseAll()
await pyside_utils.wait_for_condition(lambda: not scroll_bar.isVisible(), 0.5)
print_message_prefix(
f"Scroll Bar is not visible before expanding the tree: {not scroll_bar.isVisible()}"
)
# Get Model Index of the file paths
model_index_1 = pyside_utils.find_child_by_pattern(tree, self.file_path[0])
print(model_index_1.model())
model_index_2 = pyside_utils.find_child_by_pattern(model_index_1, self.file_path[1])
# b) Expand/Verify Top folder of file path
print_message_prefix(f"Top level folder initially collapsed: {not tree.isExpanded(model_index_1)}")
tree.expand(model_index_1)
print_message_prefix(f"Top level folder expanded: {tree.isExpanded(model_index_1)}")
# c) Expand/Verify Nested folder of file path
print_message_prefix(f"Nested folder initially collapsed: {not tree.isExpanded(model_index_2)}")
tree.expand(model_index_2)
print_message_prefix(f"Nested folder expanded: {tree.isExpanded(model_index_2)}")
# d) Verify if the ScrollBar appears after expanding folders
tree.expandAll()
await pyside_utils.wait_for_condition(lambda: scroll_bar.isVisible(), 0.5)
print_message_prefix(f"Scroll Bar appeared after expanding tree: {scroll_bar.isVisible()}")
# e) Collapse Nested and Top Level folders and verify if collapsed
tree.collapse(model_index_2)
print_message_prefix(f"Nested folder collapsed: {not tree.isExpanded(model_index_2)}")
tree.collapse(model_index_1)
print_message_prefix(f"Top level folder collapsed: {not tree.isExpanded(model_index_1)}")
# f) Verify if the correct files are appearing in the Asset Picker
verify_files_appeared(tree.model(), allowed_asset_extensions)
print_message_prefix(f"Expected Assets populated in the file picker: {not self.incorrect_file_found}")
# While we are here we can also check if we can resize and move the widget
move_and_resize_widget(active_modal_widget)
# g) Assign asset
tree.collapseAll()
await pyside_utils.wait_for_condition(
lambda: len(dialog.findChildren(QtWidgets.QFrame, "m_searchWidget")) > 0, 0.5)
search_widget = dialog.findChildren(QtWidgets.QFrame, "m_searchWidget")[0]
search_line_edit = search_widget.findChildren(QtWidgets.QLineEdit, "textSearch")[0]
search_line_edit.setText(asset)
tree.expandAll()
asset_model_index = pyside_utils.find_child_by_pattern(tree, asset)
await pyside_utils.wait_for_condition(lambda: asset_model_index.isValid(), 2.0)
tree.expand(asset_model_index)
tree.setCurrentIndex(asset_model_index)
if interaction_option == "ok":
button_box = dialog.findChild(QtWidgets.QDialogButtonBox, "m_buttonBox")
ok_button = button_box.button(QtWidgets.QDialogButtonBox.Ok)
await pyside_utils.click_button_async(ok_button)
elif interaction_option == "enter":
QtTest.QTest.keyClick(tree, Qt.Key_Enter, Qt.NoModifier)
self.prefix = ""
# 1) Open a new level
self.test_success = self.create_level(
self.args["level"],
heightmap_resolution=1024,
heightmap_meters_per_pixel=1,
terrain_texture_resolution=4096,
use_terrain=False,
)
# 2) Create entity and add Mesh component
entity_position = math.Vector3(125.0, 136.0, 32.0)
entity = hydra.Entity("TestEntity")
entity.create_entity(entity_position, ["Mesh"])
# 3) Access Entity Inspector
editor_window = pyside_utils.get_editor_main_window()
entity_inspector = editor_window.findChild(QtWidgets.QDockWidget, "Entity Inspector")
component_list_widget = entity_inspector.findChild(QtWidgets.QWidget, "m_componentListContents")
# 4) Click on Asset Picker (Mesh Asset)
general.select_object("TestEntity")
general.idle_wait(0.5)
mesh_asset = component_list_widget.findChildren(QtWidgets.QFrame, "Mesh Asset")[0]
attached_button = mesh_asset.findChildren(QtWidgets.QPushButton, "attached-button")[0]
# Assign Mesh Asset via OK button
pyside_utils.click_button_async(attached_button)
await asset_picker("Mesh Asset", ["azmodel", "fbx"], "cedar (ModelAsset)", "ok")
# 5) Verify if Mesh Asset is assigned
try:
mesh_success = await pyside_utils.wait_for_condition(lambda: is_asset_assigned(entity.components[0],
"ok"))
except pyside_utils.EventLoopTimeoutException as err:
print(err)
mesh_success = False
self.test_success = mesh_success and self.test_success
# Clear Mesh Asset
hydra.get_set_test(entity, 0, "Controller|Configuration|Mesh Asset", None)
general.select_object("TestEntity")
general.idle_wait(0.5)
mesh_asset = component_list_widget.findChildren(QtWidgets.QFrame, "Mesh Asset")[0]
attached_button = mesh_asset.findChildren(QtWidgets.QPushButton, "attached-button")[0]
# Assign Mesh Asset via Enter
pyside_utils.click_button_async(attached_button)
await asset_picker("Mesh Asset", ["azmodel", "fbx"], "cedar (ModelAsset)", "enter")
# 5) Verify if Mesh Asset is assigned
try:
mesh_success = await pyside_utils.wait_for_condition(lambda: is_asset_assigned(entity.components[0],
"enter"))
except pyside_utils.EventLoopTimeoutException as err:
print(err)
mesh_success = False
self.test_success = mesh_success and self.test_success
test = AssetPickerUIUXTest()
test.run()

@ -58,7 +58,7 @@ class AddDeleteComponentsTest(EditorTestHelper):
7) Undo deletion of component
Note:
- This test file must be called from the Lumberyard Editor command terminal
- This test file must be called from the Open 3D Engine Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.
@ -72,6 +72,7 @@ class AddDeleteComponentsTest(EditorTestHelper):
component_index = pyside_utils.find_child_by_pattern(tree, component_name)
if component_index.isValid():
print(f"{component_name} found")
tree.expand(component_index)
tree.setCurrentIndex(component_index)
QtTest.QTest.keyClick(tree, Qt.Key_Enter, Qt.NoModifier)
@ -93,8 +94,8 @@ class AddDeleteComponentsTest(EditorTestHelper):
print("Entity Created")
# 3) Select the newly created entity
general.clear_selection()
general.select_object("Entity2")
# Give the Entity Inspector time to fully create its contents
general.idle_wait(0.5)
@ -103,14 +104,11 @@ class AddDeleteComponentsTest(EditorTestHelper):
entity_inspector = editor_window.findChild(QtWidgets.QDockWidget, "Entity Inspector")
add_comp_btn = entity_inspector.findChild(QtWidgets.QPushButton, "m_addComponentButton")
await add_component("Box Shape")
print(f"Box Shape Component added: {hydra.has_components(entity_id, ['Box Shape'])}")
# 5) Add/verify Mesh component
await add_component("Mesh")
print(
f"Box Shape and Mesh Components present in the entity: {hydra.has_components(entity_id, ['Box Shape', 'Mesh'])}"
)
print(f"Mesh Component added: {hydra.has_components(entity_id, ['Mesh'])}")
# 6) Delete Mesh Component
general.idle_wait(0.5)

@ -0,0 +1,142 @@
"""
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.
C6376081: Basic Function: Docked/Undocked Tools
"""
import os
import sys
from PySide2 import QtWidgets, QtTest, QtCore
import azlmbr.legacy.general as general
import azlmbr.bus as bus
import azlmbr.editor as editor
import azlmbr.entity as entity
import azlmbr.paths
sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests'))
from automatedtesting_shared.editor_test_helper import EditorTestHelper
import automatedtesting_shared.pyside_utils as pyside_utils
class TestDockingBasicDockedTools(EditorTestHelper):
def __init__(self):
EditorTestHelper.__init__(self, log_prefix="Docking_BasicDockedTools", args=["level"])
@pyside_utils.wrap_async
async def run_test(self):
"""
Summary:
Test that tools still work as expected when docked together.
Expected Behavior:
Multiple tools can be docked together.
Tools function while docked together and the main editor responds appropriately.
Test Steps:
1) Open the tools and dock them together in a floating tabbed widget.
2) Perform actions in the docked tools to verify they still work as expected.
2.1) Select the Entity Outliner in the floating window.
2.2) Select an Entity in the Entity Outliner.
2.3) Select the Entity Inspector in the floating window.
2.4) Change the name of the selected Entity via the Entity Inspector.
2.5) Select the Console inside the floating window.
2.6) Send a console command.
2.7) Check the Editor to verify all changes were made.
:return: None
"""
# Create a level since we are going to be dealing with an Entity.
self.create_level(
self.args["level"],
heightmap_resolution=1024,
heightmap_meters_per_pixel=1,
terrain_texture_resolution=4096,
use_terrain=False,
)
# Make sure the Entity Outliner, Entity Inspector and Console tools are open
general.open_pane("Entity Outliner (PREVIEW)")
general.open_pane("Entity Inspector")
general.open_pane("Console")
# Create an Entity to test with
entity_original_name = 'MyTestEntity'
entity_id = editor.ToolsApplicationRequestBus(bus.Broadcast, 'CreateNewEntity', entity.EntityId())
editor.EditorEntityAPIBus(bus.Event, 'SetName', entity_id, entity_original_name)
editor_window = pyside_utils.get_editor_main_window()
entity_outliner = editor_window.findChild(QtWidgets.QDockWidget, "Entity Outliner (PREVIEW)")
# 1) Open the tools and dock them together in a floating tabbed widget.
# We drag/drop it over the viewport since it doesn't allow docking, so this will undock it
render_overlay = editor_window.findChild(QtWidgets.QWidget, "renderOverlay")
pyside_utils.drag_and_drop(entity_outliner, render_overlay)
# We need to grab a new reference to the Entity Outliner QDockWidget because when it gets moved
# to the floating window, its parent changes so the wrapped intance we had becomes invalid
entity_outliner = editor_window.findChild(QtWidgets.QDockWidget, "Entity Outliner (PREVIEW)")
# Dock the Entity Inspector tabbed with the floating Entity Outliner
entity_inspector = editor_window.findChild(QtWidgets.QDockWidget, "Entity Inspector")
pyside_utils.drag_and_drop(entity_inspector, entity_outliner)
# We need to grab a new reference to the Entity Inspector QDockWidget because when it gets moved
# to the floating window, its parent changes so the wrapped intance we had becomes invalid
entity_inspector = editor_window.findChild(QtWidgets.QDockWidget, "Entity Inspector")
# Dock the Console tabbed with the floating Entity Inspector
console = editor_window.findChild(QtWidgets.QDockWidget, "Console")
pyside_utils.drag_and_drop(console, entity_inspector)
# Check to ensure all the tools are parented to the same QStackedWidget
def check_all_panes_tabbed():
entity_inspector = editor_window.findChild(QtWidgets.QDockWidget, "Entity Inspector")
entity_outliner = editor_window.findChild(QtWidgets.QDockWidget, "Entity Outliner (PREVIEW)")
console = editor_window.findChild(QtWidgets.QDockWidget, "Console")
entity_inspector_parent = entity_inspector.parentWidget()
entity_outliner_parent = entity_outliner.parentWidget()
console_parent = console.parentWidget()
print(f"Entity Inspector parent = {entity_inspector_parent}, Entity Outliner parent = {entity_outliner_parent}, Console parent = {console_parent}")
return isinstance(entity_inspector_parent, QtWidgets.QStackedWidget) and (entity_inspector_parent == entity_outliner_parent) and (entity_outliner_parent == console_parent)
success = await pyside_utils.wait_for(check_all_panes_tabbed, timeout=3.0)
if success:
print("The tools are all docked together in a tabbed widget")
# 2.1,2) Select an Entity in the Entity Outliner.
entity_inspector = editor_window.findChild(QtWidgets.QDockWidget, "Entity Inspector")
entity_outliner = editor_window.findChild(QtWidgets.QDockWidget, "Entity Outliner (PREVIEW)")
console = editor_window.findChild(QtWidgets.QDockWidget, "Console")
object_tree = entity_outliner.findChild(QtWidgets.QTreeView, "m_objectTree")
test_entity_index = pyside_utils.find_child_by_pattern(object_tree, entity_original_name)
object_tree.clearSelection()
object_tree.setCurrentIndex(test_entity_index)
if object_tree.currentIndex():
print("Entity Outliner works when docked, can select an Entity")
# 2.3,4) Change the name of the selected Entity via the Entity Inspector.
entity_inspector_name_field = entity_inspector.findChild(QtWidgets.QLineEdit, "m_entityNameEditor")
expected_new_name = "DifferentName"
entity_inspector_name_field.setText(expected_new_name)
QtTest.QTest.keyClick(entity_inspector_name_field, QtCore.Qt.Key_Enter)
entity_new_name = editor.EditorEntityInfoRequestBus(bus.Event, "GetName", entity_id)
if entity_new_name == expected_new_name:
print(f"Entity Inspector works when docked, Entity name changed to {entity_new_name}")
# 2.5,6) Send a console command.
console_line_edit = console.findChild(QtWidgets.QLineEdit, "lineEdit")
console_line_edit.setText("Hello, world!")
QtTest.QTest.keyClick(console_line_edit, QtCore.Qt.Key_Enter)
test = TestDockingBasicDockedTools()
test.run()

@ -58,7 +58,7 @@ class AddRemoveInputEventsTest(EditorTestHelper):
10) Close Asset Editor
Note:
- This test file must be called from the Lumberyard Editor command terminal
- This test file must be called from the Open 3D Engine Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.

@ -0,0 +1,120 @@
"""
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.
"""
"""
C24064529: Base Edit Menu Options
"""
import os
import sys
import azlmbr.paths
sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests'))
from automatedtesting_shared.editor_test_helper import EditorTestHelper
import automatedtesting_shared.pyside_utils as pyside_utils
class TestEditMenuOptions(EditorTestHelper):
def __init__(self):
EditorTestHelper.__init__(self, log_prefix="Menus_EditMenuOptions", args=["level"])
def run_test(self):
"""
Summary:
Interact with Edit Menu options and verify if all the options are working.
Expected Behavior:
The Edit menu functions normally.
Test Steps:
1) Create a temp level
2) Interact with Edit Menu options
Note:
- This test file must be called from the Lumberyard Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.
:return: None
"""
edit_menu_options = [
("Undo",),
("Redo",),
("Duplicate",),
("Delete",),
("Select All",),
("Invert Selection",),
("Toggle Pivot Location",),
("Reset Entity Transform",),
("Reset Manipulator",),
("Reset Transform (Local)",),
("Reset Transform (World)",),
("Hide Selection",),
("Show All",),
("Modify", "Snap", "Snap angle"),
("Modify", "Transform Mode", "Move"),
("Modify", "Transform Mode", "Rotate"),
("Modify", "Transform Mode", "Scale"),
("Lock Selection",),
("Unlock All Entities",),
("Editor Settings", "Global Preferences"),
("Editor Settings", "Graphics Settings"),
("Editor Settings", "Editor Settings Manager"),
("Editor Settings", "Graphics Performance", "PC", "Very High"),
("Editor Settings", "Graphics Performance", "PC", "High"),
("Editor Settings", "Graphics Performance", "PC", "Medium"),
("Editor Settings", "Graphics Performance", "PC", "Low"),
("Editor Settings", "Graphics Performance", "OSX Metal", "Very High"),
("Editor Settings", "Graphics Performance", "OSX Metal", "High"),
("Editor Settings", "Graphics Performance", "OSX Metal", "Medium"),
("Editor Settings", "Graphics Performance", "OSX Metal", "Low"),
("Editor Settings", "Graphics Performance", "Android", "Very High"),
("Editor Settings", "Graphics Performance", "Android", "High"),
("Editor Settings", "Graphics Performance", "Android", "Medium"),
("Editor Settings", "Graphics Performance", "Android", "Low"),
("Editor Settings", "Graphics Performance", "iOS", "Very High"),
("Editor Settings", "Graphics Performance", "iOS", "High"),
("Editor Settings", "Graphics Performance", "iOS", "Medium"),
("Editor Settings", "Graphics Performance", "iOS", "Low"),
("Editor Settings", "Keyboard Customization", "Customize Keyboard"),
("Editor Settings", "Keyboard Customization", "Export Keyboard Settings"),
("Editor Settings", "Keyboard Customization", "Import Keyboard Settings"),
]
# 1) Create and open the temp level
self.test_success = self.create_level(
self.args["level"],
heightmap_resolution=1024,
heightmap_meters_per_pixel=1,
terrain_texture_resolution=4096,
use_terrain=False,
)
def on_action_triggered(action_name):
print(f"{action_name} Action triggered")
# 2) Interact with Edit Menu options
try:
editor_window = pyside_utils.get_editor_main_window()
for option in edit_menu_options:
action = pyside_utils.get_action_for_menu_path(editor_window, "Edit", *option)
trig_func = lambda: on_action_triggered(action.iconText())
action.triggered.connect(trig_func)
action.trigger()
action.triggered.disconnect(trig_func)
except Exception as e:
self.test_success = False
print(e)
test = TestEditMenuOptions()
test.run()

@ -0,0 +1,90 @@
"""
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.
"""
"""
C24064528: The File menu options function normally
C16780778: The File menu options function normally-New view interaction Model enabled
"""
import os
import sys
import azlmbr.paths
sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests'))
from automatedtesting_shared.editor_test_helper import EditorTestHelper
import automatedtesting_shared.pyside_utils as pyside_utils
class TestFileMenuOptions(EditorTestHelper):
def __init__(self):
EditorTestHelper.__init__(self, log_prefix="file_menu_options: ", args=["level"])
def run_test(self):
"""
Summary:
Interact with File Menu options and verify if all the options are working.
Expected Behavior:
The File menu functions normally.
Test Steps:
1) Open level
2) Interact with File Menu options
Note:
- This test file must be called from the Lumberyard Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.
:return: None
"""
file_menu_options = [
("New Level",),
("Open Level",),
("Import",),
("Save",),
("Save As",),
("Save Level Statistics",),
("Project Settings", "Project Settings Tool"),
("Show Log File",),
("Resave All Slices",),
("Exit",),
]
# 1) Open level
self.test_success = self.create_level(
self.args["level"],
heightmap_resolution=1024,
heightmap_meters_per_pixel=1,
terrain_texture_resolution=4096,
use_terrain=False,
)
def on_action_triggered(action_name):
print(f"{action_name} Action triggered")
# 2) Interact with File Menu options
try:
editor_window = pyside_utils.get_editor_main_window()
for option in file_menu_options:
action = pyside_utils.get_action_for_menu_path(editor_window, "File", *option)
trig_func = lambda: on_action_triggered(action.iconText())
action.triggered.connect(trig_func)
action.trigger()
action.triggered.disconnect(trig_func)
except Exception as e:
self.test_success = False
print(e)
test = TestFileMenuOptions()
test.run()

@ -0,0 +1,91 @@
"""
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.
"""
"""
C24064534: The View menu options function normally
"""
import os
import sys
import azlmbr.paths
sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests'))
from automatedtesting_shared.editor_test_helper import EditorTestHelper
import automatedtesting_shared.pyside_utils as pyside_utils
class TestViewMenuOptions(EditorTestHelper):
def __init__(self):
EditorTestHelper.__init__(self, log_prefix="Menus_EditMenuOptions", args=["level"])
def run_test(self):
"""
Summary:
Interact with View Menu options and verify if all the options are working.
Expected Behavior:
The View menu functions normally.
Test Steps:
1) Create a temp level
2) Interact with View Menu options
Note:
- This test file must be called from the Lumberyard Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.
:return: None
"""
view_menu_options = [
("Center on Selection",),
("Show Quick Access Bar",),
("Viewport", "Wireframe"),
("Viewport", "Grid Settings"),
("Viewport", "Go to Position"),
("Viewport", "Center on Selection"),
("Viewport", "Go to Location"),
("Viewport", "Remember Location"),
("Viewport", "Change Move Speed"),
("Viewport", "Switch Camera"),
("Viewport", "Show/Hide Helpers"),
("Refresh Style",),
]
# 1) Create and open the temp level
self.test_success = self.create_level(
self.args["level"],
heightmap_resolution=1024,
heightmap_meters_per_pixel=1,
terrain_texture_resolution=4096,
use_terrain=False,
)
def on_action_triggered(action_name):
print(f"{action_name} Action triggered")
# 2) Interact with View Menu options
try:
editor_window = pyside_utils.get_editor_main_window()
for option in view_menu_options:
action = pyside_utils.get_action_for_menu_path(editor_window, "View", *option)
trig_func = lambda: on_action_triggered(action.iconText())
action.triggered.connect(trig_func)
action.trigger()
action.triggered.disconnect(trig_func)
except Exception as e:
self.test_success = False
print(e)
test = TestViewMenuOptions()
test.run()

@ -0,0 +1,51 @@
"""
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 logging
import pytest
import winreg
import automatedtesting_shared.registry_utils as reg
logger = logging.getLogger(__name__)
layout = {
'path': r'Software\Amazon\Lumberyard\Editor\fancyWindowLayouts',
'value': 'last'
}
restore_camera = {
'new': 16384,
'path': r'Software\Amazon\Lumberyard\Editor\AutoHide',
'value': 'ViewportCameraRestoreOnExitGameMode'
}
@pytest.fixture(autouse=True)
def set_editor_registry_defaults(request):
# Records editor settings at start, sets to default, then returns to original at teardown.
logger.debug('Executing an Editor settings fixture. If not executing an Editor test, this may be in error.')
layout['original'] = reg.get_ly_registry_value(layout['path'], layout['value'])
restore_camera['original'] = reg.get_ly_registry_value(restore_camera['path'], restore_camera['value'])
# Deleting current layout value to restore defaults
reg.delete_ly_registry_value(layout['path'], layout['value'])
# Setting restore camera dialog to not display
reg.set_ly_registry_value(restore_camera['path'], restore_camera['value'], restore_camera['new'])
# Revert settings to original values
def teardown():
reg.set_ly_registry_value(layout['path'], layout['value'], layout['original'], value_type=winreg.REG_BINARY)
reg.set_ly_registry_value(restore_camera['path'], restore_camera['value'], restore_camera['original'])
request.addfinalizer(teardown)

@ -0,0 +1,92 @@
"""
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.
"""
"""
C13660195: Asset Browser - File Tree Navigation
"""
import os
import pytest
# Bail on the test if ly_test_tools doesn't exist.
pytest.importorskip('ly_test_tools')
import ly_test_tools.environment.file_system as file_system
import automatedtesting_shared.hydra_test_utils as hydra
test_directory = os.path.join(os.path.dirname(__file__), "EditorScripts")
log_monitor_timeout = 180
@pytest.mark.parametrize('project', ['AutomatedTesting'])
@pytest.mark.parametrize('level', ['tmp_level'])
@pytest.mark.usefixtures("automatic_process_killer")
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
class TestAssetBrowser(object):
@pytest.fixture(autouse=True)
def setup_teardown(self, request, workspace, project, level):
def teardown():
file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
request.addfinalizer(teardown)
file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
@pytest.mark.test_case_id("C13660195")
@pytest.mark.SUITE_periodic
def test_AssetBrowser_TreeNavigation(self, request, editor, level, launcher_platform):
expected_lines = [
"Collapse/Expand tests: True",
"Asset visibility test: True",
"Scrollbar visibility test: True",
"AssetBrowser_TreeNavigation: result=SUCCESS"
]
hydra.launch_and_validate_results(
request,
test_directory,
editor,
"AssetBrowser_TreeNavigation.py",
expected_lines,
run_python="--runpython",
cfg_args=[level],
timeout=log_monitor_timeout
)
@pytest.mark.test_case_id("C13660194")
@pytest.mark.SUITE_periodic
def test_AssetBrowser_SearchFiltering(self, request, editor, level, launcher_platform):
expected_lines = [
"cedar.fbx asset is filtered in Asset Browser",
"Animation file type(s) is present in the file tree: True",
"FileTag file type(s) and Animation file type(s) is present in the file tree: True",
"FileTag file type(s) is present in the file tree after removing Animation filter: True",
]
unexpected_lines = [
"Asset Browser opened: False",
"Animation file type(s) is present in the file tree: False",
"FileTag file type(s) and Animation file type(s) is present in the file tree: False",
"FileTag file type(s) is present in the file tree after removing Animation filter: False",
]
hydra.launch_and_validate_results(
request,
test_directory,
editor,
"AssetBrowser_SearchFiltering.py",
expected_lines,
unexpected_lines=unexpected_lines,
cfg_args=[level],
auto_test_mode=False,
run_python="--runpython",
timeout=log_monitor_timeout,
)

@ -0,0 +1,76 @@
"""
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.
"""
"""
C13751579: Asset Picker UI/UX
"""
import os
import pytest
# Bail on the test if ly_test_tools doesn't exist.
pytest.importorskip('ly_test_tools')
import ly_test_tools.environment.file_system as file_system
import automatedtesting_shared.hydra_test_utils as hydra
test_directory = os.path.join(os.path.dirname(__file__), "EditorScripts")
log_monitor_timeout = 90
@pytest.mark.parametrize('project', ['AutomatedTesting'])
@pytest.mark.parametrize('level', ['tmp_level'])
@pytest.mark.usefixtures("automatic_process_killer")
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
class TestAssetPicker(object):
@pytest.fixture(autouse=True)
def setup_teardown(self, request, workspace, project, level):
def teardown():
file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
request.addfinalizer(teardown)
file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
@pytest.mark.test_case_id("C13751579", "C1508814")
@pytest.mark.SUITE_periodic
def test_AssetPicker_UI_UX(self, request, editor, level, launcher_platform):
expected_lines = [
"TestEntity Entity successfully created",
"Mesh component was added to entity",
"Entity has a Mesh component",
"Mesh Asset: Asset Picker title for Mesh: Pick ModelAsset",
"Mesh Asset: Scroll Bar is not visible before expanding the tree: True",
"Mesh Asset: Top level folder initially collapsed: True",
"Mesh Asset: Top level folder expanded: True",
"Mesh Asset: Nested folder initially collapsed: True",
"Mesh Asset: Nested folder expanded: True",
"Mesh Asset: Scroll Bar appeared after expanding tree: True",
"Mesh Asset: Nested folder collapsed: True",
"Mesh Asset: Top level folder collapsed: True",
"Mesh Asset: Expected Assets populated in the file picker: True",
"Widget Move Test: True",
"Widget Resize Test: True",
"Asset assigned for ok option: True",
"Asset assigned for enter option: True",
"AssetPicker_UI_UX: result=SUCCESS"
]
hydra.launch_and_validate_results(
request,
test_directory,
editor,
"AssetPicker_UI_UX.py",
expected_lines,
cfg_args=[level],
run_python="--runpython",
auto_test_mode=False,
timeout=log_monitor_timeout,
)

@ -33,11 +33,11 @@ class TestComponentCRUD(object):
@pytest.fixture(autouse=True)
def setup_teardown(self, request, workspace, project, level):
def teardown():
file_system.delete([os.path.join(workspace.paths.dev(), project, "Levels", level)], True, True)
file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
request.addfinalizer(teardown)
file_system.delete([os.path.join(workspace.paths.dev(), project, "Levels", level)], True, True)
file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
@pytest.mark.test_case_id("C16929880", "C16877220")
@pytest.mark.SUITE_periodic
@ -48,23 +48,17 @@ class TestComponentCRUD(object):
"Box Shape found",
"Box Shape Component added: True",
"Mesh found",
"Box Shape and Mesh Components present in the entity: True",
"Mesh Component added: True",
"Mesh Component deleted: True",
"Mesh Component deletion undone: True",
]
unexpected_lines = [
"Box Shape Component added: False",
"Box Shape and Mesh Components present in the entity: False",
]
hydra.launch_and_validate_results(
request,
test_directory,
editor,
"ComponentCRUD_Add_Delete_Components.py",
expected_lines,
unexpected_lines=unexpected_lines,
cfg_args=[level],
auto_test_mode=False,
timeout=log_monitor_timeout

@ -0,0 +1,58 @@
"""
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.
C6376081: Basic Function: Docked/Undocked Tools
"""
import os
import pytest
# Bail on the test if ly_test_tools doesn't exist.
pytest.importorskip('ly_test_tools')
import ly_test_tools.environment.file_system as file_system
import automatedtesting_shared.hydra_test_utils as hydra
test_directory = os.path.join(os.path.dirname(__file__), "EditorScripts")
log_monitor_timeout = 180
@pytest.mark.parametrize('project', ['AutomatedTesting'])
@pytest.mark.parametrize('level', ['tmp_level'])
@pytest.mark.usefixtures("automatic_process_killer")
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
class TestDocking(object):
@pytest.fixture(autouse=True)
def setup_teardown(self, request, workspace, project, level):
def teardown():
file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
request.addfinalizer(teardown)
file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
@pytest.mark.test_case_id("C6376081")
@pytest.mark.SUITE_periodic
def test_basic_docked_tools(self, request, editor, level, launcher_platform):
expected_lines = [
"The tools are all docked together in a tabbed widget",
"Entity Outliner works when docked, can select an Entity",
"Entity Inspector works when docked, Entity name changed to DifferentName",
"Hello, world!" # This line verifies the Console is working while docked
]
hydra.launch_and_validate_results(
request,
test_directory,
editor,
"Docking_BasicDockedTools.py",
expected_lines,
cfg_args=[level],
timeout=log_monitor_timeout,
)

@ -33,11 +33,11 @@ class TestInputBindings(object):
@pytest.fixture(autouse=True)
def setup_teardown(self, request, workspace, project, level):
def teardown():
file_system.delete([os.path.join(workspace.paths.dev(), project, "Levels", level)], True, True)
file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
request.addfinalizer(teardown)
file_system.delete([os.path.join(workspace.paths.dev(), project, "Levels", level)], True, True)
file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
@pytest.mark.test_case_id("C1506881")
@pytest.mark.SUITE_periodic

@ -0,0 +1,143 @@
"""
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.
C16780783: Base Edit Menu Options (New Viewport Interaction Model)
"""
import os
import pytest
# Bail on the test if ly_test_tools doesn't exist.
pytest.importorskip('ly_test_tools')
import ly_test_tools.environment.file_system as file_system
import automatedtesting_shared.hydra_test_utils as hydra
test_directory = os.path.join(os.path.dirname(__file__), "EditorScripts")
log_monitor_timeout = 180
@pytest.mark.parametrize('project', ['AutomatedTesting'])
@pytest.mark.parametrize('level', ['tmp_level'])
@pytest.mark.usefixtures("automatic_process_killer")
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
class TestMenus(object):
@pytest.fixture(autouse=True)
def setup_teardown(self, request, workspace, project, level):
def teardown():
file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
request.addfinalizer(teardown)
file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
@pytest.mark.test_case_id("C16780783", "C2174438")
@pytest.mark.SUITE_periodic
def test_Menus_EditMenuOptions_Work(self, request, editor, level, launcher_platform):
expected_lines = [
"Undo Action triggered",
"Redo Action triggered",
"Duplicate Action triggered",
"Delete Action triggered",
"Select All Action triggered",
"Invert Selection Action triggered",
"Toggle Pivot Location Action triggered",
"Reset Entity Transform",
"Reset Manipulator",
"Reset Transform (Local) Action triggered",
"Reset Transform (World) Action triggered",
"Hide Selection Action triggered",
"Show All Action triggered",
"Snap angle Action triggered",
"Move Action triggered",
"Rotate Action triggered",
"Scale Action triggered",
"Lock Selection Action triggered",
"Unlock All Entities Action triggered",
"Global Preferences Action triggered",
"Graphics Settings Action triggered",
"Editor Settings Manager Action triggered",
"Very High Action triggered",
"High Action triggered",
"Medium Action triggered",
"Low Action triggered",
"Customize Keyboard Action triggered",
"Export Keyboard Settings Action triggered",
"Import Keyboard Settings Action triggered",
"Menus_EditMenuOptions: result=SUCCESS"
]
hydra.launch_and_validate_results(
request,
test_directory,
editor,
"Menus_EditMenuOptions.py",
expected_lines,
cfg_args=[level],
run_python="--runpython",
auto_test_mode=True,
timeout=log_monitor_timeout,
)
@pytest.mark.test_case_id("C16780807")
@pytest.mark.SUITE_periodic
def test_Menus_ViewMenuOptions_Work(self, request, editor, level, launcher_platform):
expected_lines = [
"Center on Selection Action triggered",
"Show Quick Access Bar Action triggered",
"Wireframe Action triggered",
"Grid Settings Action triggered",
"Go to Position Action triggered",
"Center on Selection Action triggered",
"Go to Location Action triggered",
"Remember Location Action triggered",
"Change Move Speed Action triggered",
"Switch Camera Action triggered",
"Show/Hide Helpers Action triggered",
"Refresh Style Action triggered",
]
hydra.launch_and_validate_results(
request,
test_directory,
editor,
"Menus_ViewMenuOptions.py",
expected_lines,
cfg_args=[level],
auto_test_mode=True,
run_python="--runpython",
timeout=log_monitor_timeout,
)
@pytest.mark.test_case_id("C16780778")
@pytest.mark.SUITE_periodic
def test_Menus_FileMenuOptions_Work(self, request, editor, level, launcher_platform):
expected_lines = [
"New Level Action triggered",
"Open Level Action triggered",
"Import Action triggered",
"Save Action triggered",
"Save As Action triggered",
"Save Level Statistics Action triggered",
"Project Settings Tool Action triggered",
"Show Log File Action triggered",
"Resave All Slices Action triggered",
"Exit Action triggered",
]
hydra.launch_and_validate_results(
request,
test_directory,
editor,
"Menus_FileMenuOptions.py",
expected_lines,
cfg_args=[level],
auto_test_mode=True,
run_python="--runpython",
timeout=log_monitor_timeout,
)

@ -33,11 +33,11 @@ class TestSearchFiltering(object):
@pytest.fixture(autouse=True)
def setup_teardown(self, request, workspace, project, level):
def teardown():
file_system.delete([os.path.join(workspace.paths.dev(), project, "Levels", level)], True, True)
file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
request.addfinalizer(teardown)
file_system.delete([os.path.join(workspace.paths.dev(), project, "Levels", level)], True, True)
file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
@pytest.mark.test_case_id("C13660194")
@pytest.mark.SUITE_periodic
@ -60,7 +60,7 @@ class TestSearchFiltering(object):
request,
test_directory,
editor,
"SearchFiltering_Asset_Browser_Filtering.py",
"AssetBrowser_SearchFiltering.py",
expected_lines,
unexpected_lines=unexpected_lines,
cfg_args=[level],

@ -33,11 +33,11 @@ class TestTreeNavigation(object):
@pytest.fixture(autouse=True)
def setup_teardown(self, request, workspace, project, level):
def teardown():
file_system.delete([os.path.join(workspace.paths.dev(), project, "Levels", level)], True, True)
file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
request.addfinalizer(teardown)
file_system.delete([os.path.join(workspace.paths.dev(), project, "Levels", level)], True, True)
file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
@pytest.mark.test_case_id("C13660195")
@pytest.mark.SUITE_periodic

@ -55,7 +55,7 @@ class TestAltitudeFilterComponentAndOverrides(EditorTestHelper):
8) Instance counts post-filter are verified.
Note:
- This test file must be called from the Lumberyard Editor command terminal
- This test file must be called from the Open 3D Engine Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.

@ -11,6 +11,11 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
import os
import sys
import azlmbr.bus as bus
import azlmbr.components as components
import azlmbr.editor as editor
import azlmbr.legacy.general as general
import azlmbr.math as math
import azlmbr.paths
@ -36,8 +41,8 @@ class TestAltitudeFilterFilterStageToggle(EditorTestHelper):
:return: None
"""
PREPROCESS_INSTANCE_COUNT = 16
POSTPROCESS_INSTANCE_COUNT = 13
PREPROCESS_INSTANCE_COUNT = 24
POSTPROCESS_INSTANCE_COUNT = 18
# Create empty level
self.test_success = self.create_level(
@ -60,7 +65,22 @@ class TestAltitudeFilterFilterStageToggle(EditorTestHelper):
dynveg.create_surface_entity("Surface_Entity_Parent", position, 16.0, 16.0, 1.0)
# Add entity with Mesh to replicate creation of hills
dynveg.create_mesh_surface_entity_with_slopes("hill", position, 40.0, 40.0, 40.0)
hill_entity = dynveg.create_mesh_surface_entity_with_slopes("hill", position, 40.0, 40.0, 40.0)
# Disable/Re-enable Mesh component due to ATOM-14299
general.idle_wait(1.0)
editor.EditorComponentAPIBus(bus.Broadcast, 'DisableComponents', [hill_entity.components[0]])
is_enabled = editor.EditorComponentAPIBus(bus.Broadcast, 'IsComponentEnabled', hill_entity.components[0])
if is_enabled:
print("Mesh component is still enabled")
else:
print("Mesh component was disabled")
editor.EditorComponentAPIBus(bus.Broadcast, 'EnableComponents', [hill_entity.components[0]])
is_enabled = editor.EditorComponentAPIBus(bus.Broadcast, 'IsComponentEnabled', hill_entity.components[0])
if is_enabled:
print("Mesh component is now enabled")
else:
print("Mesh component is still disabled")
# Increase Box Shape size to encompass the hills
vegetation.get_set_test(1, "Box Shape|Box Configuration|Dimensions", math.Vector3(100.0, 100.0, 100.0))
@ -69,8 +89,8 @@ class TestAltitudeFilterFilterStageToggle(EditorTestHelper):
vegetation.get_set_test(3, "Configuration|Altitude Min", 38.0)
vegetation.get_set_test(3, "Configuration|Altitude Max", 40.0)
# Create a new entity as a child of the vegetation area entity with Random Noise Gradient Generator, Gradient Transform Modifier,
# and Box Shape component
# Create a new entity as a child of the vegetation area entity with Random Noise Gradient Generator, Gradient
# Transform Modifier, and Box Shape component
random_noise = hydra.Entity("random_noise")
random_noise.create_entity(position, ["Random Noise Gradient", "Gradient Transform Modifier", "Box Shape"])
random_noise.set_test_parent_entity(vegetation)
@ -91,4 +111,4 @@ class TestAltitudeFilterFilterStageToggle(EditorTestHelper):
test = TestAltitudeFilterFilterStageToggle()
test.run()
test.run()

@ -48,7 +48,7 @@ class TestAltitudeFilterShapeSample(EditorTestHelper):
6) Instance counts post-filter are verified.
Note:
- This test file must be called from the Lumberyard Editor command terminal
- This test file must be called from the Open 3D Engine Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.

@ -57,7 +57,7 @@ class TestAssetListCombiner(EditorTestHelper):
Combiner component to force a refresh, and validate instance count
Note:
- This test file must be called from the Lumberyard Editor command terminal
- This test file must be called from the Open 3D Engine Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.

@ -52,7 +52,7 @@ class TestAssetWeightSelectorSortByWeight(EditorTestHelper):
8) Change sort values and validate instance count
Note:
- This test file must be called from the Lumberyard Editor command terminal
- This test file must be called from the Open 3D Engine Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.

@ -44,7 +44,7 @@ class TestDistanceBetweenFilterComponentOverrides(EditorTestHelper):
expected instance counts with a few different Radius values
Note:
- This test file must be called from the Lumberyard Editor command terminal
- This test file must be called from the Open 3D Engine Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.

@ -42,7 +42,7 @@ class TestDistanceBetweenFilterComponent(EditorTestHelper):
5-8) Add the Distance Between Filter, and validate expected instance counts with a few different Radius values
Note:
- This test file must be called from the Lumberyard Editor command terminal
- This test file must be called from the Open 3D Engine Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.

@ -49,7 +49,7 @@ class TestDynamicSliceInstanceSpawnerEmbeddedEditor(EditorTestHelper):
6) Save and export to engine
Note:
- This test file must be called from the Lumberyard Editor command terminal
- This test file must be called from the Open 3D Engine Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.

@ -49,7 +49,7 @@ class TestDynamicSliceInstanceSpawnerExternalEditor(EditorTestHelper):
6) Save and export to engine
Note:
- This test file must be called from the Lumberyard Editor command terminal
- This test file must be called from the Open 3D Engine Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.

@ -49,7 +49,7 @@ class TestInstanceSpawnerPriority(EditorTestHelper):
6) Validate instance counts in the spawner area
Note:
- This test file must be called from the Lumberyard Editor command terminal
- This test file must be called from the Open 3D Engine Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.

@ -59,7 +59,7 @@ class TestVegLayerBlenderCreated(EditorTestHelper):
7) Export to engine
Note:
- This test file must be called from the Lumberyard Editor command terminal
- This test file must be called from the Open 3D Engine Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.

@ -48,7 +48,7 @@ class TestLayerBlocker(EditorTestHelper):
7. Post-blocker instance counts are validated
Note:
- This test file must be called from the Lumberyard Editor command terminal
- This test file must be called from the Open 3D Engine Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.

@ -12,6 +12,9 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
import os
import sys
import azlmbr.bus as bus
import azlmbr.editor as editor
import azlmbr.legacy.general as general
import azlmbr.math as math
import azlmbr.paths
@ -36,8 +39,8 @@ class TestLayerSpawnerFilterStageToggle(EditorTestHelper):
:return: None
"""
PREPROCESS_INSTANCE_COUNT = 16
POSTPROCESS_INSTANCE_COUNT = 19
PREPROCESS_INSTANCE_COUNT = 425
POSTPROCESS_INSTANCE_COUNT = 430
# Create empty level
self.test_success = self.create_level(
@ -48,13 +51,17 @@ class TestLayerSpawnerFilterStageToggle(EditorTestHelper):
use_terrain=False,
)
general.set_current_view_position(500.49, 498.69, 46.66)
general.set_current_view_rotation(-42.05, 0.00, -36.33)
# Create a vegetation area with all needed components
position = math.Vector3(512.0, 512.0, 32.0)
asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
vegetation_entity = dynveg.create_vegetation_area("vegetation", position, 16.0, 16.0, 10.0, asset_path)
vegetation_entity.add_component("Vegetation Slope Filter")
vegetation_entity = dynveg.create_vegetation_area("vegetation", position, 16.0, 16.0, 16.0, asset_path)
vegetation_entity.add_component("Vegetation Altitude Filter")
vegetation_entity.add_component("Vegetation Position Modifier")
# Create a child entity under vegetation area
child_entity = hydra.Entity("child_entity")
components_to_add = ["Random Noise Gradient", "Gradient Transform Modifier", "Box Shape"]
@ -64,12 +71,29 @@ class TestLayerSpawnerFilterStageToggle(EditorTestHelper):
vegetation_entity.get_set_test(4, "Configuration|Position X|Gradient|Gradient Entity Id", child_entity.id)
vegetation_entity.get_set_test(4, "Configuration|Position Y|Gradient|Gradient Entity Id", child_entity.id)
# Set the min and max values for Slope Filter
vegetation_entity.get_set_test(3, "Configuration|Slope Min", 25)
vegetation_entity.get_set_test(3, "Configuration|Slope Max", 35)
# Add entity with Mesh to replicate creation of hills
dynveg.create_mesh_surface_entity_with_slopes("hill", position, 5.0, 5.0, 5.0)
# Set the min and max values for Altitude Filter
vegetation_entity.get_set_test(3, "Configuration|Altitude Min", 32.0)
vegetation_entity.get_set_test(3, "Configuration|Altitude Max", 35.0)
# Add entity with Mesh to replicate creation of hills and a flat surface to plant on
dynveg.create_surface_entity("Flat Surface", position, 32.0, 32.0, 1.0)
hill_entity = dynveg.create_mesh_surface_entity_with_slopes("hill", position, 4.0, 4.0, 4.0)
# Disable/Re-enable Mesh component due to ATOM-14299
general.idle_wait(1.0)
editor.EditorComponentAPIBus(bus.Broadcast, 'DisableComponents', [hill_entity.components[0]])
is_enabled = editor.EditorComponentAPIBus(bus.Broadcast, 'IsComponentEnabled', hill_entity.components[0])
if is_enabled:
print("Mesh component is still enabled")
else:
print("Mesh component was disabled")
editor.EditorComponentAPIBus(bus.Broadcast, 'EnableComponents', [hill_entity.components[0]])
is_enabled = editor.EditorComponentAPIBus(bus.Broadcast, 'IsComponentEnabled', hill_entity.components[0])
if is_enabled:
print("Mesh component is now enabled")
else:
print("Mesh component is still disabled")
# Set the filter stage to preprocess and postprocess respectively and verify instance count
vegetation_entity.get_set_test(0, "Configuration|Filter Stage", 1)

@ -14,6 +14,9 @@ import os, sys
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
import azlmbr.asset as asset
import azlmbr.bus as bus
import azlmbr.components as components
import azlmbr.editor as editor
import azlmbr.legacy.general as general
import azlmbr.math as math
sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests'))
@ -70,19 +73,36 @@ class test_MeshBlocker_InstancesBlockedByMesh(EditorTestHelper):
dynveg.create_surface_entity("Surface Entity", entity_position, 10.0, 10.0, 1.0)
# Create blocker entity with cube mesh
mesh_type_id = azlmbr.globals.property.EditorMeshComponentTypeId
blocker_entity = hydra.Entity("Blocker Entity")
blocker_entity.create_entity(entity_position,
["Mesh", "Vegetation Layer Blocker (Mesh)"])
["Vegetation Layer Blocker (Mesh)"])
blocker_entity.add_component_of_type(mesh_type_id)
if blocker_entity.id.IsValid():
print(f"'{blocker_entity.name}' created")
cubeId = asset.AssetCatalogRequestBus(
bus.Broadcast, "GetAssetIdByPath", os.path.join("objects", "default", "primitive_cube.cgf"), math.Uuid(),
bus.Broadcast, "GetAssetIdByPath", os.path.join("objects", "_primitives", "_box_1x1.azmodel"), math.Uuid(),
False)
blocker_entity.get_set_test(0, "MeshComponentRenderNode|Mesh asset", cubeId)
blocker_entity.get_set_test(1, "Controller|Configuration|Mesh Asset", cubeId)
components.TransformBus(bus.Event, "SetLocalScale", blocker_entity.id, math.Vector3(2.0, 2.0, 2.0))
# Disable/Re-enable Mesh component due to ATOM-14299
general.idle_wait(1.0)
editor.EditorComponentAPIBus(bus.Broadcast, 'DisableComponents', [blocker_entity.components[1]])
is_enabled = editor.EditorComponentAPIBus(bus.Broadcast, 'IsComponentEnabled', blocker_entity.components[1])
if is_enabled:
print("Mesh component is still enabled")
else:
print("Mesh component was disabled")
editor.EditorComponentAPIBus(bus.Broadcast, 'EnableComponents', [blocker_entity.components[1]])
is_enabled = editor.EditorComponentAPIBus(bus.Broadcast, 'IsComponentEnabled', blocker_entity.components[1])
if is_enabled:
print("Mesh component is now enabled")
else:
print("Mesh component is still disabled")
# Verify spawned instance counts are accurate after addition of Blocker Entity
num_expected = 160 # Number of "PurpleFlower"s that plant on a 10 x 10 surface minus 1m blocker cube
num_expected = 160 # Number of "PurpleFlower"s that plant on a 10 x 10 surface minus 2m blocker cube
result = self.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id,
num_expected), 2.0)
self.test_success = self.test_success and result

@ -10,6 +10,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
import os
import math as pymath
import sys
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
@ -17,6 +18,8 @@ import azlmbr
import azlmbr.asset as asset
import azlmbr.bus as bus
import azlmbr.components as components
import azlmbr.editor as editor
import azlmbr.legacy.general as general
import azlmbr.math as math
@ -63,6 +66,9 @@ class test_MeshBlocker_InstancesBlockedByMeshHeightTuning(EditorTestHelper):
use_terrain=False,
)
general.set_current_view_position(500.49, 498.69, 46.66)
general.set_current_view_rotation(-42.05, 0.00, -36.33)
# 2) Create entity with components "Vegetation Layer Spawner", "Vegetation Asset List", "Box Shape"
entity_position = math.Vector3(512.0, 512.0, 32.0)
asset_path = os.path.join("Slices", "PurpleFlower.dynamicslice")
@ -74,29 +80,46 @@ class test_MeshBlocker_InstancesBlockedByMeshHeightTuning(EditorTestHelper):
# 3) Create surface entity to plant on
dynveg.create_surface_entity("Surface Entity", entity_position, 10.0, 10.0, 1.0)
# 4) Create blocker entity with cube mesh
entity_position = math.Vector3(512.0, 512.0, 36.0)
# 4) Create blocker entity with rotated cube mesh
y_rotation = pymath.radians(45.0)
mesh_type_id = azlmbr.globals.property.EditorMeshComponentTypeId
blocker_entity = hydra.Entity("Blocker Entity")
blocker_entity.create_entity(entity_position,
["Mesh", "Vegetation Layer Blocker (Mesh)"])
["Vegetation Layer Blocker (Mesh)"])
blocker_entity.add_component_of_type(mesh_type_id)
if blocker_entity.id.IsValid():
print(f"'{blocker_entity.name}' created")
sphereId = asset.AssetCatalogRequestBus(
bus.Broadcast, "GetAssetIdByPath", os.path.join("objects", "default", "primitive_sphere.cgf"), math.Uuid(),
sphere_id = asset.AssetCatalogRequestBus(
bus.Broadcast, "GetAssetIdByPath", os.path.join("objects", "_primitives", "_box_1x1.azmodel"), math.Uuid(),
False)
blocker_entity.get_set_test(0, "MeshComponentRenderNode|Mesh asset", sphereId)
blocker_entity.get_set_test(1, "Controller|Configuration|Mesh Asset", sphere_id)
components.TransformBus(bus.Event, "SetLocalScale", blocker_entity.id, math.Vector3(5.0, 5.0, 5.0))
components.TransformBus(bus.Event, "SetLocalRotation", blocker_entity.id, math.Vector3(0.0, y_rotation, 0.0))
# Disable/Re-enable Mesh component due to ATOM-14299
general.idle_wait(1.0)
editor.EditorComponentAPIBus(bus.Broadcast, 'DisableComponents', [blocker_entity.components[1]])
is_enabled = editor.EditorComponentAPIBus(bus.Broadcast, 'IsComponentEnabled', blocker_entity.components[1])
if is_enabled:
print("Mesh component is still enabled")
else:
print("Mesh component was disabled")
editor.EditorComponentAPIBus(bus.Broadcast, 'EnableComponents', [blocker_entity.components[1]])
is_enabled = editor.EditorComponentAPIBus(bus.Broadcast, 'IsComponentEnabled', blocker_entity.components[1])
if is_enabled:
print("Mesh component is now enabled")
else:
print("Mesh component is still disabled")
# 5) Adjust the height Max percentage values of blocker
blocker_entity.get_set_test(1, "Configuration|Mesh Height Percent Max", 0.8)
blocker_entity.get_set_test(0, "Configuration|Mesh Height Percent Max", 0.8)
# 6) Verify spawned instance counts are accurate after adjusting height Max percentage of Blocker Entity
# The number of "PurpleFlower" instances that plant on a 10 x 10 surface minus those blocked by the sphere at
# The number of "PurpleFlower" instances that plant on a 10 x 10 surface minus those blocked by the rotated at
# 80% max height factored in.
num_expected = 117
num_expected = 127
result = self.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id,
num_expected), 2.0)
num_expected), 5.0)
self.test_success = self.test_success and result

@ -45,7 +45,7 @@ class TestMeshSurfaceTagEmitter(EditorTestHelper):
5) Make sure Mesh Surface Tag Emitter is enabled after adding Mesh
Note:
- This test file must be called from the Lumberyard Editor command terminal
- This test file must be called from the Open 3D Engine Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.

@ -42,7 +42,7 @@ class TestMeshSurfaceTagEmitter(EditorTestHelper):
3) Add/ remove Surface Tags
Note:
- This test file must be called from the Lumberyard Editor command terminal
- This test file must be called from the Open 3D Engine Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save