Browse Source

Made an example to execute a lua file from command line (#13121)

* Made a sample to execute a lua file from command line

Signed-off-by: jiaweig <[email protected]>

* Flipped the message param order

Signed-off-by: jiaweig <[email protected]>

* Update the screenshot test in automated testing

Signed-off-by: jiaweig <[email protected]>

Signed-off-by: jiaweig <[email protected]>
jiaweig 2 years ago
parent
commit
f18d6efcc1

+ 3 - 3
AutomatedTesting/Assets/AutomatedTestScripts/screenshot.sa.lua

@@ -9,12 +9,12 @@
 --
 --
 ----------------------------------------------------------------------------------------------------
 ----------------------------------------------------------------------------------------------------
 
 
-g_screenshotOutputFolder = GetScreenshotOutputPath(true)
-Print('Saving screenshots to ' .. NormalizePath(g_screenshotOutputFolder))
+g_screenshotOutputFolder = '@user@/ScriptAutomation/Screenshots/'
+Print('Saving screenshots to ' .. ResolvePath(g_screenshotOutputFolder))
 
 
 ResizeViewport(800, 600)
 ResizeViewport(800, 600)
 
 
 IdleFrames(100) -- wait for assets to load into the level
 IdleFrames(100) -- wait for assets to load into the level
 ExecuteConsoleCommand("r_displayInfo=0")
 ExecuteConsoleCommand("r_displayInfo=0")
 IdleFrames(1) -- wait 1 frame for the info text to hide
 IdleFrames(1) -- wait 1 frame for the info text to hide
-CaptureScreenshot(g_screenshotOutputFolder .. '/ScriptAutomation_CaptureScreenshotTest.png')
+CaptureScreenshot('ScriptAutomation_CaptureScreenshotTest.png')

+ 7 - 1
Gems/ScriptAutomation/Code/Include/ScriptAutomation/ScriptAutomationBus.h

@@ -24,7 +24,7 @@ namespace AZ
 
 
 namespace ScriptAutomation
 namespace ScriptAutomation
 {
 {
-    static constexpr float DefaultPauseTimeout = 5.0f;
+    static constexpr float DefaultPauseTimeout = 10.0f;
     static constexpr AZ::Crc32 AutomationServiceCrc = AZ_CRC_CE("AutomationService");
     static constexpr AZ::Crc32 AutomationServiceCrc = AZ_CRC_CE("AutomationService");
 
 
     class ScriptAutomationRequests
     class ScriptAutomationRequests
@@ -38,6 +38,12 @@ namespace ScriptAutomation
         //! Retrieve the specialized behaviour context used for automation purposes
         //! Retrieve the specialized behaviour context used for automation purposes
         virtual AZ::BehaviorContext* GetAutomationContext() = 0;
         virtual AZ::BehaviorContext* GetAutomationContext() = 0;
 
 
+        //! Load and activate the script, and connect to the tick bus.
+        virtual void ActivateScript(const char* scriptPath) = 0;
+
+        //! Deactivate all scripts and disconnect from the tick bus.
+        virtual void DeactivateScripts() = 0;
+
         //! Can be used by sample components to temporarily pause script processing, for
         //! Can be used by sample components to temporarily pause script processing, for
         //! example to delay until some required resources are loaded and initialized.
         //! example to delay until some required resources are loaded and initialized.
         virtual void PauseAutomation(float timeout = DefaultPauseTimeout) = 0;
         virtual void PauseAutomation(float timeout = DefaultPauseTimeout) = 0;

+ 131 - 44
Gems/ScriptAutomation/Code/Source/ScriptAutomationScriptBindings.cpp

@@ -65,23 +65,6 @@ namespace ScriptAutomation
             AzFramework::NativeWindow::ToggleFullScreenStateOfDefaultWindow();
             AzFramework::NativeWindow::ToggleFullScreenStateOfDefaultWindow();
         }
         }
 
 
-        AZ::IO::FixedMaxPath GetScreenshotsPath(bool resolvePath)
-        {
-            AZ::IO::FixedMaxPath path("@user@");
-            if (resolvePath)
-            {
-                if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr)
-                {
-                    path.clear();
-                    settingsRegistry->Get(path.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_ProjectUserPath);
-                }
-            }
-            
-            path /= "scriptautomation/screenshots";
-            
-            return path.LexicallyNormal();
-        }
-
         AZ::IO::FixedMaxPath GetProfilingPath(bool resolvePath)
         AZ::IO::FixedMaxPath GetProfilingPath(bool resolvePath)
         {
         {
             AZ::IO::FixedMaxPath path("@user@");
             AZ::IO::FixedMaxPath path("@user@");
@@ -286,31 +269,32 @@ namespace ScriptAutomation
             return rpiSystem->GetRenderApiName().GetCStr();
             return rpiSystem->GetRenderApiName().GetCStr();
         }
         }
 
 
-        AZStd::string GetScreenshotOutputPath(bool normalized)
-        {
-            return Utils::GetScreenshotsPath(normalized).String();
-        }
-
         AZStd::string GetProfilingOutputPath(bool normalized)
         AZStd::string GetProfilingOutputPath(bool normalized)
         {
         {
             return Utils::GetProfilingPath(normalized).String();
             return Utils::GetProfilingPath(normalized).String();
         }
         }
 
 
-        bool PrepareForScreenCapture(const AZ::IO::FixedMaxPath& path)
+        bool PrepareForScreenCapture(const AZStd::string& imageName)
         {
         {
-            if (!AZ::IO::PathView(Utils::ResolvePath(path)).IsRelativeTo(Utils::GetScreenshotsPath(true)))
+            AZStd::string fullFilePath;
+            AZ::Render::FrameCaptureTestRequestBus::BroadcastResult(
+                fullFilePath, &AZ::Render::FrameCaptureTestRequestBus::Events::BuildScreenshotFilePath, imageName, true);
+
+            if (!AZ::IO::PathView(fullFilePath).IsRelativeTo(Utils::ResolvePath("@user@")))
             {
             {
                 // The main reason we require screenshots to be in a specific folder is to ensure we don't delete or replace some other important file.
                 // The main reason we require screenshots to be in a specific folder is to ensure we don't delete or replace some other important file.
                 AZ_Error("ScriptAutomation", false, "Screenshots must be captured under the '%s' folder. Attempted to save screenshot to '%s'.",
                 AZ_Error("ScriptAutomation", false, "Screenshots must be captured under the '%s' folder. Attempted to save screenshot to '%s'.",
-                    Utils::GetScreenshotsPath(false).c_str(), path.c_str());
+                    Utils::ResolvePath("@user@").c_str(),
+                    fullFilePath.c_str());
 
 
                 return false;
                 return false;
             }
             }
 
 
             // Delete the file if it already exists
             // Delete the file if it already exists
-            if (AZ::IO::LocalFileIO::GetInstance()->Exists(path.c_str()) && !AZ::IO::LocalFileIO::GetInstance()->Remove(path.c_str()))
+            if (AZ::IO::LocalFileIO::GetInstance()->Exists(fullFilePath.c_str()) &&
+                !AZ::IO::LocalFileIO::GetInstance()->Remove(fullFilePath.c_str()))
             {
             {
-                AZ_Error("ScriptAutomation", false, "Failed to delete existing screenshot file '%s'.", path.c_str());
+                AZ_Error("ScriptAutomation", false, "Failed to delete existing screenshot file '%s'.", fullFilePath.c_str());
                 return false;
                 return false;
             }
             }
 
 
@@ -321,16 +305,63 @@ namespace ScriptAutomation
             return true;
             return true;
         }
         }
 
 
-        void CaptureScreenshot(const AZStd::string& filePath)
+        void SetScreenshotFolder(const AZStd::string& screenshotFolder)
+        {
+            auto operation = [screenshotFolder]()
+            {
+                AZ::Render::FrameCaptureTestRequestBus::Broadcast(
+                    &AZ::Render::FrameCaptureTestRequestBus::Events::SetScreenshotFolder, screenshotFolder);
+            };
+
+            ScriptAutomationInterface::Get()->QueueScriptOperation(AZStd::move(operation));
+        }
+
+        void SetTestEnvPath(const AZStd::string& envPath)
+        {
+            auto operation = [envPath]()
+            {
+                AZ::Render::FrameCaptureTestRequestBus::Broadcast(&AZ::Render::FrameCaptureTestRequestBus::Events::SetTestEnvPath, envPath);
+            };
+
+            ScriptAutomationInterface::Get()->QueueScriptOperation(AZStd::move(operation));
+        }
+
+        void SetOfficialBaselineImageFolder(const AZStd::string& baselineFolder)
+        {
+            auto operation = [baselineFolder]()
+            {
+                AZ::Render::FrameCaptureTestRequestBus::Broadcast(
+                    &AZ::Render::FrameCaptureTestRequestBus::Events::SetOfficialBaselineImageFolder, baselineFolder);
+            };
+
+            ScriptAutomationInterface::Get()->QueueScriptOperation(AZStd::move(operation));
+        }
+
+        void SetLocalBaselineImageFolder(const AZStd::string& baselineFolder)
+        {
+            auto operation = [baselineFolder]()
+            {
+                AZ::Render::FrameCaptureTestRequestBus::Broadcast(
+                    &AZ::Render::FrameCaptureTestRequestBus::Events::SetLocalBaselineImageFolder, baselineFolder);
+            };
+
+            ScriptAutomationInterface::Get()->QueueScriptOperation(AZStd::move(operation));
+        }
+
+        void CaptureScreenshot(const AZStd::string& imageName)
         {
         {
-            auto operation = [filePath]()
+            auto operation = [imageName]()
             {
             {
                 // Note this will pause the script until the capture is complete
                 // Note this will pause the script until the capture is complete
-                if (PrepareForScreenCapture(AZ::IO::FixedMaxPath(filePath)))
+                if (PrepareForScreenCapture(imageName))
                 {
                 {
+                    AZStd::string screenshotFilePath;
+                    AZ::Render::FrameCaptureTestRequestBus::BroadcastResult(
+                        screenshotFilePath, &AZ::Render::FrameCaptureTestRequestBus::Events::BuildScreenshotFilePath, imageName, true);
+
                     auto scriptAutomationInterface = ScriptAutomationInterface::Get();
                     auto scriptAutomationInterface = ScriptAutomationInterface::Get();
                     AZ::Render::FrameCaptureId frameCaptureId = AZ::Render::InvalidFrameCaptureId;
                     AZ::Render::FrameCaptureId frameCaptureId = AZ::Render::InvalidFrameCaptureId;
-                    AZ::Render::FrameCaptureRequestBus::BroadcastResult(frameCaptureId, &AZ::Render::FrameCaptureRequestBus::Events::CaptureScreenshot, filePath);
+                    AZ::Render::FrameCaptureRequestBus::BroadcastResult(frameCaptureId, &AZ::Render::FrameCaptureRequestBus::Events::CaptureScreenshot, screenshotFilePath);
                     if (frameCaptureId != AZ::Render::InvalidFrameCaptureId)
                     if (frameCaptureId != AZ::Render::InvalidFrameCaptureId)
                     {
                     {
                         scriptAutomationInterface->SetFrameCaptureId(frameCaptureId);
                         scriptAutomationInterface->SetFrameCaptureId(frameCaptureId);
@@ -338,7 +369,7 @@ namespace ScriptAutomation
                     else
                     else
                     {
                     {
                         AZ_Error("ScriptAutomation", false, "Script: failed to trigger screenshot capture");
                         AZ_Error("ScriptAutomation", false, "Script: failed to trigger screenshot capture");
-                       scriptAutomationInterface->ResumeAutomation();
+                        scriptAutomationInterface->ResumeAutomation();
                     }
                     }
                 }
                 }
             };
             };
@@ -346,16 +377,20 @@ namespace ScriptAutomation
             ScriptAutomationInterface::Get()->QueueScriptOperation(AZStd::move(operation));
             ScriptAutomationInterface::Get()->QueueScriptOperation(AZStd::move(operation));
         }
         }
 
 
-        void CaptureScreenshotWithPreview(const AZStd::string& filePath)
+        void CaptureScreenshotWithPreview(const AZStd::string& imageName)
         {
         {
-            auto operation = [filePath]()
+            auto operation = [imageName]()
             {
             {
                 // Note this will pause the script until the capture is complete
                 // Note this will pause the script until the capture is complete
-                if (PrepareForScreenCapture(AZ::IO::FixedMaxPath(filePath)))
+                if (PrepareForScreenCapture(imageName))
                 {
                 {
+                    AZStd::string screenshotFilePath;
+                    AZ::Render::FrameCaptureTestRequestBus::BroadcastResult(
+                        screenshotFilePath, &AZ::Render::FrameCaptureTestRequestBus::Events::BuildScreenshotFilePath, imageName, true);
+
                     auto scriptAutomationInterface = ScriptAutomationInterface::Get();
                     auto scriptAutomationInterface = ScriptAutomationInterface::Get();
                     AZ::Render::FrameCaptureId frameCaptureId = AZ::Render::InvalidFrameCaptureId;
                     AZ::Render::FrameCaptureId frameCaptureId = AZ::Render::InvalidFrameCaptureId;
-                    AZ::Render::FrameCaptureRequestBus::BroadcastResult(frameCaptureId, &AZ::Render::FrameCaptureRequestBus::Events::CaptureScreenshotWithPreview, filePath);
+                    AZ::Render::FrameCaptureRequestBus::BroadcastResult(frameCaptureId, &AZ::Render::FrameCaptureRequestBus::Events::CaptureScreenshotWithPreview, screenshotFilePath);
                     if (frameCaptureId != AZ::Render::InvalidFrameCaptureId)
                     if (frameCaptureId != AZ::Render::InvalidFrameCaptureId)
                     {
                     {
                         scriptAutomationInterface->SetFrameCaptureId(frameCaptureId);
                         scriptAutomationInterface->SetFrameCaptureId(frameCaptureId);
@@ -363,7 +398,7 @@ namespace ScriptAutomation
                     else
                     else
                     {
                     {
                         AZ_Error("ScriptAutomation", false, "Script: failed to trigger screenshot capture with preview");
                         AZ_Error("ScriptAutomation", false, "Script: failed to trigger screenshot capture with preview");
-                       scriptAutomationInterface->ResumeAutomation();
+                        scriptAutomationInterface->ResumeAutomation();
                     }
                     }
                 }
                 }
             };
             };
@@ -402,13 +437,13 @@ namespace ScriptAutomation
 
 
             AZStd::vector<AZStd::string> passHierarchy;
             AZStd::vector<AZStd::string> passHierarchy;
             AZStd::string slot;
             AZStd::string slot;
-            AZStd::string outputFilePath;
+            AZStd::string imageName;
 
 
             // read slot name and output file path
             // read slot name and output file path
             dc.ReadArg(1, stringValue);
             dc.ReadArg(1, stringValue);
             slot = AZStd::string(stringValue);
             slot = AZStd::string(stringValue);
             dc.ReadArg(2, stringValue);
             dc.ReadArg(2, stringValue);
-            outputFilePath = AZStd::string(stringValue);
+            imageName = AZStd::string(stringValue);
 
 
             AZ::RPI::PassAttachmentReadbackOption readbackOption = AZ::RPI::PassAttachmentReadbackOption::Output;
             AZ::RPI::PassAttachmentReadbackOption readbackOption = AZ::RPI::PassAttachmentReadbackOption::Output;
             if (dc.GetNumArguments() == 4)
             if (dc.GetNumArguments() == 4)
@@ -447,14 +482,18 @@ namespace ScriptAutomation
                 }
                 }
             }
             }
 
 
-            auto operation = [passHierarchy, slot, outputFilePath, readbackOption]()
+            auto operation = [passHierarchy, slot, imageName, readbackOption]()
             {
             {
                 // Note this will pause the script until the capture is complete
                 // Note this will pause the script until the capture is complete
-                if (PrepareForScreenCapture(AZ::IO::FixedMaxPath(outputFilePath)))
+                if (PrepareForScreenCapture(imageName))
                 {
                 {
+                    AZStd::string screenshotFilePath;
+                    AZ::Render::FrameCaptureTestRequestBus::BroadcastResult(
+                        screenshotFilePath, &AZ::Render::FrameCaptureTestRequestBus::Events::BuildScreenshotFilePath, imageName, true);
+
                     auto scriptAutomationInterface = ScriptAutomationInterface::Get();
                     auto scriptAutomationInterface = ScriptAutomationInterface::Get();
                     AZ::Render::FrameCaptureId frameCaptureId = AZ::Render::InvalidFrameCaptureId;
                     AZ::Render::FrameCaptureId frameCaptureId = AZ::Render::InvalidFrameCaptureId;
-                    AZ::Render::FrameCaptureRequestBus::BroadcastResult(frameCaptureId, &AZ::Render::FrameCaptureRequestBus::Events::CapturePassAttachment, passHierarchy, slot, outputFilePath, readbackOption);
+                    AZ::Render::FrameCaptureRequestBus::BroadcastResult(frameCaptureId, &AZ::Render::FrameCaptureRequestBus::Events::CapturePassAttachment, passHierarchy, slot, screenshotFilePath, readbackOption);
                     if (frameCaptureId != AZ::Render::InvalidFrameCaptureId)
                     if (frameCaptureId != AZ::Render::InvalidFrameCaptureId)
                     {
                     {
                         scriptAutomationInterface->SetFrameCaptureId(frameCaptureId);
                         scriptAutomationInterface->SetFrameCaptureId(frameCaptureId);
@@ -462,13 +501,57 @@ namespace ScriptAutomation
                     else
                     else
                     {
                     {
                         AZ_Error("ScriptAutomation", false, "Script: failed to trigger screenshot capture of pass");
                         AZ_Error("ScriptAutomation", false, "Script: failed to trigger screenshot capture of pass");
-                       scriptAutomationInterface->ResumeAutomation();
+                        scriptAutomationInterface->ResumeAutomation();
                     }
                     }
                 }
                 }
             };
             };
 
 
             ScriptAutomationInterface::Get()->QueueScriptOperation(AZStd::move(operation));
             ScriptAutomationInterface::Get()->QueueScriptOperation(AZStd::move(operation));
         }
         }
+
+        void CompareScreenshots(const AZStd::string& filePathA, const AZStd::string& filePathB, float minDiffFilter)
+        {
+            auto operation = [filePathA, filePathB, minDiffFilter]()
+            {
+                AZStd::string resolvedPathA = ResolvePath(filePathA);
+                AZStd::string resolvedPathB = ResolvePath(filePathB);
+
+                AZ::Utils::ImageDiffResult result;
+                AZ::Render::FrameCaptureTestRequestBus::BroadcastResult(
+                    result,
+                    &AZ::Render::FrameCaptureTestRequestBus::Events::CompareScreenshots,
+                    resolvedPathA,
+                    resolvedPathB,
+                    minDiffFilter);
+
+                if (result.m_resultCode == AZ::Utils::ImageDiffResultCode::Success)
+                {
+                    AZ_Printf(
+                        "ScriptAutomation",
+                        "Diff score is %.5f from %s and %s.",
+                        result.m_diffScore,
+                        resolvedPathA.c_str(),
+                        resolvedPathB.c_str());
+                    AZ_Printf(
+                        "ScriptAutomation",
+                        "Filtered diff score is %.5f from %s and %s.",
+                        result.m_filteredDiffScore,
+                        resolvedPathA.c_str(),
+                        resolvedPathB.c_str());
+                }
+                else
+                {
+                    AZ_Error(
+                        "ScriptAutomation",
+                        false,
+                        "Screenshots compare failed for %s and %s.",
+                        resolvedPathA.c_str(),
+                        resolvedPathB.c_str());
+                }
+            };
+
+            ScriptAutomationInterface::Get()->QueueScriptOperation(AZStd::move(operation));
+        }
     } // namespace Bindings
     } // namespace Bindings
 
 
     void ReflectScriptBindings(AZ::BehaviorContext* behaviorContext)
     void ReflectScriptBindings(AZ::BehaviorContext* behaviorContext)
@@ -490,13 +573,17 @@ namespace ScriptAutomation
         behaviorContext->Method("NormalizePath", [](AZStd::string_view path) -> AZStd::string { return AZ::IO::PathView(path).LexicallyNormal().String(); });
         behaviorContext->Method("NormalizePath", [](AZStd::string_view path) -> AZStd::string { return AZ::IO::PathView(path).LexicallyNormal().String(); });
         behaviorContext->Method("DegToRad", &AZ::DegToRad);
         behaviorContext->Method("DegToRad", &AZ::DegToRad);
         behaviorContext->Method("GetRenderApiName", &Bindings::GetRenderApiName);
         behaviorContext->Method("GetRenderApiName", &Bindings::GetRenderApiName);
-        behaviorContext->Method("GetScreenshotOutputPath", &Bindings::GetScreenshotOutputPath);
         behaviorContext->Method("GetProfilingOutputPath", &Bindings::GetProfilingOutputPath);
         behaviorContext->Method("GetProfilingOutputPath", &Bindings::GetProfilingOutputPath);
 
 
         // Screenshots...
         // Screenshots...
+        behaviorContext->Method("SetScreenshotFolder", &Bindings::SetScreenshotFolder);
+        behaviorContext->Method("SetTestEnvPath", &Bindings::SetTestEnvPath);
+        behaviorContext->Method("SetOfficialBaselineImageFolder", &Bindings::SetOfficialBaselineImageFolder);
+        behaviorContext->Method("SetLocalBaselineImageFolder", &Bindings::SetLocalBaselineImageFolder);
         behaviorContext->Method("CaptureScreenshot", &Bindings::CaptureScreenshot);
         behaviorContext->Method("CaptureScreenshot", &Bindings::CaptureScreenshot);
         behaviorContext->Method("CaptureScreenshotWithPreview", &Bindings::CaptureScreenshotWithPreview);
         behaviorContext->Method("CaptureScreenshotWithPreview", &Bindings::CaptureScreenshotWithPreview);
         behaviorContext->Method("CapturePassAttachment", &Bindings::CapturePassAttachment);
         behaviorContext->Method("CapturePassAttachment", &Bindings::CapturePassAttachment);
+        behaviorContext->Method("CompareScreenshots", &Bindings::CompareScreenshots);
 
 
         // Profiling data...
         // Profiling data...
         behaviorContext->Method("CapturePassTimestamp", &Bindings::CapturePassTimestamp);
         behaviorContext->Method("CapturePassTimestamp", &Bindings::CapturePassTimestamp);

+ 37 - 8
Gems/ScriptAutomation/Code/Source/ScriptAutomationSystemComponent.cpp

@@ -13,6 +13,7 @@
 #include <AzCore/Asset/AssetCommon.h>
 #include <AzCore/Asset/AssetCommon.h>
 #include <AzCore/Asset/AssetManager.h>
 #include <AzCore/Asset/AssetManager.h>
 #include <AzCore/Component/ComponentApplication.h>
 #include <AzCore/Component/ComponentApplication.h>
+#include <AzCore/Console/IConsole.h>
 #include <AzCore/IO/FileIO.h>
 #include <AzCore/IO/FileIO.h>
 #include <AzCore/RTTI/BehaviorContext.h>
 #include <AzCore/RTTI/BehaviorContext.h>
 #include <AzCore/Script/ScriptAsset.h>
 #include <AzCore/Script/ScriptAsset.h>
@@ -67,6 +68,38 @@ namespace ScriptAutomation
         }
         }
     } // namespace
     } // namespace
 
 
+    void ExecuteLuaScript(const AZ::ConsoleCommandContainer& arguments)
+    {
+        auto scriptAuto = ScriptAutomationInterface::Get();
+
+        if (!scriptAuto)
+        {
+            AZ_Error("ScriptAutomation", false, "There is no ScriptAutomation instance registered to the interface.");
+            return;
+        }
+
+        const char* scriptPath = arguments[0].data();
+
+        scriptAuto->ActivateScript(scriptPath);
+    }
+
+    AZ_CONSOLEFREEFUNC(ExecuteLuaScript, AZ::ConsoleFunctorFlags::Null, "Execute a Lua script");
+
+    void ScriptAutomationSystemComponent::ActivateScript(const char* scriptPath)
+    {
+        m_isStarted = false;
+        m_automationScript = scriptPath;
+
+        AZ::TickBus::Handler::BusConnect();
+    }
+
+    void ScriptAutomationSystemComponent::DeactivateScripts()
+    {
+        m_isStarted = false;
+        m_automationScript = "";
+        AZ::TickBus::Handler::BusDisconnect();
+    }
+
     void ScriptAutomationSystemComponent::Reflect(AZ::ReflectContext* context)
     void ScriptAutomationSystemComponent::Reflect(AZ::ReflectContext* context)
     {
     {
         if (AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context))
         if (AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context))
@@ -162,11 +195,8 @@ namespace ScriptAutomation
             auto commandLine = application->GetAzCommandLine();
             auto commandLine = application->GetAzCommandLine();
             if (commandLine->HasSwitch(automationSuiteSwitch))
             if (commandLine->HasSwitch(automationSuiteSwitch))
             {
             {
-                m_isStarted = false;
-                m_automationScript = commandLine->GetSwitchValue(automationSuiteSwitch, 0);
                 m_exitOnFinish = commandLine->HasSwitch(automationExitSwitch);
                 m_exitOnFinish = commandLine->HasSwitch(automationExitSwitch);
-
-                AZ::TickBus::Handler::BusConnect();
+                ActivateScript(commandLine->GetSwitchValue(automationSuiteSwitch, 0).c_str());
             }
             }
         }
         }
     }
     }
@@ -176,10 +206,7 @@ namespace ScriptAutomation
         m_scriptContext = nullptr;
         m_scriptContext = nullptr;
         m_scriptBehaviorContext = nullptr;
         m_scriptBehaviorContext = nullptr;
 
 
-        if (AZ::TickBus::Handler::BusIsConnected())
-        {
-            AZ::TickBus::Handler::BusDisconnect();
-        }
+        DeactivateScripts();
 
 
         ScriptAutomationRequestBus::Handler::BusDisconnect();
         ScriptAutomationRequestBus::Handler::BusDisconnect();
     }
     }
@@ -234,6 +261,8 @@ namespace ScriptAutomation
             {
             {
                 if(!m_scriptPaused) // final operation may have paused, wait for it to complete or time out
                 if(!m_scriptPaused) // final operation may have paused, wait for it to complete or time out
                 {
                 {
+                    DeactivateScripts();
+
                     ScriptAutomationNotificationBus::Broadcast(&ScriptAutomationNotificationBus::Events::OnAutomationFinished);
                     ScriptAutomationNotificationBus::Broadcast(&ScriptAutomationNotificationBus::Events::OnAutomationFinished);
 
 
                     if (m_exitOnFinish)
                     if (m_exitOnFinish)

+ 4 - 1
Gems/ScriptAutomation/Code/Source/ScriptAutomationSystemComponent.h

@@ -16,7 +16,7 @@
 
 
 #include <Atom/Feature/Utils/ProfilingCaptureBus.h>
 #include <Atom/Feature/Utils/ProfilingCaptureBus.h>
 #include <Atom/Feature/Utils/FrameCaptureBus.h>
 #include <Atom/Feature/Utils/FrameCaptureBus.h>
-
+#include <Atom/Feature/Utils/FrameCaptureTestBus.h>
 
 
 namespace AZ
 namespace AZ
 {
 {
@@ -61,6 +61,9 @@ namespace ScriptAutomation
         void SetFrameCaptureId(AZ::Render::FrameCaptureId frameCaptureId) override;
         void SetFrameCaptureId(AZ::Render::FrameCaptureId frameCaptureId) override;
         void StartProfilingCapture() override;
         void StartProfilingCapture() override;
 
 
+        void ActivateScript(const char* scriptPath) override;
+        void DeactivateScripts() override;
+
     protected:
     protected:
         // AZ::Component implementation
         // AZ::Component implementation
         void Activate() override;
         void Activate() override;

+ 30 - 0
Gems/ScriptAutomation/Code/Tests/Scripts/screenshot_test.lua

@@ -0,0 +1,30 @@
+----------------------------------------------------------------------------------------------------
+--
+-- Copyright (c) Contributors to the Open 3D Engine Project.
+-- For complete copyright and license terms please see the LICENSE at the root of this distribution.
+--
+-- SPDX-License-Identifier: Apache-2.0 OR MIT
+--
+----------------------------------------------------------------------------------------------------
+
+ExecuteConsoleCommand("LoadLevel levels/defaultlevel/defaultlevel.spawnable")
+IdleSeconds(5) -- wait for the level to load
+
+g_screenshotOutputFolder = '@user@/Scripts/Screenshots/'
+testEnv = GetRenderApiName()
+
+SetScreenshotFolder(g_screenshotOutputFolder)
+SetTestEnvPath(testEnv)
+
+Print("Saving screenshots to " .. ResolvePath(g_screenshotOutputFolder .. testEnv))
+
+SetOfficialBaselineImageFolder(g_screenshotOutputFolder)
+SetLocalBaselineImageFolder(g_screenshotOutputFolder)
+
+ExecuteConsoleCommand("r_displayInfo=0")
+IdleFrames(1) -- wait 1 frame for the info text to hide
+
+CaptureScreenshot("screenshot_test.png")
+
+-- compare to itself as an example
+CompareScreenshots(g_screenshotOutputFolder .. testEnv .. "/screenshot_test.png", g_screenshotOutputFolder .. testEnv .. "/screenshot_test.png", 0.01)