@Jani Hurskainen providing a top-level answer here:

If you want to truly build your own unit test framework from scratch, you'd need to create a custom resource processor class in IPM. I see from https://github.com/intersystems/ipm/issues/616 that you've already discovered this feature and I appreciate your tenacity and the deep dive into IPM that you're doing.

Every development team I've worked on within InterSystems (that is, three very different ones) has had its own things it's wanted to do that %UnitTest.Manager and %UnitTest.TestCase don't *quite* do the way we want, with the API we want, right out of the box. The approach in general is to extend %UnitTest.Manager to tweak unit test runner behaviors (IPM does this itself, as you may have noticed); to extend %UnitTest.TestCase to add application-specific utility methods, assertions, and generic On(Before|After)(All|One)Test(s?) implementations (often controlled by class parameters); and potentially to add some mix-in utility classes that one might extend along with %UnitTest.TestCase or your own derived unit test base class.

For the basic case of "I want to run tests with my own %UnitTest.Manager subclass" we have a flag you can pass in to override the unit test manager class, -DUnitTest.ManagerClass=yourclassname. See https://community.intersystems.com/post/unit-tests-and-test-coverage-int... for an example of how to use this (with my team's https://github.com/intersystems/TestCoverage open source package).

At the IPM codebase level, there's special treatment of the common "pParams" array passed around everywhere - something looking at pParams("UnitTest","ManagerClass") will find the value specified in -DUnitTest.ManagerClass in the package manager shell command.

Hopefully this is helpful!

Hi @Jani Hurskainen - the short answer is "yes, TestCoverage is coupled to %UnitTest."

Can you elaborate on what you have in mind by "other unit testing frameworks" and/or what you're trying to achieve? %UnitTest is the only unit testing framework for ObjectScript that I'm aware of.
 Is your objective to unify Python and ObjectScript unit tests?

We'll be getting out the next release of git-source-control (https://github.com/intersystems/git-source-control) this month, which includes support back to 2016.2 via an artifact associated with (some) releases. We haven't produced this for the past few releases but will do so for the next one.

You can follow the project here to be notified about new releases: https://openexchange.intersystems.com/package/Git-for-Shared-Development...

Assuming this is with git-source-control, the approach would be to have the temp folder *and all subfolders* owned by SYSTEM (in this case), as discussed at https://github.com/intersystems/git-source-control?tab=readme-ov-file#du.... This is under folder Properties > Security > Advanced. Click "Change" next to "Owner", and under Object Names to Select type in "SYSTEM". Before applying, check the box with "Replace all child object permission entries..." at the bottom of the dialog. That should do it.

I discussed this with Jason earlier this week. The simplest solution is to use the InterSystems Package Manager (IPM) with a local development environment model - if you have multiple local repos all loaded via zpm with the "-dev" flag, git-source-control will know the right place for everything to go and you can edit multiple projects under a single isfs folder in VSCode (or via Studio). Note, you may need to be more explicit than previously needed with the Directory attribute on resources in module.xml to get things perfectly right.

If there are needs that this won't quite meet, it may be possible to improve git-source-control to provide further configuration options.

@Gautam Rishi some things that would be helpful / might be worth looking into:

  • Does the user IRIS runs as (most likely irisusr) have access to /Users/abc/workspace? If not I'd imagine all sorts of things could go wrong. (And git-source-control could be more helpful by making the root cause more obvious.)
  • Where specifically is the error coming from?
    • The error #5001 / message there doesn't seem to be in the git-source-control codebase, at least that I can find.
    • If you set ^%oddENV("callererrorinfo")=2 it'll typically put the full stack trace in the error message. Just be sure to kill ^%oddENV("callererrorinfo") later so you don't keep getting it because it's noisy/annoying if you don't need it.
  • What IRIS version are you running? (write $zv)

In general, feel free to file a GitHub issue at https://github.com/intersystems/git-source-control/issues

Hi @Michael Davidovich - it's been a while! Here's a quick sample for how I'd do this:

Class Mike.Demo.REST Extends %CSP.REST
{

/// This method gets called prior to dispatch of the request. Put any common code here
/// that you want to be executed for EVERY request. If pContinue is set to 0, the
/// request will NOT be dispatched according to the UrlMap. In this case it's the
/// responsibility of the user to return a response.
ClassMethod OnPreDispatch(pUrl As %String, pMethod As %String, ByRef pContinue As %Boolean) As %Status
{
    #dim %request As %CSP.Request
    Set pContinue = 0
    Set version = %request.GetCgiEnv("HTTP_X_API_VERSION","unspecified; use X-API-VERSION header")
    Set class = $Case(+version,
        1:"Mike.Demo.v1",
        2:"Mike.Demo.v2",
        :"")
    If (class = "") {
        Set error = $$$ERROR($$$GeneralError,$$$FormatText("Invalid API version: %1",version))
        // Shoud be HTTP 400, but you probably want to report this differently/better.
        Do ..ReportHttpStatusCode(..#HTTP400BADREQUEST,error)
        Quit $$$OK
    }
    
    Quit $classmethod(class,"DispatchRequest",pUrl,pMethod,1)
}

}

Class Mike.Demo.v1 Extends %CSP.REST
{

Parameter VERSION = 1;

XData UrlMap [ XMLNamespace = "http://www.intersystems.com/urlmap" ]
{
<Routes>
<Route Url="/version" Method="GET" Call="GetVersion" />
</Routes>
}

ClassMethod GetVersion() As %Status
{
    Write {"version":(..#VERSION)}.%ToJSON()
    Quit $$$OK
}

}

Class Mike.Demo.v2 Extends Mike.Demo.v1
{

Parameter VERSION = 2;

XData UrlMap [ XMLNamespace = "http://www.intersystems.com/urlmap" ]
{
<Routes>
<Route Url="/version" Method="GET" Call="GetVersion" />
</Routes>
}

}