summaryrefslogtreecommitdiff
path: root/src/ToolBox/SOS/tests
diff options
context:
space:
mode:
Diffstat (limited to 'src/ToolBox/SOS/tests')
-rw-r--r--src/ToolBox/SOS/tests/OnCrash.do2
-rw-r--r--src/ToolBox/SOS/tests/README.md43
-rw-r--r--src/ToolBox/SOS/tests/Test.cs94
-rw-r--r--src/ToolBox/SOS/tests/dumpil.py26
-rw-r--r--src/ToolBox/SOS/tests/dumpmodule.py26
-rw-r--r--src/ToolBox/SOS/tests/runprocess.py34
-rw-r--r--src/ToolBox/SOS/tests/t_cmd_bpmd_clear.py62
-rw-r--r--src/ToolBox/SOS/tests/t_cmd_bpmd_clearall.py62
-rw-r--r--src/ToolBox/SOS/tests/t_cmd_bpmd_methoddesc.py45
-rw-r--r--src/ToolBox/SOS/tests/t_cmd_bpmd_module_function.py43
-rw-r--r--src/ToolBox/SOS/tests/t_cmd_bpmd_module_function_iloffset.py43
-rw-r--r--src/ToolBox/SOS/tests/t_cmd_bpmd_nofuturemodule_module_function.py48
-rw-r--r--src/ToolBox/SOS/tests/t_cmd_clrstack.py36
-rw-r--r--src/ToolBox/SOS/tests/t_cmd_clrthreads.py31
-rw-r--r--src/ToolBox/SOS/tests/t_cmd_clru.py46
-rw-r--r--src/ToolBox/SOS/tests/t_cmd_dso.py31
-rw-r--r--src/ToolBox/SOS/tests/t_cmd_dumpclass.py68
-rw-r--r--src/ToolBox/SOS/tests/t_cmd_dumpheap.py31
-rw-r--r--src/ToolBox/SOS/tests/t_cmd_dumpil.py38
-rw-r--r--src/ToolBox/SOS/tests/t_cmd_dumplog.py31
-rw-r--r--src/ToolBox/SOS/tests/t_cmd_dumpmd.py46
-rw-r--r--src/ToolBox/SOS/tests/t_cmd_dumpmodule.py46
-rw-r--r--src/ToolBox/SOS/tests/t_cmd_dumpmt.py68
-rw-r--r--src/ToolBox/SOS/tests/t_cmd_dumpobj.py69
-rw-r--r--src/ToolBox/SOS/tests/t_cmd_dumpstack.py31
-rw-r--r--src/ToolBox/SOS/tests/t_cmd_eeheap.py31
-rw-r--r--src/ToolBox/SOS/tests/t_cmd_eestack.py31
-rw-r--r--src/ToolBox/SOS/tests/t_cmd_gcroot.py61
-rw-r--r--src/ToolBox/SOS/tests/t_cmd_histclear.py31
-rw-r--r--src/ToolBox/SOS/tests/t_cmd_histinit.py31
-rw-r--r--src/ToolBox/SOS/tests/t_cmd_histobj.py61
-rw-r--r--src/ToolBox/SOS/tests/t_cmd_histobjfind.py61
-rw-r--r--src/ToolBox/SOS/tests/t_cmd_histroot.py61
-rw-r--r--src/ToolBox/SOS/tests/t_cmd_ip2md.py53
-rw-r--r--src/ToolBox/SOS/tests/t_cmd_name2ee.py46
-rw-r--r--src/ToolBox/SOS/tests/t_cmd_pe.py28
-rw-r--r--src/ToolBox/SOS/tests/t_cmd_sos.py31
-rw-r--r--src/ToolBox/SOS/tests/t_cmd_soshelp.py31
-rw-r--r--src/ToolBox/SOS/tests/test_libsosplugin.py338
-rw-r--r--src/ToolBox/SOS/tests/testutils.py234
40 files changed, 2022 insertions, 207 deletions
diff --git a/src/ToolBox/SOS/tests/OnCrash.do b/src/ToolBox/SOS/tests/OnCrash.do
deleted file mode 100644
index b1da86154a..0000000000
--- a/src/ToolBox/SOS/tests/OnCrash.do
+++ /dev/null
@@ -1,2 +0,0 @@
-script open("/tmp/flag_fail", "a").close()
-q
diff --git a/src/ToolBox/SOS/tests/README.md b/src/ToolBox/SOS/tests/README.md
index ed4c8d062c..1b9c1eac29 100644
--- a/src/ToolBox/SOS/tests/README.md
+++ b/src/ToolBox/SOS/tests/README.md
@@ -1,18 +1,28 @@
Testing libsosplugin
=====================================
-**Test assembly**
-The test asembly file must follow two rules:
-1. the test class must be named `Program` and
-2. it must have a static `Main` method.
-
-**Running tests**
-Make sure that python's lldb module is accessible. To run the tests, use the following command:
-`python test_libsosplugin.py --clr-args="/path/to/corerun [corerun_options] /path/to/test_assembly.exe"`
-`--clr-args` is a command that would normally be used to launch `corerun`
-This will run the test suite on the specified assembly.
-
-**Writing tests**
+**Test assembly**
+Compile test assembly file using any C# compiler you have, for example:
+- `gmcs test.cs`
+- `corerun csc.exe /nologo /r:System.Private.CoreLib.dll test.cs`
+
+
+**Running tests**
+Make sure that python's lldb module is accessible. To run the tests, use the following command:
+`python2 test_libsosplugin.py --corerun=corerun --sosplugin=sosplugin --assembly=assembly --timeout=timeout`
+- `lldb` is a path to `lldb` to run
+- `clrdir` is a directory with `corerun` and sosplugin
+- `assembly` is a compiled test assembly (e.g. Test.exe)
+- `timeout` is a deadline for a single test (in seconds)
+- `regex` is a regular expression matching tests to run
+- `repeat` is a number of passes for each test
+
+
+
+Log files for both failed and passed tests are `*.log` and `*.log.2` for standard output and error correspondingly.
+
+
+**Writing tests**
Tests start with the `TestSosCommands` class defined in `test_libsosplugin.py`. To add a test to the suite, start with implementing a new method inside this class whose name begins with `test_`. Most new commands will require only one line of code in this method: `self.do_test("scenarioname")`. This command will launch a new `lldb` instance, which in turn will call the `runScenario` method from `scenarioname` module. `scenarioname` is the name of the python module that will be running the scenario inside `lldb` (found in `tests` folder alongside with `test_libsosplugin.py` and named `scenarioname.py`).
An example of a scenario looks like this:
@@ -25,9 +35,10 @@ An example of a scenario looks like this:
process.Continue()
return True
- `runScenario` method does all the work related to running the scenario: setting breakpoints, running SOS commands and examining their output. It should return a boolean value indicating a success or a failure.
+ `runScenario` method does all the work related to running the scenario: setting breakpoints, running SOS commands and examining their output. It should return a boolean value indicating a success or a failure.
***Note:*** `testutils.py` defines some useful commands that can be reused in many scenarios.
-**Useful links**
-[Python scripting in LLDB](http://lldb.llvm.org/python-reference.html)
-[Python unittest framework](https://docs.python.org/2.7/library/unittest.html) \ No newline at end of file
+
+**Useful links**
+[Python scripting in LLDB](http://lldb.llvm.org/python-reference.html)
+[Python unittest framework](https://docs.python.org/2.7/library/unittest.html)
diff --git a/src/ToolBox/SOS/tests/Test.cs b/src/ToolBox/SOS/tests/Test.cs
new file mode 100644
index 0000000000..e4ef76b30a
--- /dev/null
+++ b/src/ToolBox/SOS/tests/Test.cs
@@ -0,0 +1,94 @@
+using System;
+
+class Test
+{
+ static void LikelyInlined()
+ {
+ Console.WriteLine("I would like to be inlined");
+ }
+
+ static void UnlikelyInlined()
+ {
+ Console.Write("I");
+ Console.Write(" ");
+ Console.Write("w");
+ Console.Write("o");
+ Console.Write("u");
+ Console.Write("l");
+ Console.Write("d");
+ Console.Write(" ");
+ Console.Write("n");
+ Console.Write("o");
+ Console.Write("t");
+ Console.Write(" ");
+ Console.Write("l");
+ Console.Write("i");
+ Console.Write("k");
+ Console.Write("e");
+ Console.Write(" ");
+ Console.Write("t");
+ Console.Write("o");
+ Console.Write(" ");
+ Console.Write("b");
+ Console.Write("e");
+ Console.Write(" ");
+ Console.Write("i");
+ Console.Write("n");
+ Console.Write("l");
+ Console.Write("i");
+ Console.Write("n");
+ Console.Write("e");
+ Console.Write("d");
+ Console.Write("\n");
+ }
+
+ static void ClrU()
+ {
+ Console.WriteLine("test dumpclass");
+ }
+
+ static void DumpClass()
+ {
+ Console.WriteLine("test dumpclass");
+ }
+
+ static void DumpIL()
+ {
+ Console.WriteLine("test dumpil");
+ }
+
+ static void DumpMD()
+ {
+ Console.WriteLine("test dumpmd");
+ }
+
+ static void DumpModule()
+ {
+ Console.WriteLine("test dumpmodule");
+ }
+
+ static void DumpObject()
+ {
+ Console.WriteLine("test dumpobject");
+ }
+
+ static void DumpStackObjects()
+ {
+ Console.WriteLine("test dso");
+ }
+
+ static void Name2EE()
+ {
+ Console.WriteLine("test name2ee");
+ }
+
+
+ static int Main()
+ {
+ DumpIL();
+ LikelyInlined();
+ UnlikelyInlined();
+
+ return 0;
+ }
+}
diff --git a/src/ToolBox/SOS/tests/dumpil.py b/src/ToolBox/SOS/tests/dumpil.py
deleted file mode 100644
index 9539b618bb..0000000000
--- a/src/ToolBox/SOS/tests/dumpil.py
+++ /dev/null
@@ -1,26 +0,0 @@
-import lldb
-import lldbutil
-import re
-import os
-import testutils
-
-def runScenario(assemblyName, debugger, target):
- process = target.GetProcess()
- res = lldb.SBCommandReturnObject()
- ci = debugger.GetCommandInterpreter()
-
- testutils.stop_in_main(ci, process, assemblyName)
- addr = testutils.exec_and_find(ci, "name2ee " + assemblyName + " Program.Main", "MethodDesc:\s+([0-9a-fA-F]+)")
-
- result = False
- if addr is not None:
- ci.HandleCommand("dumpil " + addr, res)
- if res.Succeeded():
- result = True
- else:
- print("DumpIL failed:")
- print(res.GetOutput())
- print(res.GetError())
-
- process.Continue()
- return result
diff --git a/src/ToolBox/SOS/tests/dumpmodule.py b/src/ToolBox/SOS/tests/dumpmodule.py
deleted file mode 100644
index 04a5764752..0000000000
--- a/src/ToolBox/SOS/tests/dumpmodule.py
+++ /dev/null
@@ -1,26 +0,0 @@
-import lldb
-import lldbutil
-import re
-import os
-import testutils
-
-def runScenario(assemblyName, debugger, target):
- process = target.GetProcess()
- res = lldb.SBCommandReturnObject()
- ci = debugger.GetCommandInterpreter()
-
- testutils.stop_in_main(ci, process, assemblyName)
- addr = testutils.exec_and_find(ci, "name2ee " + assemblyName + " Program.Main", "Module:\s+([0-9a-fA-F]+)")
-
- result = False
- if addr is not None:
- ci.HandleCommand("dumpmodule " + addr, res)
- if res.Succeeded():
- result = True
- else:
- print("DumpModule failed:")
- print(res.GetOutput())
- print(res.GetError())
-
- process.Continue()
- return result \ No newline at end of file
diff --git a/src/ToolBox/SOS/tests/runprocess.py b/src/ToolBox/SOS/tests/runprocess.py
deleted file mode 100644
index d9367b3e6c..0000000000
--- a/src/ToolBox/SOS/tests/runprocess.py
+++ /dev/null
@@ -1,34 +0,0 @@
-import os
-import lldb
-import sys
-import importlib
-from test_libsosplugin import fail_flag
-
-def run(assemblyName, moduleName):
- global fail_flag
-
- print(fail_flag)
- # set the flag, if it is not set
- if not os.access(fail_flag, os.R_OK):
- open(fail_flag, "a").close()
-
-
- debugger = lldb.debugger
-
- debugger.SetAsync(False)
- target = lldb.target
-
- debugger.HandleCommand("process launch -s")
- debugger.HandleCommand("breakpoint set -n LoadLibraryExW")
-
- target.GetProcess().Continue()
-
- debugger.HandleCommand("breakpoint delete 1")
- #run the scenario
- print("starting scenario...")
- i = importlib.import_module(moduleName)
- scenarioResult = i.runScenario(os.path.basename(assemblyName), debugger, target)
-
- # clear the failed flag if the exit status is OK
- if scenarioResult is True and target.GetProcess().GetExitStatus() == 0:
- os.unlink(fail_flag)
diff --git a/src/ToolBox/SOS/tests/t_cmd_bpmd_clear.py b/src/ToolBox/SOS/tests/t_cmd_bpmd_clear.py
new file mode 100644
index 0000000000..814d114d16
--- /dev/null
+++ b/src/ToolBox/SOS/tests/t_cmd_bpmd_clear.py
@@ -0,0 +1,62 @@
+import lldb
+import re
+import testutils as test
+
+# bpmd -clearall
+
+
+def runScenario(assembly, debugger, target):
+ process = target.GetProcess()
+ res = lldb.SBCommandReturnObject()
+ ci = debugger.GetCommandInterpreter()
+
+ # Run debugger, wait until libcoreclr is loaded,
+ # set breakpoint at Test.Main and stop there
+ test.stop_in_main(debugger, assembly)
+
+ # Set breakpoint
+
+ ci.HandleCommand("bpmd " + assembly + " Test.UnlikelyInlined", res)
+ out_msg = res.GetOutput()
+ err_msg = res.GetError()
+ print(out_msg)
+ print(err_msg)
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ # Output is not empty
+ # Should be at least 'Adding pending breakpoints...'
+ test.assertTrue(len(out_msg) > 0)
+
+ # Error message is empty
+ test.assertTrue(len(err_msg) == 0)
+
+ # Delete the first breakpoint
+
+ ci.HandleCommand("bpmd -clear 1", res)
+ out_msg = res.GetOutput()
+ err_msg = res.GetError()
+ print(out_msg)
+ print(err_msg)
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ match = re.search('Cleared', out_msg)
+ # Check for specific output
+ test.assertTrue(match)
+
+ # Error message is empty
+ test.assertEqual(err_msg, '')
+
+ process.Continue()
+ # Process must be exited
+ test.assertEqual(process.GetState(), lldb.eStateExited)
+
+ # The reason of this stop must be a breakpoint
+ test.assertEqual(process.GetSelectedThread().GetStopReason(),
+ lldb.eStopReasonNone)
+
+ #
+
+ # Delete all breakpoints, continue current process and checks its exit code
+ test.exit_lldb(debugger, assembly)
diff --git a/src/ToolBox/SOS/tests/t_cmd_bpmd_clearall.py b/src/ToolBox/SOS/tests/t_cmd_bpmd_clearall.py
new file mode 100644
index 0000000000..8da9239f57
--- /dev/null
+++ b/src/ToolBox/SOS/tests/t_cmd_bpmd_clearall.py
@@ -0,0 +1,62 @@
+import lldb
+import re
+import testutils as test
+
+# bpmd -clearall
+
+
+def runScenario(assembly, debugger, target):
+ process = target.GetProcess()
+ res = lldb.SBCommandReturnObject()
+ ci = debugger.GetCommandInterpreter()
+
+ # Run debugger, wait until libcoreclr is loaded,
+ # set breakpoint at Test.Main and stop there
+ test.stop_in_main(debugger, assembly)
+
+ # Set breakpoint
+
+ ci.HandleCommand("bpmd " + assembly + " Test.UnlikelyInlined", res)
+ out_msg = res.GetOutput()
+ err_msg = res.GetError()
+ print(out_msg)
+ print(err_msg)
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ # Output is not empty
+ # Should be at least 'Adding pending breakpoints...'
+ test.assertTrue(len(out_msg) > 0)
+
+ # Error message is empty
+ test.assertTrue(len(err_msg) == 0)
+
+ # Delete all breakpoints
+
+ ci.HandleCommand("bpmd -clearall", res)
+ out_msg = res.GetOutput()
+ err_msg = res.GetError()
+ print(out_msg)
+ print(err_msg)
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ match = re.search('All pending breakpoints cleared.', out_msg)
+ # Check for specific output
+ test.assertTrue(match)
+
+ # Error message is empty
+ test.assertEqual(err_msg, '')
+
+ process.Continue()
+ # Process must be exited
+ test.assertEqual(process.GetState(), lldb.eStateExited)
+
+ # The reason of this stop must be a breakpoint
+ test.assertEqual(process.GetSelectedThread().GetStopReason(),
+ lldb.eStopReasonNone)
+
+ #
+
+ # Delete all breakpoints, continue current process and checks its exit code
+ test.exit_lldb(debugger, assembly)
diff --git a/src/ToolBox/SOS/tests/t_cmd_bpmd_methoddesc.py b/src/ToolBox/SOS/tests/t_cmd_bpmd_methoddesc.py
new file mode 100644
index 0000000000..dfd75432f3
--- /dev/null
+++ b/src/ToolBox/SOS/tests/t_cmd_bpmd_methoddesc.py
@@ -0,0 +1,45 @@
+import lldb
+import re
+import testutils as test
+
+# bpmd -md <MethodDesc pointer>
+
+
+def runScenario(assembly, debugger, target):
+ process = target.GetProcess()
+ res = lldb.SBCommandReturnObject()
+ ci = debugger.GetCommandInterpreter()
+
+ # Run debugger, wait until libcoreclr is loaded,
+ # set breakpoint at Test.Main and stop there
+ test.stop_in_main(debugger, assembly)
+
+ md_addr = test.get_methoddesc(debugger, assembly, "Test.UnlikelyInlined")
+
+ ci.HandleCommand("bpmd -md %s" % md_addr, res)
+ out_msg = res.GetOutput()
+ err_msg = res.GetError()
+ print(out_msg)
+ print(err_msg)
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ # Output is not empty
+ # Should be at least 'Adding pending breakpoints...'
+ test.assertTrue(len(out_msg) > 0)
+
+ # Error message is empty
+ test.assertTrue(len(err_msg) == 0)
+
+ process.Continue()
+ # Process must be stopped at UnlinkelyInlined
+ test.assertEqual(process.GetState(), lldb.eStateStopped)
+
+ # The reason of this stop must be a breakpoint
+ test.assertEqual(process.GetSelectedThread().GetStopReason(),
+ lldb.eStopReasonBreakpoint)
+
+ #
+
+ # Continue current process and checks its exit code
+ test.exit_lldb(debugger, assembly)
diff --git a/src/ToolBox/SOS/tests/t_cmd_bpmd_module_function.py b/src/ToolBox/SOS/tests/t_cmd_bpmd_module_function.py
new file mode 100644
index 0000000000..e407ab3e4e
--- /dev/null
+++ b/src/ToolBox/SOS/tests/t_cmd_bpmd_module_function.py
@@ -0,0 +1,43 @@
+import lldb
+import re
+import testutils as test
+
+# bpmd <module name> <managed function name>
+
+
+def runScenario(assembly, debugger, target):
+ process = target.GetProcess()
+ res = lldb.SBCommandReturnObject()
+ ci = debugger.GetCommandInterpreter()
+
+ # Run debugger, wait until libcoreclr is loaded,
+ # set breakpoint at Test.Main and stop there
+ test.stop_in_main(debugger, assembly)
+
+ ci.HandleCommand("bpmd " + assembly + " Test.UnlikelyInlined", res)
+ out_msg = res.GetOutput()
+ err_msg = res.GetError()
+ print(out_msg)
+ print(err_msg)
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ # Output is not empty
+ # Should be at least 'Adding pending breakpoints...'
+ test.assertTrue(len(out_msg) > 0)
+
+ # Error message is empty
+ test.assertTrue(len(err_msg) == 0)
+
+ process.Continue()
+ # Process must be stopped at UnlinkelyInlined
+ test.assertEqual(process.GetState(), lldb.eStateStopped)
+
+ # The reason of this stop must be a breakpoint
+ test.assertEqual(process.GetSelectedThread().GetStopReason(),
+ lldb.eStopReasonBreakpoint)
+
+ #
+
+ # Delete all breakpoints, continue current process and checks its exit code
+ test.exit_lldb(debugger, assembly)
diff --git a/src/ToolBox/SOS/tests/t_cmd_bpmd_module_function_iloffset.py b/src/ToolBox/SOS/tests/t_cmd_bpmd_module_function_iloffset.py
new file mode 100644
index 0000000000..91fb1cd125
--- /dev/null
+++ b/src/ToolBox/SOS/tests/t_cmd_bpmd_module_function_iloffset.py
@@ -0,0 +1,43 @@
+import lldb
+import re
+import testutils as test
+
+# bpmd <module name> <managed function name> [<il offset>]
+
+
+def runScenario(assembly, debugger, target):
+ process = target.GetProcess()
+ res = lldb.SBCommandReturnObject()
+ ci = debugger.GetCommandInterpreter()
+
+ # Run debugger, wait until libcoreclr is loaded,
+ # set breakpoint at Test.Main and stop there
+ test.stop_in_main(debugger, assembly)
+
+ ci.HandleCommand("bpmd " + assembly + " Test.UnlikelyInlined 66", res)
+ out_msg = res.GetOutput()
+ err_msg = res.GetError()
+ print(out_msg)
+ print(err_msg)
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ # Output is not empty
+ # Should be at least 'Adding pending breakpoints...'
+ test.assertTrue(len(out_msg) > 0)
+
+ # Error message is empty
+ test.assertTrue(len(err_msg) == 0)
+
+ process.Continue()
+ # Process must be stopped at UnlinkelyInlined
+ test.assertEqual(process.GetState(), lldb.eStateStopped)
+
+ # The reason of this stop must be a breakpoint
+ test.assertEqual(process.GetSelectedThread().GetStopReason(),
+ lldb.eStopReasonBreakpoint)
+
+ #
+
+ # Delete all breakpoints, continue current process and checks its exit code
+ test.exit_lldb(debugger, assembly)
diff --git a/src/ToolBox/SOS/tests/t_cmd_bpmd_nofuturemodule_module_function.py b/src/ToolBox/SOS/tests/t_cmd_bpmd_nofuturemodule_module_function.py
new file mode 100644
index 0000000000..64efad7b65
--- /dev/null
+++ b/src/ToolBox/SOS/tests/t_cmd_bpmd_nofuturemodule_module_function.py
@@ -0,0 +1,48 @@
+import lldb
+import re
+import testutils as test
+
+# bpmd -nofuturemodule <module name> <managed function name>
+
+
+def runScenario(assembly, debugger, target):
+ process = target.GetProcess()
+ res = lldb.SBCommandReturnObject()
+ ci = debugger.GetCommandInterpreter()
+
+ # Process must be stopped here while libcoreclr loading.
+ # This test usually fails on release version of coreclr
+ # since we depend on 'LoadLibraryExW' symbol present.
+ test.assertEqual(process.GetState(), lldb.eStateStopped)
+
+ # The reason of this stop must be a breakpoint
+ test.assertEqual(process.GetSelectedThread().GetStopReason(),
+ lldb.eStopReasonBreakpoint)
+
+ ci.HandleCommand("bpmd -nofuturemodule " + assembly + " Test.Main", res)
+ out_msg = res.GetOutput()
+ err_msg = res.GetError()
+ print(out_msg)
+ print(err_msg)
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ # Output is not empty
+ # Should be at least 'Adding pending breakpoints...'
+ test.assertTrue(len(out_msg) == 0)
+
+ # Error message is empty
+ test.assertTrue(len(err_msg) == 0)
+
+ process.Continue()
+ # Process must be exited because of -nofuturemodule flag
+ test.assertEqual(process.GetState(), lldb.eStateExited)
+
+ # The reason of this stop must be a breakpoint
+ test.assertEqual(process.GetSelectedThread().GetStopReason(),
+ lldb.eStopReasonNone)
+
+ #
+
+ # Delete all breakpoints, continue current process and checks its exit code
+ test.exit_lldb(debugger, assembly)
diff --git a/src/ToolBox/SOS/tests/t_cmd_clrstack.py b/src/ToolBox/SOS/tests/t_cmd_clrstack.py
new file mode 100644
index 0000000000..28a1a8b950
--- /dev/null
+++ b/src/ToolBox/SOS/tests/t_cmd_clrstack.py
@@ -0,0 +1,36 @@
+import lldb
+import re
+import testutils as test
+
+
+def runScenario(assembly, debugger, target):
+ process = target.GetProcess()
+ res = lldb.SBCommandReturnObject()
+ ci = debugger.GetCommandInterpreter()
+
+ # Run debugger, wait until libcoreclr is loaded,
+ # set breakpoint at Test.Main and stop there
+ test.stop_in_main(debugger, assembly)
+
+ ci.HandleCommand("clrstack", res)
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ output = res.GetOutput()
+ # Output is not empty
+ test.assertTrue(len(output) > 0)
+
+ match = re.search('OS Thread Id', output)
+ # Specific string must be in the output
+ test.assertTrue(match)
+
+ match = re.search('Failed to start', output)
+ # Check if a fail was reported
+ test.assertFalse(match)
+
+ # TODO: test other use cases
+
+ # Continue current process and checks its exit code
+ test.exit_lldb(debugger, assembly)
diff --git a/src/ToolBox/SOS/tests/t_cmd_clrthreads.py b/src/ToolBox/SOS/tests/t_cmd_clrthreads.py
new file mode 100644
index 0000000000..ff731da990
--- /dev/null
+++ b/src/ToolBox/SOS/tests/t_cmd_clrthreads.py
@@ -0,0 +1,31 @@
+import lldb
+import re
+import testutils as test
+
+
+def runScenario(assembly, debugger, target):
+ process = target.GetProcess()
+ res = lldb.SBCommandReturnObject()
+ ci = debugger.GetCommandInterpreter()
+
+ # Run debugger, wait until libcoreclr is loaded,
+ # set breakpoint at Test.Main and stop there
+ test.stop_in_main(debugger, assembly)
+
+ ci.HandleCommand("clrthreads", res)
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ output = res.GetOutput()
+ # Output is not empty
+ test.assertTrue(len(output) > 0)
+
+ # Specific string must be in the output
+ test.assertNotEqual(output.find("ThreadCount:"), -1)
+
+ # TODO: test other use cases
+
+ # Continue current process and checks its exit code
+ test.exit_lldb(debugger, assembly)
diff --git a/src/ToolBox/SOS/tests/t_cmd_clru.py b/src/ToolBox/SOS/tests/t_cmd_clru.py
new file mode 100644
index 0000000000..81a583e963
--- /dev/null
+++ b/src/ToolBox/SOS/tests/t_cmd_clru.py
@@ -0,0 +1,46 @@
+import lldb
+import re
+import testutils as test
+
+
+def runScenario(assembly, debugger, target):
+ process = target.GetProcess()
+ res = lldb.SBCommandReturnObject()
+ ci = debugger.GetCommandInterpreter()
+
+ # Run debugger, wait until libcoreclr is loaded,
+ # set breakpoint at Test.Main and stop there
+ test.stop_in_main(debugger, assembly)
+
+ ci.HandleCommand("name2ee " + assembly + " Test.Main", res)
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ output = res.GetOutput()
+ # Output is not empty
+ test.assertTrue(len(output) > 0)
+
+ match = re.search('JITTED Code Address:\s+([0-9a-fA-F]+)', output)
+ # Line matched
+ test.assertTrue(match)
+
+ groups = match.groups()
+ # Match has a single subgroup
+ test.assertEqual(len(groups), 1)
+
+ jit_addr = groups[0]
+ # Address must be a hex number
+ test.assertTrue(test.is_hexnum(jit_addr))
+
+ ci.HandleCommand("clru " + jit_addr, res)
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ # TODO: test other use cases
+
+ # Continue current process and checks its exit code
+ test.exit_lldb(debugger, assembly)
diff --git a/src/ToolBox/SOS/tests/t_cmd_dso.py b/src/ToolBox/SOS/tests/t_cmd_dso.py
new file mode 100644
index 0000000000..492204da5e
--- /dev/null
+++ b/src/ToolBox/SOS/tests/t_cmd_dso.py
@@ -0,0 +1,31 @@
+import lldb
+import re
+import testutils as test
+
+
+def runScenario(assembly, debugger, target):
+ process = target.GetProcess()
+ res = lldb.SBCommandReturnObject()
+ ci = debugger.GetCommandInterpreter()
+
+ # Run debugger, wait until libcoreclr is loaded,
+ # set breakpoint at Test.Main and stop there
+ test.stop_in_main(debugger, assembly)
+
+ ci.HandleCommand("dso", res)
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ output = res.GetOutput()
+ # Output is not empty
+ test.assertTrue(len(output) > 0)
+
+ # Specific string must be in the output
+ test.assertNotEqual(output.find("SP/REG"), -1)
+
+ # TODO: test other use cases
+
+ # Continue current process and checks its exit code
+ test.exit_lldb(debugger, assembly)
diff --git a/src/ToolBox/SOS/tests/t_cmd_dumpclass.py b/src/ToolBox/SOS/tests/t_cmd_dumpclass.py
new file mode 100644
index 0000000000..6a69070eb5
--- /dev/null
+++ b/src/ToolBox/SOS/tests/t_cmd_dumpclass.py
@@ -0,0 +1,68 @@
+import lldb
+import re
+import testutils as test
+
+
+def runScenario(assembly, debugger, target):
+ process = target.GetProcess()
+ res = lldb.SBCommandReturnObject()
+ ci = debugger.GetCommandInterpreter()
+
+ # Run debugger, wait until libcoreclr is loaded,
+ # set breakpoint at Test.Main and stop there
+ test.stop_in_main(debugger, assembly)
+
+ ci.HandleCommand("name2ee " + assembly + " Test.Main", res)
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ output = res.GetOutput()
+ # Output is not empty
+ test.assertTrue(len(output) > 0)
+
+ match = re.search('MethodDesc:\s+([0-9a-fA-F]+)', output)
+ # Line matched
+ test.assertTrue(match)
+
+ groups = match.groups()
+ # Match has a single subgroup
+ test.assertEqual(len(groups), 1)
+
+ md_addr = groups[0]
+ # Address must be a hex number
+ test.assertTrue(test.is_hexnum(md_addr))
+
+ ci.HandleCommand("dumpmd " + md_addr, res)
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ output = res.GetOutput()
+ # Output is not empty
+ test.assertTrue(len(output) > 0)
+
+ match = re.search('Class:\s+([0-9a-fA-F]+)', output)
+ # Line matched
+ test.assertTrue(match)
+
+ groups = match.groups()
+ # Match has a single subgroup
+ test.assertEqual(len(groups), 1)
+
+ class_addr = groups[0]
+ # Address must be a hex number
+ test.assertTrue(test.is_hexnum(class_addr))
+
+ ci.HandleCommand("dumpmd " + class_addr, res)
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ # TODO: test other use cases
+
+ # Continue current process and checks its exit code
+ test.exit_lldb(debugger, assembly)
diff --git a/src/ToolBox/SOS/tests/t_cmd_dumpheap.py b/src/ToolBox/SOS/tests/t_cmd_dumpheap.py
new file mode 100644
index 0000000000..8546de79e1
--- /dev/null
+++ b/src/ToolBox/SOS/tests/t_cmd_dumpheap.py
@@ -0,0 +1,31 @@
+import lldb
+import re
+import testutils as test
+
+
+def runScenario(assembly, debugger, target):
+ process = target.GetProcess()
+ res = lldb.SBCommandReturnObject()
+ ci = debugger.GetCommandInterpreter()
+
+ # Run debugger, wait until libcoreclr is loaded,
+ # set breakpoint at Test.Main and stop there
+ test.stop_in_main(debugger, assembly)
+
+ ci.HandleCommand("dumpheap", res)
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ output = res.GetOutput()
+ # Output is not empty
+ test.assertTrue(len(output) > 0)
+
+ # Specific string must be in the output
+ test.assertNotEqual(output.find("Address"), -1)
+
+ # TODO: test other use cases
+
+ # Continue current process and checks its exit code
+ test.exit_lldb(debugger, assembly)
diff --git a/src/ToolBox/SOS/tests/t_cmd_dumpil.py b/src/ToolBox/SOS/tests/t_cmd_dumpil.py
new file mode 100644
index 0000000000..295cf19e6f
--- /dev/null
+++ b/src/ToolBox/SOS/tests/t_cmd_dumpil.py
@@ -0,0 +1,38 @@
+import lldb
+import re
+import testutils as test
+
+
+def runScenario(assembly, debugger, target):
+ process = target.GetProcess()
+ res = lldb.SBCommandReturnObject()
+ ci = debugger.GetCommandInterpreter()
+
+ # Run debugger, wait until libcoreclr is loaded,
+ # set breakpoint at Test.Main and stop there
+ test.stop_in_main(debugger, assembly)
+
+ md_addr = test.get_methoddesc(debugger, assembly, "Test.DumpIL")
+
+ ci.HandleCommand("dumpil " + md_addr, res)
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ insts = res.GetOutput()
+ print(insts)
+ # Function must have some instructions
+ test.assertTrue(len(insts) > 0)
+
+ match = re.search(r'IL_\w{4}:\sldstr.*test\sdumpil.*' +
+ r'IL_\w{4}:\scall.*System\.Console::WriteLine.*' +
+ r'IL_\w{4}:\sret',
+ insts.replace('\n', ' '))
+ # Must have ldstr, call and ret instructions
+ test.assertTrue(match)
+
+ # TODO: test other use cases
+
+ # Continue current process and checks its exit code
+ test.exit_lldb(debugger, assembly)
diff --git a/src/ToolBox/SOS/tests/t_cmd_dumplog.py b/src/ToolBox/SOS/tests/t_cmd_dumplog.py
new file mode 100644
index 0000000000..ab33b66d4b
--- /dev/null
+++ b/src/ToolBox/SOS/tests/t_cmd_dumplog.py
@@ -0,0 +1,31 @@
+import lldb
+import re
+import testutils as test
+
+
+def runScenario(assembly, debugger, target):
+ process = target.GetProcess()
+ res = lldb.SBCommandReturnObject()
+ ci = debugger.GetCommandInterpreter()
+
+ # Run debugger, wait until libcoreclr is loaded,
+ # set breakpoint at Test.Main and stop there
+ test.stop_in_main(debugger, assembly)
+
+ ci.HandleCommand("dumplog", res)
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ output = res.GetOutput()
+ # Output is not empty
+ test.assertTrue(len(output) > 0)
+
+ # Specific string must be in the output
+ test.assertNotEqual(output.find(" dump "), -1)
+
+ # TODO: test other use cases
+
+ # Continue current process and checks its exit code
+ test.exit_lldb(debugger, assembly)
diff --git a/src/ToolBox/SOS/tests/t_cmd_dumpmd.py b/src/ToolBox/SOS/tests/t_cmd_dumpmd.py
new file mode 100644
index 0000000000..0340eb5222
--- /dev/null
+++ b/src/ToolBox/SOS/tests/t_cmd_dumpmd.py
@@ -0,0 +1,46 @@
+import lldb
+import re
+import testutils as test
+
+
+def runScenario(assembly, debugger, target):
+ process = target.GetProcess()
+ res = lldb.SBCommandReturnObject()
+ ci = debugger.GetCommandInterpreter()
+
+ # Run debugger, wait until libcoreclr is loaded,
+ # set breakpoint at Test.Main and stop there
+ test.stop_in_main(debugger, assembly)
+
+ ci.HandleCommand("name2ee " + assembly + " Test.Main", res)
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ output = res.GetOutput()
+ # Output is not empty
+ test.assertTrue(len(output) > 0)
+
+ match = re.search('MethodDesc:\s+([0-9a-fA-F]+)', output)
+ # Line matched
+ test.assertTrue(match)
+
+ groups = match.groups()
+ # Match has a single subgroup
+ test.assertEqual(len(groups), 1)
+
+ md_addr = groups[0]
+ # Address must be a hex number
+ test.assertTrue(test.is_hexnum(md_addr))
+
+ ci.HandleCommand("dumpmd " + md_addr, res)
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ # TODO: test other use cases
+
+ # Continue current process and checks its exit code
+ test.exit_lldb(debugger, assembly)
diff --git a/src/ToolBox/SOS/tests/t_cmd_dumpmodule.py b/src/ToolBox/SOS/tests/t_cmd_dumpmodule.py
new file mode 100644
index 0000000000..2dd004818a
--- /dev/null
+++ b/src/ToolBox/SOS/tests/t_cmd_dumpmodule.py
@@ -0,0 +1,46 @@
+import lldb
+import re
+import testutils as test
+
+
+def runScenario(assembly, debugger, target):
+ process = target.GetProcess()
+ res = lldb.SBCommandReturnObject()
+ ci = debugger.GetCommandInterpreter()
+
+ # Run debugger, wait until libcoreclr is loaded,
+ # set breakpoint at Test.Main and stop there
+ test.stop_in_main(debugger, assembly)
+
+ ci.HandleCommand("name2ee " + assembly + " Test.Main", res)
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ output = res.GetOutput()
+ # Output is not empty
+ test.assertTrue(len(output) > 0)
+
+ match = re.search('Module:\s+([0-9a-fA-F]+)', output)
+ # Line matched
+ test.assertTrue(match)
+
+ groups = match.groups()
+ # Match has a single subgroup
+ test.assertEqual(len(groups), 1)
+
+ md_addr = groups[0]
+ # Address must be a hex number
+ test.assertTrue(test.is_hexnum(md_addr))
+
+ ci.HandleCommand("dumpmodule " + md_addr, res)
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ # TODO: test other use cases
+
+ # Continue current process and checks its exit code
+ test.exit_lldb(debugger, assembly)
diff --git a/src/ToolBox/SOS/tests/t_cmd_dumpmt.py b/src/ToolBox/SOS/tests/t_cmd_dumpmt.py
new file mode 100644
index 0000000000..059060b9b4
--- /dev/null
+++ b/src/ToolBox/SOS/tests/t_cmd_dumpmt.py
@@ -0,0 +1,68 @@
+import lldb
+import re
+import testutils as test
+
+
+def runScenario(assembly, debugger, target):
+ process = target.GetProcess()
+ res = lldb.SBCommandReturnObject()
+ ci = debugger.GetCommandInterpreter()
+
+ # Run debugger, wait until libcoreclr is loaded,
+ # set breakpoint at Test.Main and stop there
+ test.stop_in_main(debugger, assembly)
+
+ ci.HandleCommand("name2ee " + assembly + " Test.Main", res)
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ output = res.GetOutput()
+ # Output is not empty
+ test.assertTrue(len(output) > 0)
+
+ match = re.search('MethodDesc:\s+([0-9a-fA-F]+)', output)
+ # Line matched
+ test.assertTrue(match)
+
+ groups = match.groups()
+ # Match has a single subgroup
+ test.assertEqual(len(groups), 1)
+
+ md_addr = groups[0]
+ # Address must be a hex number
+ test.assertTrue(test.is_hexnum(md_addr))
+
+ ci.HandleCommand("dumpmd " + md_addr, res)
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ output = res.GetOutput()
+ # Output is not empty
+ test.assertTrue(len(output) > 0)
+
+ match = re.search('MethodTable:\s+([0-9a-fA-F]+)', output)
+ # Line matched
+ test.assertTrue(match)
+
+ groups = match.groups()
+ # Match has a single subgroup
+ test.assertEqual(len(groups), 1)
+
+ mt_addr = groups[0]
+ # Address must be a hex number
+ test.assertTrue(test.is_hexnum(mt_addr))
+
+ ci.HandleCommand("dumpmt " + mt_addr, res)
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ # TODO: test other use cases
+
+ # Continue current process and checks its exit code
+ test.exit_lldb(debugger, assembly)
diff --git a/src/ToolBox/SOS/tests/t_cmd_dumpobj.py b/src/ToolBox/SOS/tests/t_cmd_dumpobj.py
new file mode 100644
index 0000000000..93f32cd9ab
--- /dev/null
+++ b/src/ToolBox/SOS/tests/t_cmd_dumpobj.py
@@ -0,0 +1,69 @@
+import lldb
+import re
+import testutils as test
+
+
+def runScenario(assembly, debugger, target):
+ process = target.GetProcess()
+ res = lldb.SBCommandReturnObject()
+ ci = debugger.GetCommandInterpreter()
+
+ # Run debugger, wait until libcoreclr is loaded,
+ # set breakpoint at Test.Main and stop there
+ test.stop_in_main(debugger, assembly)
+
+ ci.HandleCommand("dso", res)
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ output = res.GetOutput()
+ # Output is not empty
+ test.assertTrue(len(output) > 0)
+
+ # Get all objects
+ objects = []
+ for line in output.split('\n'):
+ match = re.match('([0-9a-fA-F]+)\s+([0-9a-fA-F]+)\s', line)
+ # Not all lines list objects
+ if match:
+ groups = match.groups()
+ # Match has exactly two subgroups
+ test.assertEqual(len(groups), 2)
+
+ obj_addr = groups[1]
+ # Address must be a hex number
+ test.assertTrue(test.is_hexnum(obj_addr))
+
+ objects.append(obj_addr)
+
+ # There must be at least one object
+ test.assertTrue(len(objects) > 0)
+
+ for obj in objects:
+ ci.HandleCommand("dumpobj " + obj, res)
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ output = res.GetOutput()
+ # Output is not empty
+ test.assertTrue(len(output) > 0)
+
+ match = re.search('Name:\s+\S+', output)
+ test.assertTrue(match)
+ match = re.search('MethodTable:\s+[0-9a-fA-F]+', output)
+ test.assertTrue(match)
+ match = re.search('EEClass:\s+[0-9a-fA-F]+', output)
+ test.assertTrue(match)
+ match = re.search('Size:\s+[0-9a-fA-F]+', output)
+ test.assertTrue(match)
+ match = re.search('Fields:', output)
+ test.assertTrue(match)
+
+ # TODO: test other use cases
+
+ # Continue current process and checks its exit code
+ test.exit_lldb(debugger, assembly)
diff --git a/src/ToolBox/SOS/tests/t_cmd_dumpstack.py b/src/ToolBox/SOS/tests/t_cmd_dumpstack.py
new file mode 100644
index 0000000000..3e15f8b1d9
--- /dev/null
+++ b/src/ToolBox/SOS/tests/t_cmd_dumpstack.py
@@ -0,0 +1,31 @@
+import lldb
+import re
+import testutils as test
+
+
+def runScenario(assembly, debugger, target):
+ process = target.GetProcess()
+ res = lldb.SBCommandReturnObject()
+ ci = debugger.GetCommandInterpreter()
+
+ # Run debugger, wait until libcoreclr is loaded,
+ # set breakpoint at Test.Main and stop there
+ test.stop_in_main(debugger, assembly)
+
+ ci.HandleCommand("dumpstack", res)
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ output = res.GetOutput()
+ # Output is not empty
+ test.assertTrue(len(output) > 0)
+
+ # Specific string must be in the output
+ test.assertNotEqual(output.find("Test.Main()"), -1)
+
+ # TODO: test other use cases
+
+ # Continue current process and checks its exit code
+ test.exit_lldb(debugger, assembly)
diff --git a/src/ToolBox/SOS/tests/t_cmd_eeheap.py b/src/ToolBox/SOS/tests/t_cmd_eeheap.py
new file mode 100644
index 0000000000..50d8977422
--- /dev/null
+++ b/src/ToolBox/SOS/tests/t_cmd_eeheap.py
@@ -0,0 +1,31 @@
+import lldb
+import re
+import testutils as test
+
+
+def runScenario(assembly, debugger, target):
+ process = target.GetProcess()
+ res = lldb.SBCommandReturnObject()
+ ci = debugger.GetCommandInterpreter()
+
+ # Run debugger, wait until libcoreclr is loaded,
+ # set breakpoint at Test.Main and stop there
+ test.stop_in_main(debugger, assembly)
+
+ ci.HandleCommand("eeheap", res)
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ output = res.GetOutput()
+ # Output is not empty
+ test.assertTrue(len(output) > 0)
+
+ # Specific string must be in the output
+ test.assertNotEqual(output.find("Loader Heap"), -1)
+
+ # TODO: test other use cases
+
+ # Continue current process and checks its exit code
+ test.exit_lldb(debugger, assembly)
diff --git a/src/ToolBox/SOS/tests/t_cmd_eestack.py b/src/ToolBox/SOS/tests/t_cmd_eestack.py
new file mode 100644
index 0000000000..bc36592f87
--- /dev/null
+++ b/src/ToolBox/SOS/tests/t_cmd_eestack.py
@@ -0,0 +1,31 @@
+import lldb
+import re
+import testutils as test
+
+
+def runScenario(assembly, debugger, target):
+ process = target.GetProcess()
+ res = lldb.SBCommandReturnObject()
+ ci = debugger.GetCommandInterpreter()
+
+ # Run debugger, wait until libcoreclr is loaded,
+ # set breakpoint at Test.Main and stop there
+ test.stop_in_main(debugger, assembly)
+
+ ci.HandleCommand("eestack", res)
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ output = res.GetOutput()
+ # Output is not empty
+ test.assertTrue(len(output) > 0)
+
+ # Specific string must be in the output
+ test.assertNotEqual(output.find("Current frame"), -1)
+
+ # TODO: test other use cases
+
+ # Continue current process and checks its exit code
+ test.exit_lldb(debugger, assembly)
diff --git a/src/ToolBox/SOS/tests/t_cmd_gcroot.py b/src/ToolBox/SOS/tests/t_cmd_gcroot.py
new file mode 100644
index 0000000000..e6b727c9a1
--- /dev/null
+++ b/src/ToolBox/SOS/tests/t_cmd_gcroot.py
@@ -0,0 +1,61 @@
+import lldb
+import re
+import testutils as test
+
+
+def runScenario(assembly, debugger, target):
+ process = target.GetProcess()
+ res = lldb.SBCommandReturnObject()
+ ci = debugger.GetCommandInterpreter()
+
+ # Run debugger, wait until libcoreclr is loaded,
+ # set breakpoint at Test.Main and stop there
+ test.stop_in_main(debugger, assembly)
+
+ ci.HandleCommand("dso", res)
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ output = res.GetOutput()
+ # Output is not empty
+ test.assertTrue(len(output) > 0)
+
+ # Get all objects
+ objects = []
+ for line in output.split('\n'):
+ match = re.match('([0-9a-fA-F]+)\s+([0-9a-fA-F]+)\s', line)
+ # Not all lines list objects
+ if match:
+ groups = match.groups()
+ # Match has exactly two subgroups
+ test.assertEqual(len(groups), 2)
+
+ obj_addr = groups[1]
+ # Address must be a hex number
+ test.assertTrue(test.is_hexnum(obj_addr))
+
+ objects.append(obj_addr)
+
+ # There must be at least one object
+ test.assertTrue(len(objects) > 0)
+
+ for obj in objects:
+ ci.HandleCommand("gcroot " + obj, res)
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ output = res.GetOutput()
+ # Output is not empty
+ test.assertTrue(len(output) > 0)
+
+ match = re.search('Found', output)
+ test.assertTrue(match)
+
+ # TODO: test other use cases
+
+ # Continue current process and checks its exit code
+ test.exit_lldb(debugger, assembly)
diff --git a/src/ToolBox/SOS/tests/t_cmd_histclear.py b/src/ToolBox/SOS/tests/t_cmd_histclear.py
new file mode 100644
index 0000000000..db29bd85f7
--- /dev/null
+++ b/src/ToolBox/SOS/tests/t_cmd_histclear.py
@@ -0,0 +1,31 @@
+import lldb
+import re
+import testutils as test
+
+
+def runScenario(assembly, debugger, target):
+ process = target.GetProcess()
+ res = lldb.SBCommandReturnObject()
+ ci = debugger.GetCommandInterpreter()
+
+ # Run debugger, wait until libcoreclr is loaded,
+ # set breakpoint at Test.Main and stop there
+ test.stop_in_main(debugger, assembly)
+
+ ci.HandleCommand("histclear", res)
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ output = res.GetOutput()
+ # Output is not empty
+ test.assertTrue(len(output) > 0)
+
+ # Specific string must be in the output
+ test.assertNotEqual(output.find("Completed successfully."), -1)
+
+ # TODO: test other use cases
+
+ # Continue current process and checks its exit code
+ test.exit_lldb(debugger, assembly)
diff --git a/src/ToolBox/SOS/tests/t_cmd_histinit.py b/src/ToolBox/SOS/tests/t_cmd_histinit.py
new file mode 100644
index 0000000000..51191283c7
--- /dev/null
+++ b/src/ToolBox/SOS/tests/t_cmd_histinit.py
@@ -0,0 +1,31 @@
+import lldb
+import re
+import testutils as test
+
+
+def runScenario(assembly, debugger, target):
+ process = target.GetProcess()
+ res = lldb.SBCommandReturnObject()
+ ci = debugger.GetCommandInterpreter()
+
+ # Run debugger, wait until libcoreclr is loaded,
+ # set breakpoint at Test.Main and stop there
+ test.stop_in_main(debugger, assembly)
+
+ ci.HandleCommand("histinit", res)
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ output = res.GetOutput()
+ # Output is not empty
+ test.assertTrue(len(output) > 0)
+
+ # Specific string must be in the output
+ test.assertNotEqual(output.find("STRESS LOG:"), -1)
+
+ # TODO: test other use cases
+
+ # Continue current process and checks its exit code
+ test.exit_lldb(debugger, assembly)
diff --git a/src/ToolBox/SOS/tests/t_cmd_histobj.py b/src/ToolBox/SOS/tests/t_cmd_histobj.py
new file mode 100644
index 0000000000..c88bdac16e
--- /dev/null
+++ b/src/ToolBox/SOS/tests/t_cmd_histobj.py
@@ -0,0 +1,61 @@
+import lldb
+import re
+import testutils as test
+
+
+def runScenario(assembly, debugger, target):
+ process = target.GetProcess()
+ res = lldb.SBCommandReturnObject()
+ ci = debugger.GetCommandInterpreter()
+
+ # Run debugger, wait until libcoreclr is loaded,
+ # set breakpoint at Test.Main and stop there
+ test.stop_in_main(debugger, assembly)
+
+ ci.HandleCommand("dso", res)
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ output = res.GetOutput()
+ # Output is not empty
+ test.assertTrue(len(output) > 0)
+
+ # Get all objects
+ objects = []
+ for line in output.split('\n'):
+ match = re.match('([0-9a-fA-F]+)\s+([0-9a-fA-F]+)\s', line)
+ # Not all lines list objects
+ if match:
+ groups = match.groups()
+ # Match has exactly two subgroups
+ test.assertEqual(len(groups), 2)
+
+ obj_addr = groups[1]
+ # Address must be a hex number
+ test.assertTrue(test.is_hexnum(obj_addr))
+
+ objects.append(obj_addr)
+
+ # There must be at least one object
+ test.assertTrue(len(objects) > 0)
+
+ for obj in objects:
+ ci.HandleCommand("histobj " + obj, res)
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ output = res.GetOutput()
+ # Output is not empty
+ test.assertTrue(len(output) > 0)
+
+ match = re.search('GCCount', output)
+ test.assertTrue(match)
+
+ # TODO: test other use cases
+
+ # Continue current process and checks its exit code
+ test.exit_lldb(debugger, assembly)
diff --git a/src/ToolBox/SOS/tests/t_cmd_histobjfind.py b/src/ToolBox/SOS/tests/t_cmd_histobjfind.py
new file mode 100644
index 0000000000..ffe5dbf52d
--- /dev/null
+++ b/src/ToolBox/SOS/tests/t_cmd_histobjfind.py
@@ -0,0 +1,61 @@
+import lldb
+import re
+import testutils as test
+
+
+def runScenario(assembly, debugger, target):
+ process = target.GetProcess()
+ res = lldb.SBCommandReturnObject()
+ ci = debugger.GetCommandInterpreter()
+
+ # Run debugger, wait until libcoreclr is loaded,
+ # set breakpoint at Test.Main and stop there
+ test.stop_in_main(debugger, assembly)
+
+ ci.HandleCommand("dso", res)
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ output = res.GetOutput()
+ # Output is not empty
+ test.assertTrue(len(output) > 0)
+
+ # Get all objects
+ objects = []
+ for line in output.split('\n'):
+ match = re.match('([0-9a-fA-F]+)\s+([0-9a-fA-F]+)\s', line)
+ # Not all lines list objects
+ if match:
+ groups = match.groups()
+ # Match has exactly two subgroups
+ test.assertEqual(len(groups), 2)
+
+ obj_addr = groups[1]
+ # Address must be a hex number
+ test.assertTrue(test.is_hexnum(obj_addr))
+
+ objects.append(obj_addr)
+
+ # There must be at least one object
+ test.assertTrue(len(objects) > 0)
+
+ for obj in objects:
+ ci.HandleCommand("histobjfind " + obj, res)
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ output = res.GetOutput()
+ # Output is not empty
+ test.assertTrue(len(output) > 0)
+
+ match = re.search('GCCount', output)
+ test.assertTrue(match)
+
+ # TODO: test other use cases
+
+ # Continue current process and checks its exit code
+ test.exit_lldb(debugger, assembly)
diff --git a/src/ToolBox/SOS/tests/t_cmd_histroot.py b/src/ToolBox/SOS/tests/t_cmd_histroot.py
new file mode 100644
index 0000000000..7b73caafda
--- /dev/null
+++ b/src/ToolBox/SOS/tests/t_cmd_histroot.py
@@ -0,0 +1,61 @@
+import lldb
+import re
+import testutils as test
+
+
+def runScenario(assembly, debugger, target):
+ process = target.GetProcess()
+ res = lldb.SBCommandReturnObject()
+ ci = debugger.GetCommandInterpreter()
+
+ # Run debugger, wait until libcoreclr is loaded,
+ # set breakpoint at Test.Main and stop there
+ test.stop_in_main(debugger, assembly)
+
+ ci.HandleCommand("dso", res)
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ output = res.GetOutput()
+ # Output is not empty
+ test.assertTrue(len(output) > 0)
+
+ # Get all objects
+ objects = []
+ for line in output.split('\n'):
+ match = re.match('([0-9a-fA-F]+)\s+([0-9a-fA-F]+)\s', line)
+ # Not all lines list objects
+ if match:
+ groups = match.groups()
+ # Match has exactly two subgroups
+ test.assertEqual(len(groups), 2)
+
+ obj_addr = groups[1]
+ # Address must be a hex number
+ test.assertTrue(test.is_hexnum(obj_addr))
+
+ objects.append(obj_addr)
+
+ # There must be at least one object
+ test.assertTrue(len(objects) > 0)
+
+ for obj in objects:
+ ci.HandleCommand("histroot " + obj, res)
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ output = res.GetOutput()
+ # Output is not empty
+ test.assertTrue(len(output) > 0)
+
+ match = re.search('GCCount', output)
+ test.assertTrue(match)
+
+ # TODO: test other use cases
+
+ # Continue current process and checks its exit code
+ test.exit_lldb(debugger, assembly)
diff --git a/src/ToolBox/SOS/tests/t_cmd_ip2md.py b/src/ToolBox/SOS/tests/t_cmd_ip2md.py
new file mode 100644
index 0000000000..1384c38f0c
--- /dev/null
+++ b/src/ToolBox/SOS/tests/t_cmd_ip2md.py
@@ -0,0 +1,53 @@
+import lldb
+import re
+import testutils as test
+
+
+def runScenario(assembly, debugger, target):
+ process = target.GetProcess()
+ res = lldb.SBCommandReturnObject()
+ ci = debugger.GetCommandInterpreter()
+
+ # Run debugger, wait until libcoreclr is loaded,
+ # set breakpoint at Test.Main and stop there
+ test.stop_in_main(debugger, assembly)
+
+ ci.HandleCommand("name2ee " + assembly + " Test.Main", res)
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ output = res.GetOutput()
+ # Output is not empty
+ test.assertTrue(len(output) > 0)
+
+ match = re.search('JITTED Code Address:\s+([0-9a-fA-F]+)', output)
+ # Line matched
+ test.assertTrue(match)
+
+ groups = match.groups()
+ # Match has a single subgroup
+ test.assertEqual(len(groups), 1)
+
+ jit_addr = groups[0]
+ # Address must be a hex number
+ test.assertTrue(test.is_hexnum(jit_addr))
+
+ ci.HandleCommand("ip2md " + jit_addr, res)
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ output = res.GetOutput()
+ # Output is not empty
+ test.assertTrue(len(output) > 0)
+
+ # Specific string must be in the output
+ test.assertNotEqual(output.find("MethodDesc:"), -1)
+
+ # TODO: test other use cases
+
+ # Continue current process and checks its exit code
+ test.exit_lldb(debugger, assembly)
diff --git a/src/ToolBox/SOS/tests/t_cmd_name2ee.py b/src/ToolBox/SOS/tests/t_cmd_name2ee.py
new file mode 100644
index 0000000000..b617020e36
--- /dev/null
+++ b/src/ToolBox/SOS/tests/t_cmd_name2ee.py
@@ -0,0 +1,46 @@
+import lldb
+import re
+import testutils as test
+
+
+def runScenario(assembly, debugger, target):
+ process = target.GetProcess()
+ res = lldb.SBCommandReturnObject()
+ ci = debugger.GetCommandInterpreter()
+
+ # Run debugger, wait until libcoreclr is loaded,
+ # set breakpoint at Test.Main and stop there
+ test.stop_in_main(debugger, assembly)
+
+ ci.HandleCommand("name2ee " + assembly + " Test.Main", res)
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ output = res.GetOutput()
+ # Output is not empty
+ test.assertTrue(len(output) > 0)
+
+ match = re.search('Module:\s+[0-9a-fA-F]+', output)
+ test.assertTrue(match)
+ match = re.search('Assembly:\s+\S+', output)
+ test.assertTrue(match)
+ match = re.search('Token:\s+[0-9a-fA-F]+', output)
+ test.assertTrue(match)
+ match = re.search('MethodDesc:\s+[0-9a-fA-F]+', output)
+ test.assertTrue(match)
+ match = re.search('Name:\s+\S+', output)
+ test.assertTrue(match)
+
+ process.Continue()
+ # Process must exit
+ test.assertEqual(process.GetState(), lldb.eStateExited)
+
+ # Process must exit with zero code
+ test.assertEqual(process.GetExitStatus(), 0)
+
+ # TODO: test other use cases
+
+ # Continue current process and checks its exit code
+ test.exit_lldb(debugger, assembly)
diff --git a/src/ToolBox/SOS/tests/t_cmd_pe.py b/src/ToolBox/SOS/tests/t_cmd_pe.py
new file mode 100644
index 0000000000..0a87014934
--- /dev/null
+++ b/src/ToolBox/SOS/tests/t_cmd_pe.py
@@ -0,0 +1,28 @@
+import lldb
+import re
+import testutils as test
+
+
+def runScenario(assembly, debugger, target):
+ process = target.GetProcess()
+ res = lldb.SBCommandReturnObject()
+ ci = debugger.GetCommandInterpreter()
+
+ # Run debugger, wait until libcoreclr is loaded,
+ # set breakpoint at Test.Main and stop there
+ test.stop_in_main(debugger, assembly)
+
+ ci.HandleCommand("dso", res)
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ output = res.GetOutput()
+ # Output is not empty
+ test.assertTrue(len(output) > 0)
+
+ # TODO: test other use cases
+
+ # Continue current process and checks its exit code
+ test.exit_lldb(debugger, assembly)
diff --git a/src/ToolBox/SOS/tests/t_cmd_sos.py b/src/ToolBox/SOS/tests/t_cmd_sos.py
new file mode 100644
index 0000000000..b407491d79
--- /dev/null
+++ b/src/ToolBox/SOS/tests/t_cmd_sos.py
@@ -0,0 +1,31 @@
+import lldb
+import re
+import testutils as test
+
+
+def runScenario(assembly, debugger, target):
+ process = target.GetProcess()
+ res = lldb.SBCommandReturnObject()
+ ci = debugger.GetCommandInterpreter()
+
+ # Run debugger, wait until libcoreclr is loaded,
+ # set breakpoint at Test.Main and stop there
+ test.stop_in_main(debugger, assembly)
+
+ ci.HandleCommand("sos", res)
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ output = res.GetOutput()
+ # Output is not empty
+ test.assertTrue(len(output) > 0)
+
+ # Specific string must be in the output
+ test.assertNotEqual(output.find("SOS"), -1)
+
+ # TODO: test other use cases
+
+ # Continue current process and checks its exit code
+ test.exit_lldb(debugger, assembly)
diff --git a/src/ToolBox/SOS/tests/t_cmd_soshelp.py b/src/ToolBox/SOS/tests/t_cmd_soshelp.py
new file mode 100644
index 0000000000..8bb51dad5a
--- /dev/null
+++ b/src/ToolBox/SOS/tests/t_cmd_soshelp.py
@@ -0,0 +1,31 @@
+import lldb
+import re
+import testutils as test
+
+
+def runScenario(assembly, debugger, target):
+ process = target.GetProcess()
+ res = lldb.SBCommandReturnObject()
+ ci = debugger.GetCommandInterpreter()
+
+ # Run debugger, wait until libcoreclr is loaded,
+ # set breakpoint at Test.Main and stop there
+ test.stop_in_main(debugger, assembly)
+
+ ci.HandleCommand("soshelp", res)
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ output = res.GetOutput()
+ # Output is not empty
+ test.assertTrue(len(output) > 0)
+
+ # Specific string must be in the output
+ test.assertNotEqual(output.find("soshelp <functionname>"), -1)
+
+ # TODO: test other use cases
+
+ # Continue current process and checks its exit code
+ test.exit_lldb(debugger, assembly)
diff --git a/src/ToolBox/SOS/tests/test_libsosplugin.py b/src/ToolBox/SOS/tests/test_libsosplugin.py
index e4f59ebbcf..e5a5906264 100644
--- a/src/ToolBox/SOS/tests/test_libsosplugin.py
+++ b/src/ToolBox/SOS/tests/test_libsosplugin.py
@@ -1,3 +1,4 @@
+from __future__ import print_function
import unittest
import argparse
import re
@@ -5,80 +6,279 @@ import tempfile
import subprocess
import threading
import os
-import os.path
import sys
+import inspect
+
+lldb = ''
+clrdir = ''
+workdir = ''
+corerun = ''
+sosplugin = ''
+assembly = ''
+fail_flag = ''
+fail_flag_lldb = ''
+summary_file = ''
+timeout = 0
+regex = ''
+repeat = 0
+
+
+def runWithTimeout(cmd):
+ p = None
+
+ def run():
+ global p
+ p = subprocess.Popen(cmd, shell=True)
+ p.communicate()
+
+ thread = threading.Thread(target=run)
+ thread.start()
+
+ thread.join(timeout)
+ if thread.is_alive():
+ with open(summary_file, 'a+') as summary:
+ print('Timeout!', file=summary)
+ p.kill()
+ thread.join()
+
-assemblyName=''
-clrArgs=''
-fail_flag='/tmp/fail_flag'
-
-# helper functions
-
-def prepareScenarioFile(moduleName):
- global assemblyName
- #create a temporary scenario file
- fd, scenarioFileName = tempfile.mkstemp()
- scenarioFile = open(scenarioFileName, 'w')
- scenarioFile.write('script from runprocess import run\n')
- scenarioFile.write('script run("'+assemblyName+'", "'+moduleName+'")\n')
- scenarioFile.write('quit\n')
- scenarioFile.close()
- os.close(fd)
- return scenarioFileName
-
-def runWithTimeout(cmd, timeout):
- d = {'process': None}
- def run():
- d['process'] = subprocess.Popen(cmd, shell=True)
- d['process'].communicate()
-
- thread = threading.Thread(target=run)
- thread.start()
-
- thread.join(timeout)
- if thread.is_alive():
- d['process'].terminate()
- thread.join()
-
-# Test class
class TestSosCommands(unittest.TestCase):
- def do_test(self, command):
- global clrArgs
- global fail_flag
- filename = prepareScenarioFile(command)
- cmd = "lldb --source "+filename+" -b -K \"OnCrash.do\" -- "+clrArgs+" > "+command+".log 2>"+command+".log.2"
- runWithTimeout(cmd, 120)
- self.assertFalse(os.path.isfile(fail_flag))
- os.unlink(filename)
+ def do_test(self, command):
+ open(fail_flag, 'a').close()
+ try:
+ os.unlink(fail_flag_lldb)
+ except:
+ pass
+
+ cmd = (('%s -b ' % lldb) +
+ ("-k \"script open('%s', 'a').close()\" " % fail_flag_lldb) +
+ ("-k 'quit' ") +
+ ("--no-lldbinit ") +
+ ("-O \"plugin load %s \" " % sosplugin) +
+ ("-o \"script import testutils as test\" ") +
+ ("-o \"script test.fail_flag = '%s'\" " % fail_flag) +
+ ("-o \"script test.summary_file = '%s'\" " % summary_file) +
+ ("-o \"script test.run('%s', '%s')\" " % (assembly, command)) +
+ ("-o \"quit\" ") +
+ (" -- %s %s > %s.log 2> %s.log.2" % (corerun, assembly,
+ command, command)))
+
+ runWithTimeout(cmd)
+ self.assertFalse(os.path.isfile(fail_flag))
+ self.assertFalse(os.path.isfile(fail_flag_lldb))
+
+ try:
+ os.unlink(fail_flag)
+ except:
+ pass
+ try:
+ os.unlink(fail_flag_lldb)
+ except:
+ pass
+
+ def t_cmd_bpmd_nofuturemodule_module_function(self):
+ self.do_test('t_cmd_bpmd_nofuturemodule_module_function')
+
+ def t_cmd_bpmd_module_function(self):
+ self.do_test('t_cmd_bpmd_module_function')
+
+ def t_cmd_bpmd_module_function_iloffset(self):
+ self.do_test('t_cmd_bpmd_module_function_iloffset')
+
+ def t_cmd_bpmd_methoddesc(self):
+ self.do_test('t_cmd_bpmd_methoddesc')
+
+ def t_cmd_bpmd_clearall(self):
+ self.do_test('t_cmd_bpmd_clearall')
+
+ def t_cmd_clrstack(self):
+ self.do_test('t_cmd_clrstack')
+
+ def t_cmd_clrthreads(self):
+ self.do_test('t_cmd_clrthreads')
+
+ def t_cmd_clru(self):
+ self.do_test('t_cmd_clru')
+
+ def t_cmd_dumpclass(self):
+ self.do_test('t_cmd_dumpclass')
+
+ def t_cmd_dumpheap(self):
+ self.do_test('t_cmd_dumpheap')
+
+ def t_cmd_dumpil(self):
+ self.do_test('t_cmd_dumpil')
+
+ def t_cmd_dumplog(self):
+ self.do_test('t_cmd_dumplog')
+
+ def t_cmd_dumpmd(self):
+ self.do_test('t_cmd_dumpmd')
+
+ def t_cmd_dumpmodule(self):
+ self.do_test('t_cmd_dumpmodule')
+
+ def t_cmd_dumpmt(self):
+ self.do_test('t_cmd_dumpmt')
+
+ def t_cmd_dumpobj(self):
+ self.do_test('t_cmd_dumpobj')
+
+ def t_cmd_dumpstack(self):
+ self.do_test('t_cmd_dumpstack')
+
+ def t_cmd_dso(self):
+ self.do_test('t_cmd_dso')
+
+ def t_cmd_eeheap(self):
+ self.do_test('t_cmd_eeheap')
- def test_dumpmodule(self):
- self.do_test("dumpmodule")
+ def t_cmd_eestack(self):
+ self.do_test('t_cmd_eestack')
+
+ def t_cmd_gcroot(self):
+ self.do_test('t_cmd_gcroot')
+
+ def t_cmd_ip2md(self):
+ self.do_test('t_cmd_ip2md')
+
+ def t_cmd_name2ee(self):
+ self.do_test('t_cmd_name2ee')
+
+ def t_cmd_pe(self):
+ self.do_test('t_cmd_pe')
+
+ def t_cmd_histclear(self):
+ self.do_test('t_cmd_histclear')
+
+ def t_cmd_histinit(self):
+ self.do_test('t_cmd_histinit')
+
+ def t_cmd_histobj(self):
+ self.do_test('t_cmd_histobj')
+
+ def t_cmd_histobjfind(self):
+ self.do_test('t_cmd_histobjfind')
+
+ def t_cmd_histroot(self):
+ self.do_test('t_cmd_histroot')
+
+ def t_cmd_sos(self):
+ self.do_test('t_cmd_sos')
+
+ def t_cmd_soshelp(self):
+ self.do_test('t_cmd_soshelp')
+
+
+def generate_report():
+ report = [{'name': 'TOTAL', True: 0, False: 0, 'completed': True}]
+ fail_messages = []
+
+ if not os.path.isfile(summary_file):
+ print('No summary file to process!')
+ return
+
+ with open(summary_file, 'r') as summary:
+ for line in summary:
+ if line.startswith('new_suite: '):
+ report.append({'name': line.split()[-1], True: 0, False: 0,
+ 'completed': False, 'timeout': False})
+ elif line.startswith('True'):
+ report[-1][True] += 1
+ elif line.startswith('False'):
+ report[-1][False] += 1
+ elif line.startswith('Completed!'):
+ report[-1]['completed'] = True
+ elif line.startswith('Timeout!'):
+ report[-1]['timeout'] = True
+ elif line.startswith('!!! '):
+ fail_messages.append(line.rstrip('\n'))
+
+ for suite in report[1:]:
+ report[0][True] += suite[True]
+ report[0][False] += suite[False]
+ report[0]['completed'] &= suite['completed']
+
+ for line in fail_messages:
+ print(line)
+
+ print()
+ print('=' * 79)
+ print('{:72} {:6}'.format('Test suite', 'Result'))
+ print('-' * 79)
+ for suite in report[1:]:
+ if suite['timeout']:
+ result = 'Timeout'
+ elif suite[False]:
+ result = 'Fail'
+ elif not suite['completed']:
+ result = 'Crash'
+ elif suite[True]:
+ result = 'Success'
+ else:
+ result = 'Please, report'
+ print('{:68} {:>10}'.format(suite['name'], result))
+ print('=' * 79)
- def test_dumpil(self):
- self.do_test("dumpil")
-
if __name__ == '__main__':
- parser = argparse.ArgumentParser()
- parser.add_argument('--clr-args', default='')
- parser.add_argument('unittest_args', nargs='*')
-
- args = parser.parse_args()
-
- clrArgs = args.clr_args
- print("ClrArgs: " + clrArgs)
- # find assembly name among lldb arguments
- assembly_regexp = re.compile("([^\s]+\.exe)")
- assemblyMatch = assembly_regexp.search(clrArgs)
- if assemblyMatch is not None:
- assemblyName = assemblyMatch.group(1)
- else:
- print("Assembly not recognized")
- exit(1)
-
- print("Assembly name: "+assemblyName)
- sys.argv[1:] = args.unittest_args
- suite = unittest.TestLoader().loadTestsFromTestCase(TestSosCommands)
- unittest.TextTestRunner(verbosity=2).run(suite)
- os.unlink(fail_flag) \ No newline at end of file
+ parser = argparse.ArgumentParser()
+ parser.add_argument('--lldb', default='lldb')
+ parser.add_argument('--clrdir', default='.')
+ parser.add_argument('--workdir', default='.')
+ parser.add_argument('--assembly', default='Test.exe')
+ parser.add_argument('--timeout', default=90)
+ parser.add_argument('--regex', default='t_cmd_')
+ parser.add_argument('--repeat', default=1)
+ parser.add_argument('unittest_args', nargs='*')
+
+ args = parser.parse_args()
+
+ lldb = args.lldb
+ clrdir = args.clrdir
+ workdir = args.workdir
+ assembly = args.assembly
+ timeout = int(args.timeout)
+ regex = args.regex
+ repeat = int(args.repeat)
+ print("lldb: %s" % lldb)
+ print("clrdir: %s" % clrdir)
+ print("workdir: %s" % workdir)
+ print("assembly: %s" % assembly)
+ print("timeout: %i" % timeout)
+ print("regex: %s" % regex)
+ print("repeat: %i" % repeat)
+
+ corerun = os.path.join(clrdir, 'corerun')
+ sosplugin = os.path.join(clrdir, 'libsosplugin.so')
+ if os.name != 'posix':
+ print('Not implemented: corerun.exe, sosplugin.dll?')
+ exit(1)
+
+ print("corerun: %s" % corerun)
+ print("sosplugin: %s" % sosplugin)
+
+ fail_flag = os.path.join(workdir, 'fail_flag')
+ fail_flag_lldb = os.path.join(workdir, 'fail_flag.lldb')
+
+ print("fail_flag: %s" % fail_flag)
+ print("fail_flag_lldb: %s" % fail_flag_lldb)
+
+ summary_file = os.path.join(workdir, 'summary')
+ print("summary_file: %s" % summary_file)
+
+ try:
+ os.unlink(summary_file)
+ except:
+ pass
+
+ sys.argv[1:] = args.unittest_args
+ suite = unittest.TestSuite()
+ all_tests = inspect.getmembers(TestSosCommands, predicate=inspect.ismethod)
+ for (test_name, test_func) in all_tests:
+ if re.match(regex, test_name):
+ suite.addTest(TestSosCommands(test_name))
+ unittest.TextTestRunner(verbosity=1).run(suite)
+
+ generate_report()
diff --git a/src/ToolBox/SOS/tests/testutils.py b/src/ToolBox/SOS/tests/testutils.py
index 1ddb6560e6..1f784b48f6 100644
--- a/src/ToolBox/SOS/tests/testutils.py
+++ b/src/ToolBox/SOS/tests/testutils.py
@@ -1,40 +1,206 @@
+from __future__ import print_function
import lldb
import re
+import inspect
+import sys
+import os
+import importlib
+
+summary_file = ''
+fail_flag = ''
+
+failed = False
+
+
+def assertCommon(passed, fatal):
+ global failed
+ with open(summary_file, 'a+') as summary:
+ print(bool(passed), file=summary)
+ if (not passed):
+ failed = True
+ print('!!! test failed:', file=summary)
+ for s in inspect.stack()[2:]:
+ print("!!! %s:%i" % (s[1], s[2]), file=summary)
+ print("!!! %s" % s[4][0], file=summary)
+ if re.match('\W*t_\w+\.py$', s[1]):
+ break
+ print('!!! ', file=summary)
+
+ if fatal:
+ exit(1)
+
+
+def assertTrue(x, fatal=True):
+ passed = bool(x)
+ assertCommon(passed, fatal)
+
+
+def assertFalse(x, fatal=True):
+ passed = not bool(x)
+ assertCommon(passed, fatal)
+
+
+def assertEqual(x, y, fatal=True):
+ passed = (x == y)
+ if not passed:
+ print(str(x), ' != ', str(y))
+ assertCommon(passed, fatal)
+
+
+def assertNotEqual(x, y, fatal=True):
+ passed = (x != y)
+ if not passed:
+ print(str(x), ' == ', str(y))
+ assertCommon(passed, fatal)
+
def checkResult(res):
- if not res.Succeeded():
- print(res.GetOutput())
- print(res.GetError())
- exit(1)
+ if not res.Succeeded():
+ print(res.GetOutput())
+ print(res.GetError())
+ exit(1)
+
+
+def is_hexnum(s):
+ try:
+ int(s, 16)
+ return True
+ except ValueError:
+ return False
+
def exec_and_find(commandInterpreter, cmd, regexp):
- res = lldb.SBCommandReturnObject()
- commandInterpreter.HandleCommand(cmd, res)
- checkResult(res)
-
- expr = re.compile(regexp)
- addr = None
-
- print(res.GetOutput())
- lines = res.GetOutput().splitlines()
- for line in lines:
- match = expr.match(line)
- if match is not None:
- addr = match.group(1)
- break
-
- print("Found addr: " + str(addr))
- return addr
-
-def stop_in_main(commandInterpreter, process, assemblyName):
- res = lldb.SBCommandReturnObject()
- commandInterpreter.HandleCommand("bpmd " + assemblyName + " Program.Main", res)
- checkResult(res)
- print(res.GetOutput())
- print(res.GetError())
- res.Clear()
-
-
- # Use Python API to continue the process. The listening thread should be
- # able to receive the state changed events.
- process.Continue() \ No newline at end of file
+ res = lldb.SBCommandReturnObject()
+ commandInterpreter.HandleCommand(cmd, res)
+ checkResult(res)
+
+ expr = re.compile(regexp)
+ addr = None
+
+ print(res.GetOutput())
+ lines = res.GetOutput().splitlines()
+ for line in lines:
+ match = expr.match(line)
+ if match:
+ addr = match.group(1)
+ break
+
+ print("Found addr: " + str(addr))
+ return addr
+
+
+def stop_in_main(debugger, assembly):
+ ci = debugger.GetCommandInterpreter()
+ target = debugger.GetSelectedTarget()
+ process = target.GetProcess()
+ res = lldb.SBCommandReturnObject()
+
+ # Process must be stopped here while libcoreclr loading.
+ # This test usually fails on release version of coreclr
+ # since we depend on 'LoadLibraryExW' symbol present.
+ assertEqual(process.GetState(), lldb.eStateStopped)
+
+ # The reason of this stop must be a breakpoint
+ assertEqual(process.GetSelectedThread().GetStopReason(),
+ lldb.eStopReasonBreakpoint)
+
+ ci.HandleCommand("bpmd " + assembly + " Test.Main", res)
+ out_msg = res.GetOutput()
+ err_msg = res.GetError()
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ assertTrue(res.Succeeded())
+
+ # Output is not empty
+ # Should be at least 'Adding pending breakpoints...'
+ assertTrue(len(out_msg) > 0)
+
+ # Error message is empty
+ assertTrue(len(err_msg) == 0)
+
+ process.Continue()
+ # Process must be stopped here if bpmd works at all
+ assertEqual(process.GetState(), lldb.eStateStopped)
+
+ # The reason of this stop must be a breakpoint
+ assertEqual(process.GetSelectedThread().GetStopReason(),
+ lldb.eStopReasonBreakpoint)
+
+
+def exit_lldb(debugger, assembly):
+ ci = debugger.GetCommandInterpreter()
+ target = debugger.GetSelectedTarget()
+ process = target.GetProcess()
+ res = lldb.SBCommandReturnObject()
+
+ ci.HandleCommand("breakpoint delete --force", res)
+ out_msg = res.GetOutput()
+ err_msg = res.GetError()
+ print(out_msg)
+ print(err_msg)
+ # Interpreter must have this command and able to run it
+ # assertTrue(res.Succeeded())
+
+ process.Continue()
+ # Process must exit
+ assertEqual(process.GetState(), lldb.eStateExited)
+
+ # Process must exit with zero code
+ assertEqual(process.GetExitStatus(), 0)
+
+
+def get_methoddesc(debugger, assembly, funcname):
+ ci = debugger.GetCommandInterpreter()
+ target = debugger.GetSelectedTarget()
+ process = target.GetProcess()
+ res = lldb.SBCommandReturnObject()
+
+ ci.HandleCommand("name2ee %s %s" % (assembly, funcname), res)
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ assertTrue(res.Succeeded())
+
+ output = res.GetOutput()
+ # Output is not empty
+ assertTrue(len(output) > 0)
+
+ match = re.search('MethodDesc:\s+([0-9a-fA-F]+)', output)
+ # Line matched
+ assertTrue(match)
+
+ groups = match.groups()
+ # Match has a single subgroup
+ assertEqual(len(groups), 1)
+
+ md_addr = groups[0]
+ # Address must be a hex number
+ assertTrue(is_hexnum(md_addr))
+
+ return md_addr
+
+
+def run(assembly, module):
+ with open(summary_file, 'a+') as summary:
+ print('new_suite: %s' % module, file=summary)
+
+ debugger = lldb.debugger
+
+ debugger.SetAsync(False)
+ target = lldb.target
+
+ debugger.HandleCommand("breakpoint set --one-shot --name coreclr_execute_assembly")
+ debugger.HandleCommand("process launch")
+
+ # run the scenario
+ print("starting scenario...")
+ i = importlib.import_module(module)
+ scenarioResult = i.runScenario(os.path.basename(assembly), debugger,
+ target)
+
+ if (target.GetProcess().GetExitStatus() == 0) and not failed:
+ os.unlink(fail_flag)
+
+ with open(summary_file, 'a+') as summary:
+ print('Completed!', file=summary)