TestRunner: detect netcoredbg process death (#308)
authorPavel Orekhov/Platform Lab /SRR/Staff Engineer/Samsung Electronics <p.orekhov@partner.samsung.com>
Wed, 11 Nov 2020 17:14:51 +0000 (20:14 +0300)
committerAlexander Soldatov/Platform Lab /SRR/Staff Engineer/Samsung Electronics <soldatov.a@samsung.com>
Wed, 11 Nov 2020 17:14:51 +0000 (20:14 +0300)
* TestRunner: detect netcoredbg process death

* fix #297
* fix Dispose LocalDebugger.Process on Ok termination
* fix run_tests.sh to kill Test process and another children
  on netcoredbg/TestRunner death
* add timeout feature to run_tests.sh like PR#279

* Fix Xunit testrunner (weak)

* fix #297 part 2
** fix timeout at run_tests.sh
** fix behaviour of xunit on test's death
* add a test to manual-assisted test unexpected death of process chain of a test

test-suite/LocalDebugger/LocalDebuggerProcess.cs
test-suite/VSCodeTest297killNCD/VSCodeTest297killNCD.csproj [new file with mode: 0644]
test-suite/VSCodeTest297killNCD/t297killNCD.cs [new file with mode: 0644]
test-suite/run_tests.ps1
test-suite/run_tests.sh
test-suite/test-suite.sln

index 894cb61490e0fc25b5ef3b5dc522413acec8d37b..81ca8ebb17b0e91af5b839688cedae8ff9c53977 100644 (file)
@@ -36,13 +36,13 @@ namespace LocalDebugger
 
         private void DebuggerProcess_Exited(object sender, System.EventArgs e)
         {
-            if (!CloseCalled)
+            if (!CloseCalled && DebuggerProcess.ExitCode != 0)
             {
                 //kill process of test, which is child of netcoredbg. It's PID I don't know
                 // For Win it works automatically (I hope). For linux it is going
                 // to be passed to run_tests.sh/timeout
-                System.Console.Error.WriteLine("TestRunner: netcoredbg is dead with exit code {0}.\n{1}",
-                    DebuggerProcess.ExitCode, e.ToString());
+                System.Console.Error.WriteLine("TestRunner: netcoredbg is dead with exit code {0}.",
+                    DebuggerProcess.ExitCode);
                 System.Environment.Exit(DebuggerProcess.ExitCode);
             }
         }
diff --git a/test-suite/VSCodeTest297killNCD/VSCodeTest297killNCD.csproj b/test-suite/VSCodeTest297killNCD/VSCodeTest297killNCD.csproj
new file mode 100644 (file)
index 0000000..e592a7e
--- /dev/null
@@ -0,0 +1,21 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <ItemGroup>
+    <ProjectReference Include="..\NetcoreDbgTest\NetcoreDbgTest.csproj" />
+    <ProjectReference Include="..\TestRunner\TestRunner.csproj" />
+  </ItemGroup>
+
+  <PropertyGroup>
+    <OutputType>Exe</OutputType>
+    <TargetFramework>netcoreapp3.1</TargetFramework>
+    <!--
+    -->
+    <EnableDefaultCompileItems>False</EnableDefaultCompileItems>
+  </PropertyGroup>
+
+
+  <ItemGroup>
+    <Compile Include="t297killNCD.cs" />
+  </ItemGroup>
+
+</Project>
diff --git a/test-suite/VSCodeTest297killNCD/t297killNCD.cs b/test-suite/VSCodeTest297killNCD/t297killNCD.cs
new file mode 100644 (file)
index 0000000..c4e59df
--- /dev/null
@@ -0,0 +1,208 @@
+using System;
+using System.IO;
+using System.Collections.Generic;
+
+using NetcoreDbgTest;
+using NetcoreDbgTest.VSCode;
+using NetcoreDbgTest.Script;
+
+using Xunit;
+using Newtonsoft.Json;
+
+namespace NetcoreDbgTest.Script
+{
+    // Context includes methods and constants which
+    // will be move to debugger API
+    class Context
+    {
+        public static void PrepareStart()
+        {
+            InitializeRequest initializeRequest = new InitializeRequest();
+            initializeRequest.arguments.clientID = "vscode";
+            initializeRequest.arguments.clientName = "Visual Studio Code";
+            initializeRequest.arguments.adapterID = "coreclr";
+            initializeRequest.arguments.pathFormat = "path";
+            initializeRequest.arguments.linesStartAt1 = true;
+            initializeRequest.arguments.columnsStartAt1 = true;
+            initializeRequest.arguments.supportsVariableType = true;
+            initializeRequest.arguments.supportsVariablePaging = true;
+            initializeRequest.arguments.supportsRunInTerminalRequest = true;
+            initializeRequest.arguments.locale = "en-us";
+            Assert.True(VSCodeDebugger.Request(initializeRequest).Success);
+
+            LaunchRequest launchRequest = new LaunchRequest();
+            launchRequest.arguments.name = ".NET Core Launch (console) with pipeline";
+            launchRequest.arguments.type = "coreclr";
+            launchRequest.arguments.preLaunchTask = "build";
+            launchRequest.arguments.program = DebuggeeInfo.TargetAssemblyPath;
+            launchRequest.arguments.cwd = "";
+            launchRequest.arguments.console = "internalConsole";
+            launchRequest.arguments.stopAtEntry = true;
+            launchRequest.arguments.internalConsoleOptions = "openOnSessionStart";
+            launchRequest.arguments.__sessionId = Guid.NewGuid().ToString();
+            Assert.True(VSCodeDebugger.Request(launchRequest).Success);
+        }
+
+        public static void PrepareEnd()
+        {
+            ConfigurationDoneRequest configurationDoneRequest = new ConfigurationDoneRequest();
+            Assert.True(VSCodeDebugger.Request(configurationDoneRequest).Success);
+        }
+
+        public static void WasEntryPointHit()
+        {
+            Func<string, bool> filter = (resJSON) => {
+                if (VSCodeDebugger.isResponseContainProperty(resJSON, "event", "stopped")
+                    && VSCodeDebugger.isResponseContainProperty(resJSON, "reason", "entry")) {
+                    threadId = Convert.ToInt32(VSCodeDebugger.GetResponsePropertyValue(resJSON, "threadId"));
+                    return true;
+                }
+                return false;
+            };
+
+            if (!VSCodeDebugger.IsEventReceived(filter))
+                throw new NetcoreDbgTestCore.ResultNotSuccessException();
+        }
+
+        public static void WasExit()
+        {
+            bool wasExited = false;
+            int ?exitCode = null;
+            bool wasTerminated = false;
+
+            Func<string, bool> filter = (resJSON) => {
+                if (VSCodeDebugger.isResponseContainProperty(resJSON, "event", "exited")) {
+                    wasExited = true;
+                    ExitedEvent exitedEvent = JsonConvert.DeserializeObject<ExitedEvent>(resJSON);
+                    exitCode = exitedEvent.body.exitCode;
+                }
+                if (VSCodeDebugger.isResponseContainProperty(resJSON, "event", "terminated")) {
+                    wasTerminated = true;
+                }
+                if (wasExited && exitCode == 0 && wasTerminated)
+                    return true;
+
+                return false;
+            };
+
+            if (!VSCodeDebugger.IsEventReceived(filter))
+                throw new NetcoreDbgTestCore.ResultNotSuccessException();
+        }
+
+        public static void DebuggerExit()
+        {
+            DisconnectRequest disconnectRequest = new DisconnectRequest();
+            disconnectRequest.arguments = new DisconnectArguments();
+            disconnectRequest.arguments.restart = false;
+            Assert.True(VSCodeDebugger.Request(disconnectRequest).Success);
+        }
+
+        public static void AddBreakpoint(string bpName, string Condition = null)
+        {
+            Breakpoint bp = DebuggeeInfo.Breakpoints[bpName];
+            Assert.Equal(BreakpointType.Line, bp.Type);
+            var lbp = (LineBreakpoint)bp;
+
+            BreakpointSourceName = lbp.FileName;
+            BreakpointList.Add(new SourceBreakpoint(lbp.NumLine, Condition));
+            BreakpointLines.Add(lbp.NumLine);
+        }
+
+        public static void SetBreakpoints()
+        {
+            SetBreakpointsRequest setBreakpointsRequest = new SetBreakpointsRequest();
+            setBreakpointsRequest.arguments.source.name = BreakpointSourceName;
+            // NOTE this code works only with one source file
+            setBreakpointsRequest.arguments.source.path = DebuggeeInfo.SourceFilesPath;
+            setBreakpointsRequest.arguments.lines.AddRange(BreakpointLines);
+            setBreakpointsRequest.arguments.breakpoints.AddRange(BreakpointList);
+            setBreakpointsRequest.arguments.sourceModified = false;
+            Assert.True(VSCodeDebugger.Request(setBreakpointsRequest).Success);
+        }
+
+        public static void WasBreakpointHit(Breakpoint breakpoint)
+        {
+            Func<string, bool> filter = (resJSON) => {
+                if (VSCodeDebugger.isResponseContainProperty(resJSON, "event", "stopped")
+                    && VSCodeDebugger.isResponseContainProperty(resJSON, "reason", "breakpoint")) {
+                    threadId = Convert.ToInt32(VSCodeDebugger.GetResponsePropertyValue(resJSON, "threadId"));
+                    return true;
+                }
+                return false;
+            };
+
+            if (!VSCodeDebugger.IsEventReceived(filter))
+                throw new NetcoreDbgTestCore.ResultNotSuccessException();
+
+            StackTraceRequest stackTraceRequest = new StackTraceRequest();
+            stackTraceRequest.arguments.threadId = threadId;
+            stackTraceRequest.arguments.startFrame = 0;
+            stackTraceRequest.arguments.levels = 20;
+            var ret = VSCodeDebugger.Request(stackTraceRequest);
+            Assert.True(ret.Success);
+
+            Assert.Equal(BreakpointType.Line, breakpoint.Type);
+            var lbp = (LineBreakpoint)breakpoint;
+
+            StackTraceResponse stackTraceResponse =
+                JsonConvert.DeserializeObject<StackTraceResponse>(ret.ResponseStr);
+
+            foreach (var Frame in stackTraceResponse.body.stackFrames) {
+                if (Frame.line == lbp.NumLine
+                    && Frame.source.name == lbp.FileName
+                    // NOTE this code works only with one source file
+                    && Frame.source.path == DebuggeeInfo.SourceFilesPath)
+                    return;
+            }
+
+            throw new NetcoreDbgTestCore.ResultNotSuccessException();
+        }
+
+        public static void Continue()
+        {
+            ContinueRequest continueRequest = new ContinueRequest();
+            continueRequest.arguments.threadId = threadId;
+            Assert.True(VSCodeDebugger.Request(continueRequest).Success);
+        }
+
+        static VSCodeDebugger VSCodeDebugger = new VSCodeDebugger();
+        static int threadId = -1;
+        public static string BreakpointSourceName;
+        public static List<SourceBreakpoint> BreakpointList = new List<SourceBreakpoint>();
+        public static List<int> BreakpointLines = new List<int>();
+    }
+}
+
+namespace VSCodeTest297killNCD
+{
+    class Program
+    {
+        static void Main(string[] args)
+        {
+            // first checkpoint (initialization) must provide "init" as id
+            Label.Checkpoint("init", "bp_test", () => {
+                Context.PrepareStart();
+                Context.AddBreakpoint("bp");
+                Context.SetBreakpoints();
+                Context.PrepareEnd();
+                Context.WasEntryPointHit();
+                Context.Continue();
+            });
+
+            Console.WriteLine("Pre delay"); 
+            System.Threading.Thread.Sleep(25000);
+            Console.WriteLine("Sleep done. A breakpoint \"bp\" is here"); Label.Breakpoint("bp");
+
+            Label.Checkpoint("bp_test", "finish", () => {
+                Context.WasBreakpointHit(DebuggeeInfo.Breakpoints["bp"]);
+                Context.Continue();
+            });
+
+            // last checkpoint must provide "finish" as id or empty string ("") as next checkpoint id
+            Label.Checkpoint("finish", "", () => {
+                Context.WasExit();
+                Context.DebuggerExit();
+            });
+        }
+    }
+}
index a17a3c8034075c97837736fe1d0b6d7147623c91..15e281f04aacf9994272950c573fb31be7705675 100644 (file)
@@ -39,6 +39,9 @@ $ALL_TEST_NAMES = @(
     "VSCodeTestSrcBreakpointResolve"
 )
 
+# Skipped tests:
+# VSCodeTest297killNCD --- is not automated enough. For manual run only.
+
 $TEST_NAMES = $args
 
 if ($NETCOREDBG.count -eq 0) {
index 3e6404826cf4461083eb5b4bf5cd838b65939f19..edc32553c69b08571b63c9e7aea15d93809dfacd 100755 (executable)
@@ -40,6 +40,9 @@ ALL_TEST_NAMES=(
     "VSCodeTestSrcBreakpointResolve"
 )
 
+# Skipped tests:
+# VSCodeTest297killNCD --- is not automated enough. For manual run only.
+
 TEST_NAMES="$@"
 
 if [[ -z $NETCOREDBG ]]; then
@@ -84,7 +87,7 @@ test_timeout()(
             sleep $1
             echo "task killed by timeout" >&2
             get_pgid() { set -- $(cat /proc/self/stat); echo $5; }
-            kill -ALRM -$pgid >/dev/null 2>&1
+            kill -ALRM -$(get_pgid) >/dev/null 2>&1
         } &
         shift
         $saved_errexit
index 9f1519f612cec7b0645d38aa0101a343892b480b..7ebb037072c1b98cccd513e71d5baaec71407160 100644 (file)
@@ -75,6 +75,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MITestSrcBreakpointResolve"
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VSCodeTestSrcBreakpointResolve", "VSCodeTestSrcBreakpointResolve\VSCodeTestSrcBreakpointResolve.csproj", "{C4B66CFD-47AA-4B41-BE26-B6FE2282FF09}"
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VSCodeTest297killNCD", "VSCodeTest297killNCD\VSCodeTest297killNCD.csproj", "{EE566D3A-1859-451F-AFCA-CFDC624B9E66}"
+EndProject
 Global
        GlobalSection(SolutionConfigurationPlatforms) = preSolution
                Debug|Any CPU = Debug|Any CPU
@@ -532,5 +534,17 @@ Global
                {C4B66CFD-47AA-4B41-BE26-B6FE2282FF09}.Release|x64.Build.0 = Release|Any CPU
                {C4B66CFD-47AA-4B41-BE26-B6FE2282FF09}.Release|x86.ActiveCfg = Release|Any CPU
                {C4B66CFD-47AA-4B41-BE26-B6FE2282FF09}.Release|x86.Build.0 = Release|Any CPU
+        {EE566D3A-1859-451F-AFCA-CFDC624B9E66}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+        {EE566D3A-1859-451F-AFCA-CFDC624B9E66}.Debug|Any CPU.Build.0 = Debug|Any CPU
+        {EE566D3A-1859-451F-AFCA-CFDC624B9E66}.Debug|x64.ActiveCfg = Debug|Any CPU
+        {EE566D3A-1859-451F-AFCA-CFDC624B9E66}.Debug|x64.Build.0 = Debug|Any CPU
+        {EE566D3A-1859-451F-AFCA-CFDC624B9E66}.Debug|x86.ActiveCfg = Debug|Any CPU
+        {EE566D3A-1859-451F-AFCA-CFDC624B9E66}.Debug|x86.Build.0 = Debug|Any CPU
+        {EE566D3A-1859-451F-AFCA-CFDC624B9E66}.Release|Any CPU.ActiveCfg = Release|Any CPU
+        {EE566D3A-1859-451F-AFCA-CFDC624B9E66}.Release|Any CPU.Build.0 = Release|Any CPU
+        {EE566D3A-1859-451F-AFCA-CFDC624B9E66}.Release|x64.ActiveCfg = Release|Any CPU
+        {EE566D3A-1859-451F-AFCA-CFDC624B9E66}.Release|x64.Build.0 = Release|Any CPU
+        {EE566D3A-1859-451F-AFCA-CFDC624B9E66}.Release|x86.ActiveCfg = Release|Any CPU
+        {EE566D3A-1859-451F-AFCA-CFDC624B9E66}.Release|x86.Build.0 = Release|Any CPU
        EndGlobalSection
 EndGlobal