You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
#lockdown Nick.Penwarden Change 3315047 on 2017/02/21 by Mieszko.Zielinski@mieszko.zielinski_T4675_Orion HTN code first check in #UE4 #rb none #test currently unused Change 3314042 on 2017/02/21 by Jason.Bestimt@Jason.Bestimt_Dev-General #ORION_DG - DAILY Main @ CL 3313484 #RB:none #Tests:none Change 3313355 on 2017/02/20 by Uriel.Doyon@uriel.doyon_PC2_Orion Changed the preliminary GPU benchmark workloads to take into account the target workload. This is to prevent running the last test with poor performance, risking a driver reset. #jira OR-29915 #rb marcus.wassmer #test Run the game triggering benchmarks Change 3312553 on 2017/02/20 by Mieszko.Zielinski@mieszko.zielinski_T4675_Orion Implemented a simple AITask for running EQS queries #UE4 #rb Lukasz.Furman #test golden path Change 3311661 on 2017/02/20 by Jason.Bestimt@Jason.Bestimt_Dev-General #ORION_DG - Merge MAIN @ CL 3311631 #RB:none #Tests:none Change 3310392 on 2017/02/17 by Daniel.Lamb@daniel.lamb_T3905_6612 Unreal pak now outputs to named log files instead of timestamps. #rb Trivial #test Cook deploy paragon #jira OR-36057 Change 3310196 on 2017/02/17 by Clayton.Langford@RDU-WD-8359_3635_Paragon_DevGen Created an event to be fired whenever a GameplayCue is routed that passes all relevant info about that GC. Added a listener in OrionPhasedFunctionalTest that parses that event into a string and stores it in an array to be accessed from a test phase later. #test PIE #rb Ben.Salem, Adric.Worley Change 3308437 on 2017/02/16 by Jason.Bestimt@Jason.Bestimt_Dev-General #ORION_DG - Merge MAIN @ CL 3308413 (Prep for Merge up) #RB:none #Tests:none Change 3306497 on 2017/02/16 by Andrew.Grant@andrew.grant.T6730.orion.floating Fix for compilation issue with USE_MALLOC_STOMP #rb none #tests compiled with malloc_stomp Change 3306468 on 2017/02/16 by Cody.Haskell@OrionStream #Orion - Text popup work for Shield. If you click on an OrionEditableTextBox while running the game with -gfn, a special popup is called. Should do nothing normally. #rb none #tests PIE, golden path. Change 3305945 on 2017/02/16 by David.Ratti@David.Ratti_G6218_Orion.Dev-General Remove unused/deprecated UGameplayEffectExtension class #rb #tests none Change 3304630 on 2017/02/15 by Jason.Bestimt@Jason.Bestimt_Dev-General #ORION_DG - Merge Mieszko stuff from MAIN to DG #RB:none #TestS:none #!codereview: mieszko.zielinski Change 3303785 on 2017/02/15 by jason.bestimt@Jason.Bestimt_Dev-General #ORION_MAIN - Merge 38.3 @ CL 3303224 #RB:none #Tests:none #!ROBOMERGE-SOURCE: CL 3303718 in //Orion/Main/... #!ROBOMERGE-BOT: ORION (Main -> Dev-General) #!ROBOMERGE-SAYS: Unresolved conflicts. jason.bestimt, please merge this change by hand. //Orion/Dev-General/OrionGame/Content/UI/DeckBuilder/DeckBuilderRoot.uasset - can't integrate exclusive file already opened //Orion/Dev-General/OrionGame/Content/UI/Master_Layouts/FrontEnd.uasset - can't integrate exclusive file already opened #!codereview: jason.bestimt Change 3302382 on 2017/02/14 by Alexis.Matte@amatte-orion-dev-general Fix import of morph target when there is no animation #jira UE-41383 #jira OR-35859 #rb none #test none Change 3301538 on 2017/02/14 by Jason.Bestimt@ROBOMERGE_ORION_Dev_General #!ROBOMERGE-AUTHOR: jason.bestimt #ORION_MAIN - Merge 38.3 @ CL 3301392 #RB:none #Tests:none #!ROBOMERGE-SOURCE: CL 3301481 in //Orion/Main/... #!ROBOMERGE-BOT: ORION (Main -> Dev-General) Change 3299985 on 2017/02/13 by Lukasz.Furman@Lukasz.Furman_T7320_OrionStream added time limit to "get out of overlap" move for minons to avoid getting stuck in moving to inaccessbile spots #jira OR-35834 #rb Mieszko.Zielinski #tests PIE Change 3299732 on 2017/02/13 by Mieszko.Zielinski@mieszko.zielinski_T4675_Orion Tweaked the way EQS tests of negative score get normalized #UE4 #rb none #test golden path + math #!codereview Lukasz.Furman, John.Abercrombie Change 3299724 on 2017/02/13 by Mieszko.Zielinski@mieszko.zielinski_T4675_Orion Generic AI interface extensions #UE4 Mostly getters #rb none #test golden path Change 3299717 on 2017/02/13 by Mieszko.Zielinski@mieszko.zielinski_T4675_Orion A little tweak to VisLog's point labels drawing - if there's only one point in a set it will no longer append '_0' to the label #UE4 #rb none #test PIE Change 3299527 on 2017/02/13 by Paul.Moore@OrionWorkspace_Dev-General #orion #mms - Update libWebSockets binaries to fix Linux server web socket connections. #tests matchmaking, mms #rb none Change 3299278 on 2017/02/13 by David.Ratti@David.Ratti_G6218_Orion.Dev-General Ability Task Pass: tasks should not broadcast out (back into ability graph) if the owning ability has completed EndAbility. #rb none #tests pie, golden path Change3297884on 2017/02/10 by Paul.Moore@OrionWorkspace_Dev-General #mms - Enable SSL module for PS4 (needed by OpenSSL when using WebSockets). - Turn on verbose logging for WebSockets module for initial MMS debugging. #tests PS4 #rb none Change 3296911 on 2017/02/10 by John.Pollard@John.Pollard_T2802_Orion_DevGeneral Encode user search string so we support special characters #rb RyanG #tests Replays Change 3296746 on 2017/02/10 by Jason.Bestimt@ROBOMERGE_ORION_Dev_General #!ROBOMERGE-AUTHOR: jason.bestimt #ORION_MAIN - Merge 38.3 @ CL 3296659 #RB:none #Tests:none #!ROBOMERGE-SOURCE: CL 3296735 in //Orion/Main/... #!ROBOMERGE-BOT: ORION (Main -> Dev-General) Change 3296705 on 2017/02/10 by Daniel.Lamb@daniel.lamb_T3905_6612 Added support to the cooker for iterating shared builds. #rb Not used yet #test Fast cook paragon Change 3295747 on 2017/02/09 by Paul.Moore@OrionWorkspace_Dev-General #orion #mms - Integrated WS upgrade header functionality with latest Fortnite libws changes. - Added "ws" and "wss" protocols to web socket manager context. #rb rob.cannaday #!codereview rob.cannaday, james.hopkin #tests win64, ps4 Change 3295579 on 2017/02/09 by John.Pollard@John.Pollard_T2802_Orion_DevGeneral Fix for replay backward compatibility from John.Pollard #tests #rb na Merging using OrionScratchReleaseMapping Change 3295506 on 2017/02/09 by Rolando.Caloca@rolando.caloca_T3903_OrionMainS O - Added option for force recompute tangents using skin cache #rb none #jira UE-41541 #tests Editor run, toggle, restart Change 3295461 on 2017/02/09 by Lukasz.Furman@Lukasz.Furman_T7320_OrionStream fixed huge interpolation times for linear network smoothing on stationary characters, fixed mismatch in movement Base between NavWalking server and Walking client, causing some stationary characters to float in midair copy of CL# 3295439 #jira OR-35664, OR-35572 #rb none #tests game Change 3294954 on 2017/02/09 by Paul.Moore@OrionWorkspace_Dev-General #orion #mms - Integrating Fortnite WebSocket changes into Orion that fixes some win10 issues. #!codereview rob.cannaday, james.hopkin #tests compile ps4, linux, win64 #rb none Change 3294947 on 2017/02/09 by Daniel.Lamb@daniel.lamb_T3905_6612 The generate stub return result is considered as success when saving cooked packages. Fixes bug with cooking blueprint nativized packages. #rb Trivial #test Cook paragon Change 3293307 on 2017/02/08 by Andrew.Grant@andrew.grant.T6730.orion.floating Fix for issue in last checkin - need to clear activecontext regardless #rb none #tests solo smoke with nullrhi Change 3293284 on 2017/02/08 by Ryan.Gerleve@Ryan.Gerleve_T3703_Orion Allow setting the per-frame time limit for processing queued bunches separately for instant replays, since they may have more strict timing/framerate requirements. #rb john.pollard #tests golden path Change 3293148 on 2017/02/08 by Andrew.Grant@andrew.grant.T6730.orion.floating Fixed invalid memory access* with nullrhi and suppressed IME warning if no valid window handle exists (*Likely only an issue when running with memory validation) #rb none #tests verified invalid access exception no longer occurs with nullrhi #!review-3293149 @Matt.Khulenschmidt Change 3293103 on 2017/02/08 by Max.Chen@Max.Chen_T4664_Orion_Main Sequencer: Fix build #jira OR-34918 #rb none #tests none Change 3292921 on 2017/02/08 by Max.Chen@Max.Chen_T4664_Orion_Main Sequencer: Force local player to maintain x fov axis. #jira OR-34918 #rb david.ratti #tests Render/PIE a level sequence and test that the camera isn't zoomed in. Change 3292869 on 2017/02/08 by David.Ratti@David.Ratti_G6218_Orion.Dev-General Yet more logging for OR-35448 #rb #tests none Change 3292821 on 2017/02/08 by Jason.Bestimt@ROBOMERGE_ORION_Dev_General #!ROBOMERGE-AUTHOR: rob.cannaday PS4 libwebsockets build fix Update build cs files to point to PS4 file location Copy libwebsocket include directory from Fortnite to Orion #rb paul.moore #tests compile/link Win64 Development Editor, PS4 Debug, Linux Development Server #!ROBOMERGE-SOURCE: CL 3292820 in //Orion/Main/... #!ROBOMERGE-BOT: ORION (Main -> Dev-General) Change 3292277 on 2017/02/08 by Jason.Bestimt@ROBOMERGE_ORION_Dev_General #!ROBOMERGE-AUTHOR: jason.bestimt #ORION_MAIN - Merge DMM @ CL 3292219 #RB:none #Tests:none [CODEREVIEW] paul.moore, benjamin.crocker #QAReview #!ROBOMERGE-SOURCE: CL 3292276 in //Orion/Main/... #!ROBOMERGE-BOT: ORION (Main -> Dev-General) Change 3292211 on 2017/02/08 by Andrew.Grant@andrew.grant.T6730.orion.floating Pulling new ags library from Release-4.15 and reverting hack that disabled feature for AMD users #rb Marcus.Wassmer #tests compiled Change 3292167 on 2017/02/08 by David.Ratti@David.Ratti_G6218_Orion.Dev-General Additional logging for OR-35448 #rb none #tests pie Change 3289462 on 2017/02/06 by Ben.Salem@ben.salem_OrionMain Adding priority filters to Automation tests, also commands to filter on priority levels. #rb adric worley #tests Compiled, ran a few commands to verify it works. Change3288801on 2017/02/06 by Jason.Bestimt@ROBOMERGE_ORION_Dev_General #!ROBOMERGE-AUTHOR: jason.bestimt #ORION_MAIN - Merge 37.2 (38.3) @ CL3288681#RB:none #Tests:none #!ROBOMERGE-SOURCE: CL 3288800 in //Orion/Main/... #!ROBOMERGE-BOT: ORION (Main -> Dev-General) Change 3288750 on 2017/02/06 by Daniel.Lamb@daniel.lamb_T3905_6612 Fixed issue when cooking client and server platforms in single cook some packages would be marked incorrectly because they would be stripped when from client / server. #rb Andrew.Grant #test Cook paragon Change 3288624 on 2017/02/06 by Andrew.Grant@andrew.grant.T6730.orion.floating Unlocked network version #rb #tests na OR-35603 Change 3288612 on 2017/02/06 by Daniel.Lamb@daniel.lamb_T3905_6612 Added more ini settings to the iterative ini blacklist. #rb Trivial #test Iterative Cook Paragon Change 3288184 on 2017/02/06 by Andrew.Grant@andrew.grant.T6730.orion.floating Downgraded warning to display #!review-3288185 @David.Ratti #rb none #tests none Change 3287634 on 2017/02/06 by Jason.Bestimt@ROBOMERGE_ORION_Dev_General #!ROBOMERGE-AUTHOR: jason.bestimt #ORION_MAIN - Merge 37.2 @ 3287498 #RB:none #Tests:none #!ROBOMERGE-SOURCE: CL 3287619 in //Orion/Main/... #!ROBOMERGE-BOT: ORION (Main -> Dev-General) Change 3286668 on 2017/02/03 by Alexis.Matte@amatte-orion-dev-general Fix a crash when importing a LOD containing different material with less sections #rb none #test none Change 3286112 on 2017/02/03 by Alexis.Matte@amatte-orion-dev-general Fix the re-import skeletal mesh regression, where all material disapear. #jira UE-41294 #rb matt.kuhlenschmidt #test see the jira Change3285859on 2017/02/03 by Daniel.Lamb@daniel.lamb_T3905_6612 Fixed merge error from last checkin with the DDC commandlet #!codereview Matthew.Griffin #test DDC commandlet paragon #rb None Change 3285637 on 2017/02/03 by Ryan.Gerleve@Ryan.Gerleve_T3703_Orion Pass in the DemoNetDriver pointer to the ConcurrentWithSlateTickTask instead of accessing it from the world in the task itself. #rb john.pollard #tests golden path Change 3285479 on 2017/02/03 by Mieszko.Zielinski@mieszko.zielinski_T4675_Orion Made bot communicate ults when they're up, not when they're using it #Orion CL also contains a bit of code shuffling around, preparing ground for HTN plug in #rb none #test golden path Change 3285125 on 2017/02/03 by Jason.Bestimt@ROBOMERGE_ORION_Dev_General #!ROBOMERGE-AUTHOR: jason.bestimt #ORION_MAIN - Merge 37.2 @ CL 3285078 #RB:none #Tests:none #!ROBOMERGE-SOURCE: CL 3285124 in //Orion/Main/... #!ROBOMERGE-BOT: ORION (Main -> Dev-General) Change 3283996 on 2017/02/02 by Michael.Trepka@Michael.Trepka_PC_Orion-Dev-General Added UGameUserSettings::GetRecommandedResolutionScale() to replace UOrionGameUserSettings::GetDefaultResolutionScale(). This makes things less confusing (UGameUserSettings::GetRecommandedResolutionScale() returns scale recommended based on results of the benchmark and UGameUserSettings::GetDefaultResolutionScale() returns scale based on user settings) and fixes a regression introduced in 3257936 (OR-35544) #rb Cody.Haskell #tests Tested on PC Change 3283951 on 2017/02/02 by Daniel.Lamb@daniel.lamb_T3905_6612 Ensure DDC commandlet calls begincacheforcookedplatformdata correctly. #rb None #!codereview Matthew.Griffin #test DDC commandlet paragon. Change 3283874 on 2017/02/02 by Lina.Halper@Lina.Halper_Orion fix for invalid resource issue #rb: none #code review: Daniel.Wright #tests: compile and editor with wolf Change 3283621 on 2017/02/02 by Laurent.Delayen@laurent.delayen_Work2016_Orion Femme WIP whip aiming for Q ability. #rb none #tests Femme Change 3283216 on 2017/02/02 by jason.bestimt@Jason.Bestimt_Dev-General #ORION_MAIN - Merge 37.2 @ CL3282900#RB:none #Tests:none #!ROBOMERGE-SOURCE: CL 3283199 in //Orion/Main/... #!ROBOMERGE-BOT: ORION (Main -> Dev-General) Change 3282954 on 2017/02/02 by Lina.Halper@Lina.Halper_Orion It becomes invalid on the resource, so checking null, but still wip on verifying this with Daniel Wright. He's sick out. #rb:none #tests: compile #code review:Daniel.Wright #Jira: OR-35418 Change 3281993 on 2017/02/01 by Daniel.Lamb@daniel.lamb_T3905_6612 Removed default unattended flag. #rb Trivial #test PS4 cook run paragon. Change 3281990 on 2017/02/01 by Daniel.Lamb@daniel.lamb_T3905_6612 Potential fix for deterministic cooking issue with UMovieSceneSignedObjects. #rb Andrew.Grant #!codereview Max.Preussner #test Cook and run paragon ps4. Change 3281610 on 2017/02/01 by Laurent.Delayen@laurent.delayen_Work2016_Orion AimOffsetLookAt is now thread safe. #rb lina.halper #tests femme Change 3281609 on 2017/02/01 by Laurent.Delayen@laurent.delayen_Work2016_Orion Fixed 'Convert to AimOffset LookAt' option being broken in Persona. #rb lina.halper #tests works for Femme now. Change 3281019 on 2017/02/01 by Jason.Bestimt@ROBOMERGE_ORION_Dev_General #!ROBOMERGE-AUTHOR: jason.bestimt #ORION_MAIN - Merge 37.2 @ CL 3280498 #RB:none #Tests:none #!ROBOMERGE-SOURCE: CL 3281018 in //Orion/Main/... #!ROBOMERGE-BOT: ORION (Main -> Dev-General) Change 3280813 on 2017/02/01 by Jason.Bestimt@ROBOMERGE_ORION_Dev_General #!ROBOMERGE-AUTHOR: matthew.griffin Prevent inclusion of NotForLicensees files when staging CrashReportClient config files #rb none #tests none #!ROBOMERGE-SOURCE: CL 3280812 in //Orion/Main/... #!ROBOMERGE-BOT: ORION (Main -> Dev-General) Change 3279921 on 2017/01/31 by Yanni.Tripolitis@yanni.tripolitis_Dev_General_Cary Fixed an error in the Round MF, that was somehow "leaked" into Paragon from Odin. #lockdown Billy.Rivers, Adam.Bellefeuil #!codereview Tim.Elek Change 3279178 on 2017/01/31 by Daniel.Lamb@daniel.lamb_T3905_6612 Fixed up diff files commandlet stack information #rb Joe.Conley #test Diff cooked packages Change 3279084 on 2017/01/31 by Andrew.Grant@andrew.grant.T6730.orion.floating Merging //UE4/Main at 3276432 through Orion-Staging #rb #tests na Change 3279078 on 2017/01/31 by Jason.Bestimt@ROBOMERGE_ORION_Dev_General #!ROBOMERGE-AUTHOR: jason.bestimt #ORION_MAIN - Merge 37.2 @ CL 3279032 #RB:none #Tests:none #!ROBOMERGE-SOURCE: CL3279077in //Orion/Main/... #!ROBOMERGE-BOT: ORION (Main -> Dev-General) Change 3277908 on 2017/01/30 by Jason.Bestimt@ROBOMERGE_ORION_Dev_General #!ROBOMERGE-AUTHOR: jason.bestimt #ORION_37 - Fix for "-game" crash with missing meta data #RB:none #Tests:none [CodeReviewed]: andrew.grant, jamie.dale, mieszko.zielinski #!ROBOMERGE-SOURCE: CL 3277901 in //Orion/Release-37/... via CL 3277902 via CL 3277904 via CL 3277905 #!ROBOMERGE-BOT: ORION (Main -> Dev-General) Change 3277520 on 2017/01/30 by Andrew.Grant@andrew.grant.T6730.orion.floating Workaround for OR-35418 #!ROBOMERGE: Main #rb none #tests verified ShortSoloGame test completes without a crash Change 3277357 on 2017/01/30 by Daniel.Lamb@daniel.lamb_T3905_6612 Fixed the rebuild lighting commandlet. #rb Trivial #test Rebuild lighting dev general Change 3277322 on 2017/01/30 by Jason.Bestimt@ROBOMERGE_ORION_Dev_General #!ROBOMERGE-AUTHOR: jason.bestimt #ORION_MAIN - Merge 37.2 @ CL 3277275 #RB:none #Tests:none #!ROBOMERGE-SOURCE: CL 3277296 in //Orion/Main/... #!ROBOMERGE-BOT: ORION (Main -> Dev-General) Change 3277210 on 2017/01/30 by Jason.Bestimt@ROBOMERGE_ORION_Dev_General #!ROBOMERGE-AUTHOR: andrew.grant Non-shipping test changes: Fixed issue where with -stdout messages would be duplicated due to FeedbackContextAnsi echoing to stdout by default Changed stdout output to postfix instead of trail newlines Firstpass of finding and displaying crash callstacks in Orion Test Framework. #rb none #tests ran test framework with tests that purposefully crashed/checked #!ROBOMERGE-SOURCE: CL 3276889 in //Orion/Release-37/... via CL 3277207 via CL 3277208 via CL 3277209 #!ROBOMERGE-BOT: ORION (Main -> Dev-General) Change 3276774 on 2017/01/29 by Andrew.Grant@andrew.grant.T6730.orion.floating Fix for non-unity issue. #tests compiled #rb none #!ROBOMERGE: Main, DUI Change 3276594 on 2017/01/28 by Lina.Halper@Lina.Halper_Orion Checked in potential fix for nonunity build issue #rb:none #tests:compile Change 3275806 on 2017/01/27 by Ben.Salem@ben.salem_OrionMain Adding in a checkpointing system for automated test passes where, if a client crashes while running a pass, on reboot and reissue of the automation command the test pass will start off where it left off, skipping the crashing test. #rb clayton.langford #tests Ran several dozen test passses. Seriously. #!codereview steve.white, bob.ferreira, clayton.langford, adric.worley Change 3275803 on 2017/01/27 by Shaun.Kime@shaun.kime_RDU-WD-9788_oriondevgen Paragon has retainer widgets with no World set. When encountered, they can cause the scene list to be desynchronized with the rendering thread. This logic resolves the issue by registering a null scene in this case, properly setting the slate scene index for subsequent slate draw calls. #rb nick.darnell #jira OR-34919 #TESTS na Change 3275533 on 2017/01/27 by Max.Chen@Max.Chen_T4664_Orion_Main Sequencer: Switch to static pointer to fix crash when tearing down curve editor. #jira UE-40796 #rb andrew.rodham #tests none Change 3275093 on 2017/01/27 by Jason.Bestimt@ROBOMERGE_ORION_Dev_General #!ROBOMERGE-AUTHOR: jason.bestimt #ORION_MAIN - Merge 37.2 @ CL 3273298 #RB:none #Tests:none #!ROBOMERGE-SOURCE: CL 3273417 in //Orion/Main/... #!ROBOMERGE-BOT: ORION (Main -> Dev-General) Change 3274700 on 2017/01/26 by Lina.Halper@Lina.Halper_Orion #Anim curve crash on cooking - fixed crash during cooking while accessing default value of material - this code doesn't have to run during cooking with inactive world, so I'm checking that #code review: Daniel.Wright, Chris.Bunner, Jurre.DeBaare #rb: none #tests: cooking Change 3274129 on 2017/01/26 by Lina.Halper@Lina.Halper_Orion Fixed safer to get featurelevel #rb: Daniel.Wright #tests: compile/wolf Change 3274012 on 2017/01/26 by Lukasz.Furman@Lukasz.Furman_T7320_OrionStream fixed crash in navigation grids #jira OR-35356 #rb none #tests PIE Change 3273803 on 2017/01/26 by Lina.Halper@Lina.Halper_Orion Fixed issue with animation curve getting reset to 0.f - the issue is that skeleton contains material flag types, so now it just keeps setting the value - even after I fix validation check, it still cleared it due to the material curve not found anymore, so added to support default value setting #jira: OR-34563 #rb: Martin.Wilson, Chris.Bunner, Benn.Gallagher #code review: Martin.Wilson, Daniel.Wright #tests: wolf, coil Change3273257on 2017/01/26 by Alexis.Matte@amatte-orion-dev-general Isolate by material slot instead of section index. Add UI to isolate and highlight material in the material panel #rb matt.kuhlenschmidt #jira UE-41131 #tests none Change 3272527 on 2017/01/25 by Jason.Bestimt@ROBOMERGE_ORION_Dev_General #!ROBOMERGE-AUTHOR: chris.bunner Ensure FSceneRenderTargets snapshot copies default clear colors. #tests Golden path on lowest and high settings #rb None #lockdown Jason.Bestimt #jira OR-34905 #!ROBOMERGE-SOURCE: CL 3272507 in //Orion/Release-37.1/... via CL 3272521 via CL 3272525 #!ROBOMERGE-BOT: ORION (Main -> Dev-General) Change 3272244 on 2017/01/25 by Rolando.Caloca@rolando.caloca_T3903_OrionMainS Show more info when a material instance failed to compile #jira OR-34626 #tests Forced crash in the debugger #rb Daniel.Wright Change 3272109 on 2017/01/25 by Jason.Bestimt@ROBOMERGE_ORION_Dev_General #!ROBOMERGE-AUTHOR: philip.buuck Fix bad merge from Main #rb Dan.Hertzka #tests PIE [CodeReviewed] Andrew.Grant #lockdown Andrew.Grant #!ROBOMERGE-SOURCE: CL 3272106 in //Orion/Release-37.1/... via CL 3272107 via CL 3272108 #!ROBOMERGE-BOT: ORION (Main -> Dev-General) Change 3271721 on 2017/01/25 by Lukasz.Furman@Lukasz.Furman_T7320_OrionStream jungle minions will spawn navigation obstacles when they are stuck in static geometry, fixed issues with falling off cliffs #jira OR-35054 #rb Mieszko.Zielinski #tests PIE Change 3271432 on 2017/01/25 by Jason.Bestimt@ROBOMERGE_ORION_Dev_General #!ROBOMERGE-AUTHOR: jason.bestimt #ORION_MAIN - Merge 37.2 @ CL 3271043 #RB:none #Tests:none #!ROBOMERGE-SOURCE: CL 3271429 in //Orion/Main/... #!ROBOMERGE-BOT: ORION (Main -> Dev-General) [CL 3322856 by Andrew Grant in Main branch]
1206 lines
40 KiB
C++
1206 lines
40 KiB
C++
// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "CoreMinimal.h"
|
|
#include "HAL/FileManager.h"
|
|
#include "Misc/CommandLine.h"
|
|
#include "Misc/Paths.h"
|
|
#include "Misc/ConfigCacheIni.h"
|
|
#include "Misc/AutomationTest.h"
|
|
#include "Misc/App.h"
|
|
#include "Interfaces/IAutomationReport.h"
|
|
#include "AutomationWorkerMessages.h"
|
|
#include "IMessageContext.h"
|
|
#include "Helpers/MessageEndpoint.h"
|
|
#include "Modules/ModuleManager.h"
|
|
#include "Helpers/MessageEndpointBuilder.h"
|
|
#include "AssetEditorMessages.h"
|
|
#include "ImageComparer.h"
|
|
#include "AutomationControllerManager.h"
|
|
#include "Interfaces/IScreenShotToolsModule.h"
|
|
#include "Serialization/JsonSerializer.h"
|
|
#include "JsonObjectConverter.h"
|
|
#include "Misc/EngineVersion.h"
|
|
#include "Misc/FileHelper.h"
|
|
#include "PlatformHttp.h"
|
|
|
|
#if WITH_EDITOR
|
|
#include "Logging/MessageLog.h"
|
|
#endif
|
|
|
|
namespace AutomationControllerConstants
|
|
{
|
|
const FString HistoryConfigSectionName = TEXT("AutomationController.History");
|
|
}
|
|
|
|
FAutomationControllerManager::FAutomationControllerManager()
|
|
{
|
|
FParse::Value(FCommandLine::Get(), TEXT("ReportOutputPath="), ReportOutputPathOverride, false);
|
|
CheckpointFile = nullptr;
|
|
}
|
|
|
|
void FAutomationControllerManager::RequestAvailableWorkers(const FGuid& SessionId)
|
|
{
|
|
//invalidate previous tests
|
|
++ExecutionCount;
|
|
DeviceClusterManager.Reset();
|
|
|
|
ControllerResetDelegate.Broadcast();
|
|
|
|
// Don't allow reports to be exported
|
|
bTestResultsAvailable = false;
|
|
|
|
//store off active session ID to reject messages that come in from different sessions
|
|
ActiveSessionId = SessionId;
|
|
|
|
//TODO AUTOMATION - include change list, game, etc, or remove when launcher is integrated
|
|
int32 ChangelistNumber = 10000;
|
|
FString ProcessName = TEXT("instance_name");
|
|
|
|
MessageEndpoint->Publish(new FAutomationWorkerFindWorkers(ChangelistNumber, FApp::GetGameName(), ProcessName, SessionId), EMessageScope::Network);
|
|
|
|
// Reset the check test timers
|
|
LastTimeUpdateTicked = FPlatformTime::Seconds();
|
|
CheckTestTimer = 0.f;
|
|
|
|
IScreenShotToolsModule& ScreenShotModule = FModuleManager::LoadModuleChecked<IScreenShotToolsModule>("ScreenShotComparisonTools");
|
|
ScreenshotManager = ScreenShotModule.GetScreenShotManager();
|
|
}
|
|
|
|
void FAutomationControllerManager::RequestTests()
|
|
{
|
|
//invalidate incoming results
|
|
ExecutionCount++;
|
|
//reset the number of responses we have received
|
|
RefreshTestResponses = 0;
|
|
|
|
ReportManager.Empty();
|
|
|
|
for ( int32 ClusterIndex = 0; ClusterIndex < DeviceClusterManager.GetNumClusters(); ++ClusterIndex )
|
|
{
|
|
int32 DevicesInCluster = DeviceClusterManager.GetNumDevicesInCluster(ClusterIndex);
|
|
if ( DevicesInCluster > 0 )
|
|
{
|
|
FMessageAddress MessageAddress = DeviceClusterManager.GetDeviceMessageAddress(ClusterIndex, 0);
|
|
|
|
ResetIntermediateTestData();
|
|
|
|
//issue tests on appropriate platforms
|
|
MessageEndpoint->Send(new FAutomationWorkerRequestTests(bDeveloperDirectoryIncluded, RequestedTestFlags), MessageAddress);
|
|
}
|
|
}
|
|
}
|
|
|
|
void FAutomationControllerManager::RunTests(const bool bInIsLocalSession)
|
|
{
|
|
ExecutionCount++;
|
|
CurrentTestPass = 0;
|
|
ReportManager.SetCurrentTestPass(CurrentTestPass);
|
|
ClusterDistributionMask = 0;
|
|
bTestResultsAvailable = false;
|
|
TestRunningArray.Empty();
|
|
bIsLocalSession = bInIsLocalSession;
|
|
|
|
// Reset the check test timers
|
|
LastTimeUpdateTicked = FPlatformTime::Seconds();
|
|
CheckTestTimer = 0.f;
|
|
|
|
#if WITH_EDITOR
|
|
FMessageLog AutomationTestingLog("AutomationTestingLog");
|
|
FString NewPageName = FString::Printf(TEXT("-----Test Run %d----"), ExecutionCount);
|
|
FText NewPageNameText = FText::FromString(*NewPageName);
|
|
AutomationTestingLog.Open();
|
|
AutomationTestingLog.NewPage(NewPageNameText);
|
|
AutomationTestingLog.Info(NewPageNameText);
|
|
#endif
|
|
//reset all tests
|
|
ReportManager.ResetForExecution(NumTestPasses);
|
|
|
|
for ( int32 ClusterIndex = 0; ClusterIndex < DeviceClusterManager.GetNumClusters(); ++ClusterIndex )
|
|
{
|
|
//enable each device cluster
|
|
ClusterDistributionMask |= ( 1 << ClusterIndex );
|
|
|
|
//for each device in this cluster
|
|
for ( int32 DeviceIndex = 0; DeviceIndex < DeviceClusterManager.GetNumDevicesInCluster(ClusterIndex); ++DeviceIndex )
|
|
{
|
|
//mark the device as idle
|
|
DeviceClusterManager.SetTest(ClusterIndex, DeviceIndex, NULL);
|
|
|
|
// Send command to reset tests (delete local files, etc)
|
|
FMessageAddress MessageAddress = DeviceClusterManager.GetDeviceMessageAddress(ClusterIndex, DeviceIndex);
|
|
MessageEndpoint->Send(new FAutomationWorkerResetTests(), MessageAddress);
|
|
}
|
|
}
|
|
|
|
// Inform the UI we are running tests
|
|
if ( ClusterDistributionMask != 0 )
|
|
{
|
|
SetControllerStatus(EAutomationControllerModuleState::Running);
|
|
}
|
|
}
|
|
|
|
void FAutomationControllerManager::StopTests()
|
|
{
|
|
bTestResultsAvailable = false;
|
|
ClusterDistributionMask = 0;
|
|
|
|
ReportManager.StopRunningTests();
|
|
|
|
// Inform the UI we have stopped running tests
|
|
if ( DeviceClusterManager.HasActiveDevice() )
|
|
{
|
|
SetControllerStatus(EAutomationControllerModuleState::Ready);
|
|
}
|
|
else
|
|
{
|
|
SetControllerStatus(EAutomationControllerModuleState::Disabled);
|
|
}
|
|
|
|
TestRunningArray.Empty();
|
|
}
|
|
|
|
void FAutomationControllerManager::Init()
|
|
{
|
|
extern void EmptyLinkFunctionForStaticInitializationAutomationExecCmd();
|
|
EmptyLinkFunctionForStaticInitializationAutomationExecCmd();
|
|
|
|
AutomationTestState = EAutomationControllerModuleState::Disabled;
|
|
bTestResultsAvailable = false;
|
|
bScreenshotsEnabled = true;
|
|
bSendAnalytics = FParse::Param(FCommandLine::Get(), TEXT("SendAutomationAnalytics"));
|
|
|
|
// Update the ini with the settings
|
|
bTrackHistory = false;
|
|
GConfig->GetBool(*AutomationControllerConstants::HistoryConfigSectionName, TEXT("bTrackHistory"), bTrackHistory, GEngineIni);
|
|
|
|
// Default num of items to track
|
|
NumberOfHistoryItemsTracked = 5;
|
|
GConfig->GetInt(*AutomationControllerConstants::HistoryConfigSectionName, TEXT("NumberOfHistoryItemsTracked"), NumberOfHistoryItemsTracked, GEngineIni);
|
|
}
|
|
|
|
void FAutomationControllerManager::RequestLoadAsset(const FString& InAssetName)
|
|
{
|
|
MessageEndpoint->Publish(new FAssetEditorRequestOpenAsset(InAssetName), EMessageScope::Process);
|
|
}
|
|
|
|
void FAutomationControllerManager::Tick()
|
|
{
|
|
ProcessAvailableTasks();
|
|
ProcessComparisonQueue();
|
|
}
|
|
|
|
void FAutomationControllerManager::ProcessComparisonQueue()
|
|
{
|
|
TSharedPtr<FComparisonEntry> Entry;
|
|
if ( ComparisonQueue.Peek(Entry) )
|
|
{
|
|
if ( Entry->PendingComparison.IsReady() )
|
|
{
|
|
const bool Dequeued = ComparisonQueue.Dequeue(Entry);
|
|
check(Dequeued);
|
|
|
|
FImageComparisonResult Result = Entry->PendingComparison.Get();
|
|
|
|
const bool bIsNew = Result.IsNew();
|
|
const bool bAreSimilar = Result.AreSimilar();
|
|
|
|
// Issue tests on appropriate platforms
|
|
MessageEndpoint->Send(new FAutomationWorkerImageComparisonResults(bIsNew, bAreSimilar), Entry->Sender);
|
|
|
|
// Record the metadata for the test that needed the screenshots compared.
|
|
for ( int32 Index = 0; Index < TestRunningArray.Num(); Index++ )
|
|
{
|
|
// Find the game session instance info
|
|
int32 ClusterIndex;
|
|
int32 DeviceIndex;
|
|
verify(DeviceClusterManager.FindDevice(Entry->Sender, ClusterIndex, DeviceIndex));
|
|
|
|
TSharedPtr<IAutomationReport> Report = DeviceClusterManager.GetTest(ClusterIndex, DeviceIndex);
|
|
check(Report.IsValid());
|
|
|
|
FString ApprovedFolder = ScreenshotManager->GetLocalApprovedFolder();
|
|
FString UnapprovedFolder = ScreenshotManager->GetLocalUnapprovedFolder();
|
|
FString ComparisonFolder = ScreenshotManager->GetLocalComparisonFolder();
|
|
|
|
TArray<FString> Files;
|
|
Files.Add(ApprovedFolder / Result.ApprovedFile);
|
|
Files.Add(UnapprovedFolder / Result.IncomingFile);
|
|
Files.Add(ComparisonFolder / Result.ComparisonFile);
|
|
|
|
Report->AddArtifact(ClusterIndex, CurrentTestPass, FAutomationArtifact(Entry->Name, EAutomationArtifactType::Comparison, Files));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void FAutomationControllerManager::ProcessAvailableTasks()
|
|
{
|
|
// Distribute tasks
|
|
if ( ClusterDistributionMask != 0 )
|
|
{
|
|
// For each device cluster
|
|
for ( int32 ClusterIndex = 0; ClusterIndex < DeviceClusterManager.GetNumClusters(); ++ClusterIndex )
|
|
{
|
|
bool bAllTestsComplete = true;
|
|
|
|
// If any of the devices were valid
|
|
if ( ( ClusterDistributionMask & ( 1 << ClusterIndex ) ) && DeviceClusterManager.GetNumDevicesInCluster(ClusterIndex) > 0 )
|
|
{
|
|
ExecuteNextTask(ClusterIndex, bAllTestsComplete);
|
|
}
|
|
|
|
//if we're all done running our tests
|
|
if ( bAllTestsComplete )
|
|
{
|
|
//we don't need to test this cluster anymore
|
|
ClusterDistributionMask &= ~( 1 << ClusterIndex );
|
|
|
|
if ( ClusterDistributionMask == 0 )
|
|
{
|
|
ProcessResults();
|
|
//Notify the graphical layout we are done processing results.
|
|
TestsCompleteDelegate.Broadcast();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( bIsLocalSession == false )
|
|
{
|
|
// Update the test status for timeouts if this is not a local session
|
|
UpdateTests();
|
|
}
|
|
}
|
|
|
|
void FAutomationControllerManager::ReportTestResults()
|
|
{
|
|
GLog->Logf(TEXT("Test Pass Results:"));
|
|
for ( int32 i = 0; i < OurPassResults.TestInformation.Num(); i++ )
|
|
{
|
|
GLog->Logf(TEXT("%s: %s"), *OurPassResults.TestInformation[i].TestDisplayName, ToString(OurPassResults.TestInformation[i].State));
|
|
}
|
|
}
|
|
|
|
void FAutomationControllerManager::CollectTestResults(TSharedPtr<IAutomationReport> Report, const FAutomationTestResults& Results)
|
|
{
|
|
// TODO This is slow, change to a map.
|
|
for ( int32 i = 0; i < OurPassResults.TestInformation.Num(); i++ )
|
|
{
|
|
FAutomatedTestResult& ReportResult = OurPassResults.TestInformation[i];
|
|
if ( ReportResult.FullTestPath == Report->GetFullTestPath() )
|
|
{
|
|
ReportResult.Logs = Results.Logs;
|
|
ReportResult.Warnings = Results.Warnings;
|
|
for ( int j = 0; j < Results.Errors.Num(); j++ )
|
|
{
|
|
ReportResult.Errors.Add(Results.Errors[j].Message);
|
|
}
|
|
|
|
ReportResult.State = Results.State;
|
|
ReportResult.Artifacts = Results.Artifacts;
|
|
|
|
switch ( Results.State )
|
|
{
|
|
case EAutomationState::Success:
|
|
OurPassResults.NumSucceeded++;
|
|
break;
|
|
case EAutomationState::Fail:
|
|
OurPassResults.NumFailed++;
|
|
break;
|
|
default:
|
|
OurPassResults.NumNotRun++;
|
|
break;
|
|
}
|
|
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
void FAutomationControllerManager::GenerateJsonTestPassSummary(FDateTime Timestamp)
|
|
{
|
|
if (!OurPassResults.TestInformation.Num())
|
|
{
|
|
return;
|
|
}
|
|
|
|
const FAutomatedTestPassResults SerializedPassResults = OurPassResults;
|
|
TSharedPtr<FJsonObject> ReportJson = FJsonObjectConverter::UStructToJsonObject(SerializedPassResults);
|
|
if (ReportJson.IsValid())
|
|
{
|
|
FString ReportOutputPath = GetReportPath(Timestamp);
|
|
|
|
FString ReportFileName = FString::Printf(TEXT("%s/index.json"), *ReportOutputPath);
|
|
FArchive* ReportFileWriter = IFileManager::Get().CreateFileWriter(*ReportFileName);
|
|
if (ReportFileWriter != nullptr)
|
|
{
|
|
TSharedRef<TJsonWriter<> > JsonWriter = TJsonWriterFactory<>::Create(ReportFileWriter, 0);
|
|
FJsonSerializer::Serialize(ReportJson.ToSharedRef(), JsonWriter);
|
|
|
|
delete ReportFileWriter;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
GLog->Logf(ELogVerbosity::Error, TEXT("Test Report Json is invalid - report not generated."));
|
|
}
|
|
}
|
|
|
|
void FAutomationControllerManager::GenerateHtmlTestPassSummary(FDateTime Timestamp)
|
|
{
|
|
if ( !OurPassResults.TestInformation.Num() )
|
|
{
|
|
return;
|
|
}
|
|
|
|
FString ReportOutputPath = GetReportPath(Timestamp);
|
|
FScreenshotExportResults ExportResults = ScreenshotManager->ExportComparisonResultsAsync(ReportOutputPath).Get();
|
|
|
|
FAutomatedTestPassResults SerializedPassResults = OurPassResults;
|
|
SerializedPassResults.TestInformation.StableSort([] (const FAutomatedTestResult& A, const FAutomatedTestResult& B) {
|
|
if ( A.Errors.Num() > 0 )
|
|
{
|
|
if ( B.Errors.Num() > 0 )
|
|
return ( A.TestDisplayName < B.TestDisplayName );
|
|
else
|
|
return true;
|
|
}
|
|
else if ( B.Errors.Num() > 0 )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if ( A.Warnings.Num() > 0 )
|
|
{
|
|
if ( B.Warnings.Num() > 0 )
|
|
return ( A.TestDisplayName < B.TestDisplayName );
|
|
else
|
|
return true;
|
|
}
|
|
else if ( B.Warnings.Num() > 0 )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return A.TestDisplayName < B.TestDisplayName;
|
|
});
|
|
|
|
FString MasterTemplate, ResultTemplate, LogTemplate, ArtifactCompareTemplate, ArtifactImageTemplate;
|
|
const bool bLoadedMaster = FFileHelper::LoadFileToString(MasterTemplate, *( FPaths::EngineContentDir() / TEXT("Automation/Report-Master-Template.html") ));
|
|
const bool bLoadedResult = FFileHelper::LoadFileToString(ResultTemplate, *( FPaths::EngineContentDir() / TEXT("Automation/Report-Result-Template.html") ));
|
|
const bool bLoadedLog = FFileHelper::LoadFileToString(LogTemplate, *( FPaths::EngineContentDir() / TEXT("Automation/Report-Log-Template.html") ));
|
|
const bool bLoadedCompareArtifact = FFileHelper::LoadFileToString(ArtifactCompareTemplate, *( FPaths::EngineContentDir() / TEXT("Automation/Report-Artifact-Compare-Template.html") ));
|
|
const bool bLoadedImageArtifact = FFileHelper::LoadFileToString(ArtifactImageTemplate, *( FPaths::EngineContentDir() / TEXT("Automation/Report-Artifact-Image-Template.html") ));
|
|
check(bLoadedMaster && bLoadedResult && bLoadedLog && bLoadedCompareArtifact && bLoadedImageArtifact);
|
|
|
|
FString ReportState = TEXT("success");
|
|
FString ReportIcon = TEXT("heartbeat");
|
|
if ( SerializedPassResults.TestInformation.Num() > 0 )
|
|
{
|
|
const FAutomatedTestResult& FirstTest = SerializedPassResults.TestInformation[0];
|
|
if ( FirstTest.Errors.Num() > 0 )
|
|
{
|
|
ReportState = TEXT("error");
|
|
ReportIcon = TEXT("bomb");
|
|
}
|
|
else if ( FirstTest.Warnings.Num() > 0 )
|
|
{
|
|
ReportState = TEXT("warning");
|
|
ReportIcon = TEXT("exclamation-triangle");
|
|
}
|
|
}
|
|
|
|
FString HtmlResults;
|
|
for ( const FAutomatedTestResult& Test : SerializedPassResults.TestInformation )
|
|
{
|
|
FString TestState = Test.Errors.Num() > 0 ? TEXT("error") : Test.Warnings.Num() > 0 ? TEXT("warning") : TEXT("success");
|
|
|
|
FString Logs = TEXT("");
|
|
|
|
for ( const FString& LogItem : Test.Errors )
|
|
{
|
|
TMap<FString, FStringFormatArg> Args;
|
|
Args.Add(TEXT("Statement"), FPlatformHttp::HtmlEncode(LogItem));
|
|
Logs += FString::Format(*LogTemplate, Args);
|
|
}
|
|
|
|
for ( const FString& LogItem : Test.Warnings )
|
|
{
|
|
TMap<FString, FStringFormatArg> Args;
|
|
Args.Add(TEXT("Statement"), FPlatformHttp::HtmlEncode(LogItem));
|
|
Logs += FString::Format(*LogTemplate, Args);
|
|
}
|
|
|
|
for ( const FString& LogItem : Test.Logs )
|
|
{
|
|
TMap<FString, FStringFormatArg> Args;
|
|
Args.Add(TEXT("Statement"), FPlatformHttp::HtmlEncode(LogItem));
|
|
Logs += FString::Format(*LogTemplate, Args);
|
|
}
|
|
|
|
for ( const FAutomationArtifact& Artifact : Test.Artifacts )
|
|
{
|
|
if ( Artifact.Type == EAutomationArtifactType::Comparison )
|
|
{
|
|
TMap<FString, FStringFormatArg> Args;
|
|
Args.Add(TEXT("Name"), FPlatformHttp::HtmlEncode(Artifact.Name));
|
|
Args.Add(TEXT("Approved"), CopyArtifact(ReportOutputPath, Artifact.FilePaths[0]));
|
|
Args.Add(TEXT("Unapproved"), CopyArtifact(ReportOutputPath, Artifact.FilePaths[1]));
|
|
Args.Add(TEXT("Difference"), CopyArtifact(ReportOutputPath, Artifact.FilePaths[2]));
|
|
|
|
Logs += FString::Format(*ArtifactCompareTemplate, Args);
|
|
}
|
|
else if ( Artifact.Type == EAutomationArtifactType::Image )
|
|
{
|
|
TMap<FString, FStringFormatArg> Args;
|
|
Args.Add(TEXT("Name"), FPlatformHttp::HtmlEncode(Artifact.Name));
|
|
Args.Add(TEXT("File"), CopyArtifact(ReportOutputPath, Artifact.FilePaths[0]));
|
|
|
|
Logs += FString::Format(*ArtifactCompareTemplate, Args);
|
|
}
|
|
else
|
|
{
|
|
check(false);
|
|
}
|
|
}
|
|
|
|
{
|
|
TMap<FString, FStringFormatArg> Args;
|
|
Args.Add(TEXT("TestState"), TestState);
|
|
Args.Add(TEXT("TestName"), Test.TestDisplayName);
|
|
Args.Add(TEXT("TestPath"), Test.FullTestPath);
|
|
Args.Add(TEXT("Logs"), Logs);
|
|
|
|
HtmlResults += FString::Format(*ResultTemplate, Args);
|
|
}
|
|
}
|
|
|
|
{
|
|
TMap<FString, FStringFormatArg> Args;
|
|
Args.Add(TEXT("Title"), TEXT("Automation Test Results"));
|
|
Args.Add(TEXT("ReportState"), ReportState);
|
|
Args.Add(TEXT("ReportIcon"), ReportIcon);
|
|
Args.Add(TEXT("ComparisonExportDirectory"), ExportResults.ExportPath);
|
|
Args.Add(TEXT("Results"), HtmlResults);
|
|
|
|
FString Html = FString::Format(*MasterTemplate, Args);
|
|
|
|
FString ReportFileName = FString::Printf(TEXT("%s/index.html"), *ReportOutputPath);
|
|
if ( !FFileHelper::SaveStringToFile(Html, *ReportFileName, FFileHelper::EEncodingOptions::ForceUTF8) )
|
|
{
|
|
GLog->Logf(ELogVerbosity::Error, TEXT("Test Report Html is invalid - report not generated."));
|
|
}
|
|
}
|
|
}
|
|
|
|
FString FAutomationControllerManager::CopyArtifact(const FString& DestFolder, const FString& SourceFile) const
|
|
{
|
|
FString AritfactDirectory = FString::Printf(TEXT("ReportArtifacts-%d"), FEngineVersion::Current().GetChangelist());
|
|
|
|
FString ArtifactFile = AritfactDirectory / FGuid::NewGuid().ToString(EGuidFormats::Digits) + FPaths::GetExtension(SourceFile, true);
|
|
FString ArtifactDestination = DestFolder / ArtifactFile;
|
|
IFileManager::Get().Copy(*ArtifactDestination, *SourceFile, true, true);
|
|
|
|
return ArtifactFile;
|
|
}
|
|
|
|
FString FAutomationControllerManager::GetReportPath(FDateTime Timestamp) const
|
|
{
|
|
return ReportOutputPathOverride.IsEmpty() ? FString::Printf(TEXT("%s/Report-%d-%s"), *FPaths::AutomationLogDir(), FEngineVersion::Current().GetChangelist(), *Timestamp.ToString()) : ReportOutputPathOverride;
|
|
}
|
|
|
|
void FAutomationControllerManager::ExecuteNextTask( int32 ClusterIndex, OUT bool& bAllTestsCompleted )
|
|
{
|
|
bool bTestThatRequiresMultiplePraticipantsHadEnoughParticipants = false;
|
|
TArray< IAutomationReportPtr > TestsRunThisPass;
|
|
|
|
// For each device in this cluster
|
|
int32 NumDevicesInCluster = DeviceClusterManager.GetNumDevicesInCluster( ClusterIndex );
|
|
for ( int32 DeviceIndex = 0; DeviceIndex < NumDevicesInCluster; ++DeviceIndex )
|
|
{
|
|
// If this device is idle
|
|
if ( !DeviceClusterManager.GetTest(ClusterIndex, DeviceIndex).IsValid() && DeviceClusterManager.DeviceEnabled(ClusterIndex, DeviceIndex) )
|
|
{
|
|
// Get the next test that should be worked on
|
|
TSharedPtr< IAutomationReport > NextTest = ReportManager.GetNextReportToExecute(bAllTestsCompleted, ClusterIndex, CurrentTestPass, NumDevicesInCluster);
|
|
if ( NextTest.IsValid() )
|
|
{
|
|
// Get the status of the test
|
|
EAutomationState TestState = NextTest->GetState(ClusterIndex, CurrentTestPass);
|
|
if ( TestState == EAutomationState::NotRun )
|
|
{
|
|
// Reserve this device for the test
|
|
DeviceClusterManager.SetTest(ClusterIndex, DeviceIndex, NextTest);
|
|
TestsRunThisPass.Add(NextTest);
|
|
|
|
// Register this as a test we'll need to report on.
|
|
FAutomatedTestResult tempresult;
|
|
tempresult.Test = NextTest;
|
|
tempresult.TestDisplayName = NextTest->GetDisplayName();
|
|
tempresult.FullTestPath = NextTest->GetFullTestPath();
|
|
|
|
OurPassResults.TestInformation.Add(tempresult);
|
|
|
|
// If we now have enough devices reserved for the test, run it!
|
|
TArray<FMessageAddress> DeviceAddresses = DeviceClusterManager.GetDevicesReservedForTest(ClusterIndex, NextTest);
|
|
if ( DeviceAddresses.Num() == NextTest->GetNumParticipantsRequired() )
|
|
{
|
|
// Send it to each device
|
|
for ( int32 AddressIndex = 0; AddressIndex < DeviceAddresses.Num(); ++AddressIndex )
|
|
{
|
|
FAutomationTestResults TestResults;
|
|
|
|
GLog->Logf(ELogVerbosity::Display, TEXT("Running Automation: '%s' (Class Name: '%s')"), *TestsRunThisPass[AddressIndex]->GetFullTestPath(), *TestsRunThisPass[AddressIndex]->GetCommand());
|
|
TestResults.State = EAutomationState::InProcess;
|
|
|
|
if (CheckpointFile)
|
|
{
|
|
WriteLineToCheckpointFile(NextTest->GetFullTestPath());
|
|
}
|
|
|
|
TestResults.GameInstance = DeviceClusterManager.GetClusterDeviceName(ClusterIndex, DeviceIndex);
|
|
NextTest->SetResults(ClusterIndex, CurrentTestPass, TestResults);
|
|
NextTest->ResetNetworkCommandResponses();
|
|
|
|
// Mark the device as busy
|
|
FMessageAddress DeviceAddress = DeviceAddresses[AddressIndex];
|
|
|
|
// Send the test to the device for execution!
|
|
MessageEndpoint->Send(new FAutomationWorkerRunTests(ExecutionCount, AddressIndex, NextTest->GetCommand(), NextTest->GetDisplayName(), bScreenshotsEnabled, bSendAnalytics), DeviceAddress);
|
|
|
|
// Add a test so we can check later if the device is still active
|
|
TestRunningArray.Add(FTestRunningInfo(DeviceAddress));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// At least one device is still working
|
|
bAllTestsCompleted = false;
|
|
}
|
|
}
|
|
|
|
// Ensure any tests we have attempted to run on this pass had enough participants to successfully run.
|
|
for ( int32 TestIndex = 0; TestIndex < TestsRunThisPass.Num(); TestIndex++ )
|
|
{
|
|
IAutomationReportPtr CurrentTest = TestsRunThisPass[TestIndex];
|
|
|
|
if ( CurrentTest->GetNumDevicesRunningTest() != CurrentTest->GetNumParticipantsRequired() )
|
|
{
|
|
if ( GetNumDevicesInCluster(ClusterIndex) < CurrentTest->GetNumParticipantsRequired() )
|
|
{
|
|
float EmptyDuration = 0.0f;
|
|
TArray<FString> EmptyStringArray;
|
|
TArray<FString> AutomationsWarnings;
|
|
AutomationsWarnings.Add(FString::Printf(TEXT("Needed %d devices to participate, Only had %d available."), CurrentTest->GetNumParticipantsRequired(), DeviceClusterManager.GetNumDevicesInCluster(ClusterIndex)));
|
|
|
|
FAutomationTestResults TestResults;
|
|
TestResults.State = EAutomationState::NotEnoughParticipants;
|
|
TestResults.GameInstance = DeviceClusterManager.GetClusterDeviceName(ClusterIndex, 0);
|
|
TestResults.Warnings.Append(AutomationsWarnings);
|
|
|
|
CurrentTest->SetResults(ClusterIndex, CurrentTestPass, TestResults);
|
|
DeviceClusterManager.ResetAllDevicesRunningTest(ClusterIndex, CurrentTest);
|
|
}
|
|
}
|
|
}
|
|
|
|
//Check to see if we finished a pass
|
|
if ( bAllTestsCompleted && CurrentTestPass < NumTestPasses - 1 )
|
|
{
|
|
CurrentTestPass++;
|
|
ReportManager.SetCurrentTestPass(CurrentTestPass);
|
|
bAllTestsCompleted = false;
|
|
}
|
|
}
|
|
|
|
|
|
void FAutomationControllerManager::Startup()
|
|
{
|
|
MessageEndpoint = FMessageEndpoint::Builder("FAutomationControllerModule")
|
|
.Handling<FAutomationWorkerFindWorkersResponse>(this, &FAutomationControllerManager::HandleFindWorkersResponseMessage)
|
|
.Handling<FAutomationWorkerPong>(this, &FAutomationControllerManager::HandlePongMessage)
|
|
.Handling<FAutomationWorkerRequestNextNetworkCommand>(this, &FAutomationControllerManager::HandleRequestNextNetworkCommandMessage)
|
|
.Handling<FAutomationWorkerRequestTestsReply>(this, &FAutomationControllerManager::HandleRequestTestsReplyMessage)
|
|
.Handling<FAutomationWorkerRequestTestsReplyComplete>(this, &FAutomationControllerManager::HandleRequestTestsReplyCompleteMessage)
|
|
.Handling<FAutomationWorkerRunTestsReply>(this, &FAutomationControllerManager::HandleRunTestsReplyMessage)
|
|
.Handling<FAutomationWorkerScreenImage>(this, &FAutomationControllerManager::HandleReceivedScreenShot)
|
|
.Handling<FAutomationWorkerWorkerOffline>(this, &FAutomationControllerManager::HandleWorkerOfflineMessage);
|
|
|
|
if ( MessageEndpoint.IsValid() )
|
|
{
|
|
MessageEndpoint->Subscribe<FAutomationWorkerWorkerOffline>();
|
|
}
|
|
|
|
ClusterDistributionMask = 0;
|
|
ExecutionCount = 0;
|
|
bDeveloperDirectoryIncluded = false;
|
|
RequestedTestFlags = EAutomationTestFlags::SmokeFilter | EAutomationTestFlags::EngineFilter | EAutomationTestFlags::ProductFilter | EAutomationTestFlags::PerfFilter;
|
|
|
|
NumOfTestsToReceive = 0;
|
|
NumTestPasses = 1;
|
|
|
|
//Default to machine name
|
|
DeviceGroupFlags = 0;
|
|
ToggleDeviceGroupFlag(EAutomationDeviceGroupTypes::MachineName);
|
|
}
|
|
|
|
void FAutomationControllerManager::Shutdown()
|
|
{
|
|
MessageEndpoint.Reset();
|
|
ShutdownDelegate.Broadcast();
|
|
RemoveCallbacks();
|
|
}
|
|
|
|
void FAutomationControllerManager::RemoveCallbacks()
|
|
{
|
|
ShutdownDelegate.Clear();
|
|
TestsAvailableDelegate.Clear();
|
|
TestsRefreshedDelegate.Clear();
|
|
TestsCompleteDelegate.Clear();
|
|
}
|
|
|
|
void FAutomationControllerManager::SetTestNames(const FMessageAddress& AutomationWorkerAddress)
|
|
{
|
|
int32 DeviceClusterIndex = INDEX_NONE;
|
|
int32 DeviceIndex = INDEX_NONE;
|
|
|
|
// Find the device that requested these tests
|
|
if ( DeviceClusterManager.FindDevice(AutomationWorkerAddress, DeviceClusterIndex, DeviceIndex) )
|
|
{
|
|
// Sort tests by display name
|
|
struct FCompareAutomationTestInfo
|
|
{
|
|
FORCEINLINE bool operator()(const FAutomationTestInfo& A, const FAutomationTestInfo& B) const
|
|
{
|
|
return A.GetDisplayName() < B.GetDisplayName();
|
|
}
|
|
};
|
|
|
|
TestInfo.Sort(FCompareAutomationTestInfo());
|
|
|
|
// Add each test to the collection
|
|
for ( int32 TestIndex = 0; TestIndex < TestInfo.Num(); ++TestIndex )
|
|
{
|
|
// Ensure our test exists. If not, add it
|
|
ReportManager.EnsureReportExists(TestInfo[TestIndex], DeviceClusterIndex, NumTestPasses);
|
|
}
|
|
|
|
// Clear any intermediate data we had associated with the tests whilst building the full list of tests
|
|
ResetIntermediateTestData();
|
|
}
|
|
else
|
|
{
|
|
//todo automation - make sure to report error if the device was not discovered correctly
|
|
}
|
|
|
|
// Note the response
|
|
RefreshTestResponses++;
|
|
|
|
// If we have received all the responses we expect to
|
|
if ( RefreshTestResponses == DeviceClusterManager.GetNumClusters() )
|
|
{
|
|
TestsRefreshedDelegate.Broadcast();
|
|
|
|
// Update the tests with tracking details
|
|
ReportManager.TrackHistory(bTrackHistory, NumberOfHistoryItemsTracked);
|
|
}
|
|
}
|
|
|
|
void FAutomationControllerManager::ProcessResults()
|
|
{
|
|
bHasErrors = false;
|
|
bHasWarning = false;
|
|
bHasLogs = false;
|
|
|
|
TArray< TSharedPtr< IAutomationReport > >& TestReports = GetReports();
|
|
|
|
if ( TestReports.Num() )
|
|
{
|
|
bTestResultsAvailable = true;
|
|
|
|
for ( int32 Index = 0; Index < TestReports.Num(); Index++ )
|
|
{
|
|
CheckChildResult(TestReports[Index]);
|
|
}
|
|
}
|
|
|
|
if ( !ReportOutputPathOverride.IsEmpty() )
|
|
{
|
|
FDateTime Timestamp = FDateTime::Now();
|
|
|
|
// Generate Html
|
|
GenerateHtmlTestPassSummary(Timestamp);
|
|
// Generate Json
|
|
GenerateJsonTestPassSummary(Timestamp);
|
|
}
|
|
|
|
// Then clean our array for the next pass.
|
|
OurPassResults.ClearAllEntries();
|
|
CleanUpCheckpointFile();
|
|
|
|
SetControllerStatus(EAutomationControllerModuleState::Ready);
|
|
}
|
|
|
|
void FAutomationControllerManager::CheckChildResult(TSharedPtr<IAutomationReport> InReport)
|
|
{
|
|
TArray<TSharedPtr<IAutomationReport> >& ChildReports = InReport->GetChildReports();
|
|
|
|
if ( ChildReports.Num() > 0 )
|
|
{
|
|
for ( int32 Index = 0; Index < ChildReports.Num(); Index++ )
|
|
{
|
|
CheckChildResult(ChildReports[Index]);
|
|
}
|
|
}
|
|
else if ( ( bHasErrors && bHasWarning && bHasLogs ) == false && InReport->IsEnabled() )
|
|
{
|
|
for ( int32 ClusterIndex = 0; ClusterIndex < GetNumDeviceClusters(); ++ClusterIndex )
|
|
{
|
|
FAutomationTestResults TestResults = InReport->GetResults(ClusterIndex, CurrentTestPass);
|
|
|
|
if ( TestResults.Errors.Num() )
|
|
{
|
|
bHasErrors = true;
|
|
}
|
|
if ( TestResults.Warnings.Num() )
|
|
{
|
|
bHasWarning = true;
|
|
}
|
|
if ( TestResults.Logs.Num() )
|
|
{
|
|
bHasLogs = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void FAutomationControllerManager::SetControllerStatus(EAutomationControllerModuleState::Type InAutomationTestState)
|
|
{
|
|
if ( InAutomationTestState != AutomationTestState )
|
|
{
|
|
// Inform the UI if the test state has changed
|
|
AutomationTestState = InAutomationTestState;
|
|
TestsAvailableDelegate.Broadcast(AutomationTestState);
|
|
}
|
|
}
|
|
|
|
void FAutomationControllerManager::RemoveTestRunning(const FMessageAddress& TestAddressToRemove)
|
|
{
|
|
for ( int32 Index = 0; Index < TestRunningArray.Num(); Index++ )
|
|
{
|
|
if ( TestRunningArray[Index].OwnerMessageAddress == TestAddressToRemove )
|
|
{
|
|
TestRunningArray.RemoveAt(Index);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void FAutomationControllerManager::AddPingResult(const FMessageAddress& ResponderAddress)
|
|
{
|
|
for ( int32 Index = 0; Index < TestRunningArray.Num(); Index++ )
|
|
{
|
|
if ( TestRunningArray[Index].OwnerMessageAddress == ResponderAddress )
|
|
{
|
|
TestRunningArray[Index].LastPingTime = 0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void FAutomationControllerManager::UpdateTests()
|
|
{
|
|
static const float CheckTestInterval = 1.0f;
|
|
static const float GameInstanceLostTimer = 200.0f;
|
|
|
|
CheckTestTimer += FPlatformTime::Seconds() - LastTimeUpdateTicked;
|
|
LastTimeUpdateTicked = FPlatformTime::Seconds();
|
|
if ( CheckTestTimer > CheckTestInterval )
|
|
{
|
|
for ( int32 Index = 0; Index < TestRunningArray.Num(); Index++ )
|
|
{
|
|
TestRunningArray[Index].LastPingTime += CheckTestTimer;
|
|
|
|
if ( TestRunningArray[Index].LastPingTime > GameInstanceLostTimer )
|
|
{
|
|
// Find the game session instance info
|
|
int32 ClusterIndex;
|
|
int32 DeviceIndex;
|
|
verify(DeviceClusterManager.FindDevice(TestRunningArray[Index].OwnerMessageAddress, ClusterIndex, DeviceIndex));
|
|
//verify this device thought it was busy
|
|
TSharedPtr <IAutomationReport> Report = DeviceClusterManager.GetTest(ClusterIndex, DeviceIndex);
|
|
check(Report.IsValid());
|
|
// A dummy array used to report the result
|
|
|
|
TArray<FString> EmptyStringArray;
|
|
TArray<FString> ErrorStringArray;
|
|
ErrorStringArray.Add(FString(TEXT("Failed")));
|
|
bHasErrors = true;
|
|
GLog->Logf(ELogVerbosity::Display, TEXT("Timeout hit. Nooooooo."));
|
|
|
|
FAutomationTestResults TestResults;
|
|
TestResults.State = EAutomationState::Fail;
|
|
TestResults.GameInstance = DeviceClusterManager.GetClusterDeviceName(ClusterIndex, DeviceIndex);
|
|
|
|
// Set the results
|
|
Report->SetResults(ClusterIndex, CurrentTestPass, TestResults);
|
|
bTestResultsAvailable = true;
|
|
|
|
// Disable the device in the cluster so it is not used again
|
|
DeviceClusterManager.DisableDevice(ClusterIndex, DeviceIndex);
|
|
|
|
// Remove the running test
|
|
TestRunningArray.RemoveAt(Index--);
|
|
|
|
// If there are no more devices, set the module state to disabled
|
|
if ( DeviceClusterManager.HasActiveDevice() == false )
|
|
{
|
|
GLog->Logf(ELogVerbosity::Display, TEXT("Module disabled"));
|
|
SetControllerStatus(EAutomationControllerModuleState::Disabled);
|
|
ClusterDistributionMask = 0;
|
|
}
|
|
else
|
|
{
|
|
GLog->Logf(ELogVerbosity::Display, TEXT("Module not disabled. Keep looking."));
|
|
// Remove the cluster from the mask if there are no active devices left
|
|
if ( DeviceClusterManager.GetNumActiveDevicesInCluster(ClusterIndex) == 0 )
|
|
{
|
|
ClusterDistributionMask &= ~( 1 << ClusterIndex );
|
|
}
|
|
if ( TestRunningArray.Num() == 0 )
|
|
{
|
|
SetControllerStatus(EAutomationControllerModuleState::Ready);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
MessageEndpoint->Send(new FAutomationWorkerPing(), TestRunningArray[Index].OwnerMessageAddress);
|
|
}
|
|
}
|
|
CheckTestTimer = 0.f;
|
|
}
|
|
}
|
|
|
|
const bool FAutomationControllerManager::ExportReport(uint32 FileExportTypeMask)
|
|
{
|
|
return ReportManager.ExportReport(FileExportTypeMask, GetNumDeviceClusters());
|
|
}
|
|
|
|
bool FAutomationControllerManager::IsTestRunnable(IAutomationReportPtr InReport) const
|
|
{
|
|
bool bIsRunnable = false;
|
|
|
|
for ( int32 ClusterIndex = 0; ClusterIndex < GetNumDeviceClusters(); ++ClusterIndex )
|
|
{
|
|
if ( InReport->IsSupported(ClusterIndex) )
|
|
{
|
|
if ( GetNumDevicesInCluster(ClusterIndex) >= InReport->GetNumParticipantsRequired() )
|
|
{
|
|
bIsRunnable = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return bIsRunnable;
|
|
}
|
|
|
|
/* FAutomationControllerModule callbacks
|
|
*****************************************************************************/
|
|
|
|
void FAutomationControllerManager::HandleFindWorkersResponseMessage(const FAutomationWorkerFindWorkersResponse& Message, const IMessageContextRef& Context)
|
|
{
|
|
if ( Message.SessionId == ActiveSessionId )
|
|
{
|
|
DeviceClusterManager.AddDeviceFromMessage(Context->GetSender(), Message, DeviceGroupFlags);
|
|
}
|
|
|
|
RequestTests();
|
|
|
|
SetControllerStatus(EAutomationControllerModuleState::Ready);
|
|
}
|
|
|
|
void FAutomationControllerManager::HandlePongMessage( const FAutomationWorkerPong& Message, const IMessageContextRef& Context )
|
|
{
|
|
AddPingResult(Context->GetSender());
|
|
}
|
|
|
|
void FAutomationControllerManager::HandleReceivedScreenShot(const FAutomationWorkerScreenImage& Message, const IMessageContextRef& Context)
|
|
{
|
|
FString ScreenshotIncomingFolder = FPaths::GameSavedDir() / TEXT("Automation/Incoming/");
|
|
|
|
bool bTree = true;
|
|
FString FileName = ScreenshotIncomingFolder / Message.ScreenShotName;
|
|
IFileManager::Get().MakeDirectory(*FPaths::GetPath(FileName), bTree);
|
|
FFileHelper::SaveArrayToFile(Message.ScreenImage, *FileName);
|
|
|
|
// TODO Automation There is identical code in, Engine\Source\Runtime\AutomationWorker\Private\AutomationWorkerModule.cpp,
|
|
// need to move this code into common area.
|
|
|
|
FString Json;
|
|
if ( FJsonObjectConverter::UStructToJsonObjectString(Message.Metadata, Json) )
|
|
{
|
|
FString MetadataPath = FPaths::ChangeExtension(FileName, TEXT("json"));
|
|
FFileHelper::SaveStringToFile(Json, *MetadataPath, FFileHelper::EEncodingOptions::ForceUTF8WithoutBOM);
|
|
}
|
|
|
|
TSharedRef<FComparisonEntry> Comparison = MakeShareable(new FComparisonEntry());
|
|
Comparison->Sender = Context->GetSender();
|
|
Comparison->Name = Message.Metadata.Name;
|
|
Comparison->PendingComparison = ScreenshotManager->CompareScreensotAsync(Message.ScreenShotName);
|
|
|
|
ComparisonQueue.Enqueue(Comparison);
|
|
}
|
|
|
|
void FAutomationControllerManager::HandleRequestNextNetworkCommandMessage(const FAutomationWorkerRequestNextNetworkCommand& Message, const IMessageContextRef& Context)
|
|
{
|
|
// Harvest iteration of running the tests this result came from (stops stale results from being committed to subsequent runs)
|
|
if ( Message.ExecutionCount == ExecutionCount )
|
|
{
|
|
// Find the device id for the address
|
|
int32 ClusterIndex;
|
|
int32 DeviceIndex;
|
|
|
|
verify(DeviceClusterManager.FindDevice(Context->GetSender(), ClusterIndex, DeviceIndex));
|
|
|
|
// Verify this device thought it was busy
|
|
TSharedPtr<IAutomationReport> Report = DeviceClusterManager.GetTest(ClusterIndex, DeviceIndex);
|
|
check(Report.IsValid());
|
|
|
|
// Increment network command responses
|
|
bool bAllResponsesReceived = Report->IncrementNetworkCommandResponses();
|
|
|
|
// Test if we've accumulated all responses AND this was the result for the round of test running AND we're still running tests
|
|
if ( bAllResponsesReceived && ( ClusterDistributionMask & ( 1 << ClusterIndex ) ) )
|
|
{
|
|
// Reset the counter
|
|
Report->ResetNetworkCommandResponses();
|
|
|
|
// For every device in this networked test
|
|
TArray<FMessageAddress> DeviceAddresses = DeviceClusterManager.GetDevicesReservedForTest(ClusterIndex, Report);
|
|
check(DeviceAddresses.Num() == Report->GetNumParticipantsRequired());
|
|
|
|
// Send it to each device
|
|
for ( int32 AddressIndex = 0; AddressIndex < DeviceAddresses.Num(); ++AddressIndex )
|
|
{
|
|
//send "next command message" to worker
|
|
MessageEndpoint->Send(new FAutomationWorkerNextNetworkCommandReply(), DeviceAddresses[AddressIndex]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void FAutomationControllerManager::HandleRequestTestsReplyMessage(const FAutomationWorkerRequestTestsReply& Message, const IMessageContextRef& Context)
|
|
{
|
|
FAutomationTestInfo NewTest = Message.GetTestInfo();
|
|
TestInfo.Add(NewTest);
|
|
}
|
|
|
|
void FAutomationControllerManager::HandleRequestTestsReplyCompleteMessage(const FAutomationWorkerRequestTestsReplyComplete& Message, const IMessageContextRef& Context)
|
|
{
|
|
SetTestNames(Context->GetSender());
|
|
}
|
|
|
|
void FAutomationControllerManager::HandleRunTestsReplyMessage(const FAutomationWorkerRunTestsReply& Message, const IMessageContextRef& Context)
|
|
{
|
|
// If we should commit these results
|
|
if ( Message.ExecutionCount == ExecutionCount )
|
|
{
|
|
FAutomationTestResults TestResults;
|
|
|
|
TestResults.State = Message.Success ? EAutomationState::Success : EAutomationState::Fail;
|
|
TestResults.Duration = Message.Duration;
|
|
|
|
// Mark device as back on the market
|
|
int32 ClusterIndex;
|
|
int32 DeviceIndex;
|
|
|
|
verify(DeviceClusterManager.FindDevice(Context->GetSender(), ClusterIndex, DeviceIndex));
|
|
|
|
TestResults.GameInstance = DeviceClusterManager.GetClusterDeviceName(ClusterIndex, DeviceIndex);
|
|
for ( auto& Error : Message.Errors )
|
|
{
|
|
TestResults.Errors.Add(Error.ToAutomationEvent());
|
|
}
|
|
TestResults.Logs = Message.Logs;
|
|
TestResults.Warnings = Message.Warnings;
|
|
|
|
// Verify this device thought it was busy
|
|
TSharedPtr<IAutomationReport> Report = DeviceClusterManager.GetTest(ClusterIndex, DeviceIndex);
|
|
check(Report.IsValid());
|
|
|
|
Report->SetResults(ClusterIndex, CurrentTestPass, TestResults);
|
|
|
|
const FAutomationTestResults& FinalResults = Report->GetResults(ClusterIndex, CurrentTestPass);
|
|
|
|
// Gather all of the data relevant to this test for our json reporting.
|
|
CollectTestResults(Report, FinalResults);
|
|
|
|
#if WITH_EDITOR
|
|
FMessageLog AutomationTestingLog("AutomationTestingLog");
|
|
AutomationTestingLog.Open();
|
|
#endif
|
|
|
|
for ( TArray<FAutomationEvent>::TConstIterator ErrorIter(TestResults.Errors); ErrorIter; ++ErrorIter )
|
|
{
|
|
// FAutomationTestFramework::Get().LogTestMessage(**ErrorIter, ELogVerbosity::Error);
|
|
GLog->Logf(ELogVerbosity::Error, TEXT("%s"), *( *ErrorIter ).ToString());
|
|
#if WITH_EDITOR
|
|
AutomationTestingLog.Error(FText::FromString(( *ErrorIter ).ToString()));
|
|
#endif
|
|
}
|
|
for ( TArray<FString>::TConstIterator WarningIter(Message.Warnings); WarningIter; ++WarningIter )
|
|
{
|
|
GLog->Logf(ELogVerbosity::Warning, TEXT("%s"), **WarningIter);
|
|
#if WITH_EDITOR
|
|
AutomationTestingLog.Warning(FText::FromString(*WarningIter));
|
|
#endif
|
|
}
|
|
for ( TArray<FString>::TConstIterator LogItemIter(Message.Logs); LogItemIter; ++LogItemIter )
|
|
{
|
|
GLog->Logf(ELogVerbosity::Log, TEXT("%s"), **LogItemIter);
|
|
#if WITH_EDITOR
|
|
AutomationTestingLog.Info(FText::FromString(*LogItemIter));
|
|
#endif
|
|
}
|
|
|
|
if ( TestResults.State == EAutomationState::Success )
|
|
{
|
|
FString SuccessString = FString::Printf(TEXT("...Automation Test Succeeded (%s)"), *Report->GetDisplayName());
|
|
GLog->Logf(ELogVerbosity::Log, TEXT("%s"), *SuccessString);
|
|
#if WITH_EDITOR
|
|
AutomationTestingLog.Info(FText::FromString(*SuccessString));
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
FString FailureString = FString::Printf(TEXT("...Automation Test Failed (%s)"), *Report->GetDisplayName());
|
|
GLog->Logf(ELogVerbosity::Log, TEXT("%s"), *FailureString);
|
|
#if WITH_EDITOR
|
|
AutomationTestingLog.Error(FText::FromString(*FailureString));
|
|
#endif
|
|
//FAutomationTestFramework::Get().Lo
|
|
}
|
|
|
|
// const bool TestSucceeded = (TestResults.State == EAutomationState::Success);
|
|
//FAutomationTestFramework::Get().LogEndTestMessage(Report->GetDisplayName(), TestSucceeded);
|
|
|
|
// Device is now good to go
|
|
DeviceClusterManager.SetTest(ClusterIndex, DeviceIndex, NULL);
|
|
}
|
|
|
|
// Remove the running test
|
|
RemoveTestRunning(Context->GetSender());
|
|
}
|
|
|
|
void FAutomationControllerManager::HandleWorkerOfflineMessage( const FAutomationWorkerWorkerOffline& Message, const IMessageContextRef& Context )
|
|
{
|
|
FMessageAddress DeviceMessageAddress = Context->GetSender();
|
|
DeviceClusterManager.Remove(DeviceMessageAddress);
|
|
}
|
|
|
|
bool FAutomationControllerManager::IsDeviceGroupFlagSet( EAutomationDeviceGroupTypes::Type InDeviceGroup ) const
|
|
{
|
|
const uint32 FlagMask = 1 << InDeviceGroup;
|
|
return (DeviceGroupFlags & FlagMask) > 0;
|
|
}
|
|
|
|
void FAutomationControllerManager::ToggleDeviceGroupFlag( EAutomationDeviceGroupTypes::Type InDeviceGroup )
|
|
{
|
|
const uint32 FlagMask = 1 << InDeviceGroup;
|
|
DeviceGroupFlags = DeviceGroupFlags ^ FlagMask;
|
|
}
|
|
|
|
void FAutomationControllerManager::UpdateDeviceGroups( )
|
|
{
|
|
DeviceClusterManager.ReGroupDevices( DeviceGroupFlags );
|
|
|
|
// Update the reports in case the number of clusters changed
|
|
int32 NumOfClusters = DeviceClusterManager.GetNumClusters();
|
|
ReportManager.ClustersUpdated(NumOfClusters);
|
|
}
|
|
|
|
void FAutomationControllerManager::TrackReportHistory(const bool bShouldTrack, const int32 NumReportsToTrack)
|
|
{
|
|
bTrackHistory = bShouldTrack;
|
|
NumberOfHistoryItemsTracked = NumReportsToTrack;
|
|
|
|
// Update the ini with the settings
|
|
GConfig->SetBool(*AutomationControllerConstants::HistoryConfigSectionName, TEXT("bTrackHistory"), bTrackHistory, GEngineIni);
|
|
GConfig->SetInt(*AutomationControllerConstants::HistoryConfigSectionName, TEXT("NumberOfHistoryItemsTracked"), NumberOfHistoryItemsTracked, GEngineIni);
|
|
|
|
ReportManager.TrackHistory(bTrackHistory, NumberOfHistoryItemsTracked);
|
|
}
|
|
|
|
const bool FAutomationControllerManager::IsTrackingHistory() const
|
|
{
|
|
return bTrackHistory;
|
|
}
|
|
|
|
const int32 FAutomationControllerManager::GetNumberHistoryItemsTracking() const
|
|
{
|
|
return NumberOfHistoryItemsTracked;
|
|
}
|
|
|
|
TArray<FString> FAutomationControllerManager::GetCheckpointFileContents()
|
|
{
|
|
TestsRun.Empty();
|
|
FString CheckpointFileName = FString::Printf(TEXT("%sautomationcheckpoint.txt"), *FPaths::AutomationDir());
|
|
if (IFileManager::Get().FileExists(*CheckpointFileName))
|
|
{
|
|
FString FileData;
|
|
FFileHelper::LoadFileToString(FileData, *CheckpointFileName);
|
|
FileData.ParseIntoArrayLines(TestsRun);
|
|
|
|
}
|
|
return TestsRun;
|
|
}
|
|
|
|
FArchive* FAutomationControllerManager::GetCheckpointFileForWrite()
|
|
{
|
|
if (!CheckpointFile)
|
|
{
|
|
FString CheckpointFileName = FString::Printf(TEXT("%sautomationcheckpoint.txt"), *FPaths::AutomationDir());
|
|
CheckpointFile = IFileManager::Get().CreateFileWriter(*CheckpointFileName, 8);
|
|
}
|
|
return CheckpointFile;
|
|
}
|
|
|
|
void FAutomationControllerManager::CleanUpCheckpointFile()
|
|
{
|
|
if (CheckpointFile)
|
|
{
|
|
CheckpointFile->Close();
|
|
CheckpointFile = nullptr;
|
|
}
|
|
FString CheckpointFileName = FString::Printf(TEXT("%sautomationcheckpoint.txt"), *FPaths::AutomationDir());
|
|
if (IFileManager::Get().FileExists(*CheckpointFileName))
|
|
{
|
|
IFileManager::Get().Delete(*CheckpointFileName);
|
|
}
|
|
}
|
|
|
|
void FAutomationControllerManager::WriteLoadedCheckpointDataToFile()
|
|
{
|
|
GetCheckpointFileForWrite();
|
|
for (int i = 0; i < TestsRun.Num(); i++)
|
|
{
|
|
FString LineToWrite = FString::Printf(TEXT("%s\n"), *TestsRun[i]);
|
|
CheckpointFile->Serialize(TCHAR_TO_ANSI(*LineToWrite), LineToWrite.Len());
|
|
}
|
|
}
|
|
|
|
void FAutomationControllerManager::WriteLineToCheckpointFile(FString StringToWrite)
|
|
{
|
|
GetCheckpointFileForWrite();
|
|
if (CheckpointFile)
|
|
{
|
|
FString LineToWrite = FString::Printf(TEXT("%s\n"), *StringToWrite);
|
|
CheckpointFile->Serialize(TCHAR_TO_ANSI(*LineToWrite), LineToWrite.Len());
|
|
CheckpointFile->Flush();
|
|
}
|
|
} |