diff --git a/CHANGELOG.md b/CHANGELOG.md index 2fe6ad4..d5fe327 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [4.0.2] - 2024-08-16 + +### Fixed +- #51: Don't start (and stop) the ObjectScript and Python monitors if there are no ObjectScript/Python routines being tracked respectively, fixes error from trying to start/stop the %Monitor.System.LineByLine with no routines + + ## [4.0.1] - 2024-08-16 ### Fixed diff --git a/cls/TestCoverage/Manager.cls b/cls/TestCoverage/Manager.cls index 938a4e1..6e28cf7 100644 --- a/cls/TestCoverage/Manager.cls +++ b/cls/TestCoverage/Manager.cls @@ -528,10 +528,10 @@ Method EndCoverageTracking(pTestSuite As %String = "", pTestClass As %String = " Set tSC = $$$OK Try { If ((..CoverageTargets '= "") || (..PyCoverageTargets '= "")) { - // Pause the monitor. - Set tSC = ..Monitor.Pause() - Do ##class(TestCoverage.Utils.LineByLineMonitor).PyStop() - If $$$ISERR(tSC) { + if (..Monitor.Started) { + // Pause the monitor. + Set tSC = ..Monitor.Pause() + If $$$ISERR(tSC) { If $System.Status.GetErrorCodes(tSC) = $$$MonitorNotRunning { // Not really an error, and nothing to do in this case. Set tSC = $$$OK @@ -540,6 +540,11 @@ Method EndCoverageTracking(pTestSuite As %String = "", pTestClass As %String = " $$$ThrowStatus(tSC) } } + } + + if (..Monitor.PyStarted) { + Do ##class(TestCoverage.Utils.LineByLineMonitor).PyStop() + } Set tTarget = $ListBuild($$$TestPathAllTests) // detail = 0 If (pTestSuite '= "") { @@ -719,7 +724,12 @@ ClassMethod OnAfterAllTests(manager As TestCoverage.Manager, dir As %String, ByR Do manager.ListenerManager.BroadCastToAll(tObj) } } - Do manager.Monitor.Stop() + if (manager.Monitor.Started) { + Do manager.Monitor.Stop() + } + if (manager.Monitor.PyStarted) { + Do manager.Monitor.PyStop() + } } Catch e { Set tSC = e.AsStatus() } diff --git a/cls/TestCoverage/Utils/LineByLineMonitor.cls b/cls/TestCoverage/Utils/LineByLineMonitor.cls index 1c63e13..1e335d5 100644 --- a/cls/TestCoverage/Utils/LineByLineMonitor.cls +++ b/cls/TestCoverage/Utils/LineByLineMonitor.cls @@ -8,11 +8,20 @@ Class TestCoverage.Utils.LineByLineMonitor Extends %Monitor.System.LineByLine /// True if the line-by-line monitor has been started. Property Started As %Boolean [ Calculated, Private, ReadOnly ]; +/// True if the Python trace has been set +Property PyStarted As %Boolean [ Calculated, Private, ReadOnly ]; + Method StartedGet() As %Boolean [ CodeMode = expression ] { $zu(84,8) } +Method PyStartedGet() As %Boolean [ Language = python ] +{ + import sys + return sys.gettrace() is not None +} + /// True if the line-by-line monitor is paused Property Paused As %Boolean [ Calculated, Private, ReadOnly ]; @@ -30,6 +39,8 @@ Property LastMetricList As %List [ Private ]; Property LastProcessList As %List [ Private ]; +Property LastPythonList As %List [ Private ]; + /// This callback method is invoked by the %Close method to /// provide notification that the current object is being closed. /// @@ -98,20 +109,22 @@ Method StartWithScope(pRoutineList As %List, pPyClasses As %List, pMetricList As Set tSC = $$$OK Try { Set ..PythonClassList = pPyClasses - Set tDifferentScope = (..LastRoutineList '= pRoutineList) || (..LastMetricList '= pMetricList) || (..LastProcessList '= pProcessList) - If tDifferentScope && ..Started { + Set tDifferentScope = (..LastRoutineList '= pRoutineList) || (..LastMetricList '= pMetricList) || (..LastProcessList '= pProcessList) || (..LastPythonList '= pPyClasses) + If tDifferentScope && (..Started || ..PyStarted) { // If we need to track different routines/metrics/processes, need to stop the monitor before restarting with the new context. - Do ..Stop() - Do ..PyStop() + If (..Started) { + Do ..Stop() + } + Do ..PyStop() // setting the trace to None can and should always be done Set ..LastRoutineList = pRoutineList Set ..LastMetricList = pMetricList Set ..LastProcessList = pProcessList + Set ..LastPythonList = pPyClasses } - If '..Started { - Do ..PyClearCounters() + // take care of starting the ObjectScript Monitor + If ('..Started && $ListLength(pRoutineList) '= 0) { Set tSC = ..Start(pRoutineList, pMetricList, pProcessList) - Do ..PyStartWithScope(pPyClasses) If $System.Status.Equals(tSC,$$$ERRORCODE($$$MonitorMemoryAlloc)) { // Construct a more helpful error message. Set tSC = $$$EMBEDSC(..CheckAvailableMemory($ListLength(pProcessList),$ListLength(pRoutineList),1),tSC) @@ -119,12 +132,20 @@ Method StartWithScope(pRoutineList As %List, pPyClasses As %List, pMetricList As $$$ThrowOnError(tSC) } Else { // If the monitor was already running, clear the counters. - Set tSC = ..ClearCounters() - $$$ThrowOnError(tSC) - If ..Paused { - $$$ThrowOnError(..Resume()) - Do ..PyStartWithScope(pPyClasses) + if (..Started) { + Set tSC = ..ClearCounters() + $$$ThrowOnError(tSC) } + If (..Paused && $ListLength(pRoutineList) '= 0){ + $$$ThrowOnError(..Resume()) + } + } + + If ('..PyStarted && $ListLength(pPyClasses) '= 0) { + // whether we're resuming or restarting, we either way want to clear counters + // since StoreIntCoverage should have already + Do ..PyClearCounters() + Do ..PyStartWithScope(pPyClasses) } } Catch e { Set tSC = e.AsStatus() diff --git a/module.xml b/module.xml index 5540c9e..3b9f9ec 100644 --- a/module.xml +++ b/module.xml @@ -2,7 +2,7 @@ TestCoverage - 4.0.1 + 4.0.2 Run your typical ObjectScript %UnitTest tests and see which lines of your code are executed. Includes Cobertura-style reporting for use in continuous integration tools. module