@Michael Davidovich we'd generally set ^UnitTestRoot to the path in the cloned repo and then run tests right from there. Another workflow might be to have unit tests run in their own namespace that has all the same code/supporting data but is distinct from the namespace where you're doing dev work - in that case, it's safe to delete the unit tests from that second namespace. (But practically speaking we just use one namespace and don't delete.)
Re: best practices/shortcuts as an individual developer, I'd honestly just say embrace the automation and iterate in a feature branch with the tests running on commit to feature branches (not just main). It also helps to use the package manager to make a more modular codebase where each module has its own associated tests, so you're not rebuilding and testing everything every time.
In a case where you're (a) using the package manager and (b) being really strict about test coverage, combining the techniques in the article I linked earlier is a good approach - e.g., saying to run specific tests *and* measure test coverage. That helps answer "how well do the tests I'm currently writing cover the code I'm currently adding/changing?"
Of course, you can do this with the normal APIs for running unit tests with test coverage too. (TestCoverage.Manager also has DebugRunTestCase - think of it like %UnitTest.Manager but with test coverage built in.)
WARNING! When you implement this (using %CSP.StreamServer or whatever), make sure that you're not opening up a way for a malicious user to download any arbitrary file on the server.
set req = ##class(%Net.HttpRequest).%New()
set req.SSLConfiguration="MBTA"// Set this up in the management portal under Security Management > SSL/TSL Configurations; this is the SSLConfig's "Name"// For HTTP Basic authentication, simple route is e.g.:set req.Username = "foo"set req.Password = "bar"// For other modes, e.g.:do req.SetHeader("Authorization","Bearer abcd")
set sc = req.Get("https://api-v3.mbta.com/routes")
// TODO: check sc / $$$ThrowOnError(sc)// TODO: check req.HttpResponse.StatusCode to make sure it's 200 and error handle appropriatelyset obj = {}.%FromJSON(req.HttpResponse.Data)
zw obj // There's your object!
@Vitaliy.Serdtsev thank you for pointing there! I couldn't find that via the new-and-improved (but still in progress) doc search and have provided feedback to that effect.
Side note: I love having the "Feedback" button on the right side in the docs, and it's great to see the amazing effort being put in to improving the docs, search, etc.
Class DC.Demo.SerialObject Extends%SerialObject
{
Property foo As%String;Property bar As%String;
}
Class DC.Demo.IndexOnSerialObject Extends%Persistent
{
Property blah As DC.Demo.SerialObject;
Index blahFooBar On (blah.foo, blah.bar);ClassMethod RunDemo()
{
Do ..%KillExtent()
Set inst = ..%New()
Set inst.blah.foo = "foo"Set inst.blah.bar = "bar"Do inst.%Save()
zw^DC.Demo.IndexOnSerialObjectD,^DC.Demo.IndexOnSerialObjectI
}
}
Which produces output:
d ##class(DC.Demo.IndexOnSerialObject).RunDemo()
^DC.Demo.IndexOnSerialObjectD=1
^DC.Demo.IndexOnSerialObjectD(1)=$lb("",$lb("foo","bar"))
^DC.Demo.IndexOnSerialObjectI("blahFooBar"," FOO"," BAR",1)=""
Could be a difference of behavior related to select mode - could you try running the management portal query in ODBC and Display mode as well and see if that makes a difference? (This is most often the root cause I see when getting different results for the same query in different contexts.)
[Abstract, NoExtent] lets you define a class that extends %Persistent but doesn't have storage - so subclasses have their own storage (which is presumably what you want)
@Michael Davidovich you could/should definitely do that validation on the client as well. No need to go to the server to compare two dates.
To work as written, the ObjectScript method itself should return a truthy/falsy result (e.g., quit 0 or quit 1) rather than doing that return in JS.
If you turn on auditing for Terminate, Login, Logout, and Protect events you may see helpful things about what's happening with the JOB command (e.g., if it hits an error).
@Michael Davidovich it might be helpful to look under the hood - specifically, at the class generated for the CSP page ("View Other" in Studio/VSCode).
OnPreHTTP is special in that it runs before the page is rendered (and can e.g. redirect you somewhere else). Generally, I would put code that runs on form submit / POST in OnPreHTTP.
Where you just have <script language="Cache" runat="server">, that'll run as the page is rendered whenever it gets to that block. This would generally be used to render more complex content for which other tag-based CSP options are in sufficient. If you're familiar with PHP, this is equivalent to the <?php ... ?> block in:
<script language="Cache" method="SomeMethod"> would be used in hyperevents (i.e., #server(..SomeMethod())# and #call(..SomeMethod())#).
From a coding/design best practices perspective: you should be able to do input validation on the client to provide a friendly error message without needing to go back to the server (e.g., via #server). BUT you should also do validation on the server to make sure that even if the user (maliciously or otherwise) bypasses the client-side validation, they can't submit invalid data.
go to post
@Michael Davidovich we'd generally set ^UnitTestRoot to the path in the cloned repo and then run tests right from there. Another workflow might be to have unit tests run in their own namespace that has all the same code/supporting data but is distinct from the namespace where you're doing dev work - in that case, it's safe to delete the unit tests from that second namespace. (But practically speaking we just use one namespace and don't delete.)
Re: best practices/shortcuts as an individual developer, I'd honestly just say embrace the automation and iterate in a feature branch with the tests running on commit to feature branches (not just main). It also helps to use the package manager to make a more modular codebase where each module has its own associated tests, so you're not rebuilding and testing everything every time.
In a case where you're (a) using the package manager and (b) being really strict about test coverage, combining the techniques in the article I linked earlier is a good approach - e.g., saying to run specific tests *and* measure test coverage. That helps answer "how well do the tests I'm currently writing cover the code I'm currently adding/changing?"
Of course, you can do this with the normal APIs for running unit tests with test coverage too. (TestCoverage.Manager also has DebugRunTestCase - think of it like %UnitTest.Manager but with test coverage built in.)
go to post
@Michael Davidovich - @Pravin Barton is from my team, so I have little to add to what he said - other than to also point to https://community.intersystems.com/post/unit-tests-and-test-coverage-obj.... If you're using InterSystems' package manager it makes tests much easier/more natural to run.
go to post
WARNING! When you implement this (using %CSP.StreamServer or whatever), make sure that you're not opening up a way for a malicious user to download any arbitrary file on the server.
go to post
@Vitaliy Serdtsev thank you for pointing this out. We've fixed the issue; it was actually a separate root cause from before.
go to post
This is a bug. We'll look into it. Thank you for bringing it to our attention.
go to post
Not a full answer, but OnDrawCell is the place to start: https://docs.intersystems.com/ens201815/csp/docbook/DocBook.UI.Page.cls?...
go to post
Sure, here's one:
set req = ##class(%Net.HttpRequest).%New() set req.SSLConfiguration="MBTA" // Set this up in the management portal under Security Management > SSL/TSL Configurations; this is the SSLConfig's "Name" // For HTTP Basic authentication, simple route is e.g.: set req.Username = "foo" set req.Password = "bar" // For other modes, e.g.: do req.SetHeader("Authorization","Bearer abcd") set sc = req.Get("https://api-v3.mbta.com/routes") // TODO: check sc / $$$ThrowOnError(sc) // TODO: check req.HttpResponse.StatusCode to make sure it's 200 and error handle appropriately set obj = {}.%FromJSON(req.HttpResponse.Data) zw obj // There's your object!
go to post
Turns out the problem was *not* the woff files at all - it was the CSS file that used the font. Solution was:
go to post
Update: it looks like we now support local edit/save/compile of CSP application files, provided the web application name starts with "/csp" - see: https://github.com/intersystems-community/vscode-objectscript/pull/622
go to post
@Vitaliy.Serdtsev thank you for pointing there! I couldn't find that via the new-and-improved (but still in progress) doc search and have provided feedback to that effect.
Side note: I love having the "Feedback" button on the right side in the docs, and it's great to see the amazing effort being put in to improving the docs, search, etc.
go to post
Yes. Here's a quick sample:
Class DC.Demo.SerialObject Extends %SerialObject { Property foo As %String; Property bar As %String; } Class DC.Demo.IndexOnSerialObject Extends %Persistent { Property blah As DC.Demo.SerialObject; Index blahFooBar On (blah.foo, blah.bar); ClassMethod RunDemo() { Do ..%KillExtent() Set inst = ..%New() Set inst.blah.foo = "foo" Set inst.blah.bar = "bar" Do inst.%Save() zw ^DC.Demo.IndexOnSerialObjectD,^DC.Demo.IndexOnSerialObjectI } }
Which produces output:
go to post
Could be a difference of behavior related to select mode - could you try running the management portal query in ODBC and Display mode as well and see if that makes a difference? (This is most often the root cause I see when getting different results for the same query in different contexts.)
go to post
Generally I'd do this as follows:
Class DC.Demo.DefinesIndices Extends %Persistent [ Abstract, NoExtent ] { Index TXSBI On TextSearch(KEYS); Index TXSSI On TextSimilarity(KEYS) [ Data = TextSimilarity(ELEMENTS) ]; Property TextSearch As %Text(LANGUAGECLASS = "%Text.English", MAXLEN = 1000, XMLPROJECTION = "NONE"); Property TextSimilarity As %Text(LANGUAGECLASS = "%Text.English", MAXLEN = 1000, SIMILARITYINDEX = "TXSSI", XMLPROJECTION = "NONE"); } Class DC.Demo.InheritsIndices Extends DC.Demo.DefinesIndices { Storage Default { <Data name="InheritsIndicesDefaultData"> <Value name="1"> <Value>%%CLASSNAME</Value> </Value> <Value name="2"> <Value>TextSearch</Value> </Value> <Value name="3"> <Value>TextSimilarity</Value> </Value> </Data> <DataLocation>^DC.Demo.InheritsIndicesD</DataLocation> <DefaultData>InheritsIndicesDefaultData</DefaultData> <IdLocation>^DC.Demo.InheritsIndicesD</IdLocation> <IndexLocation>^DC.Demo.InheritsIndicesI</IndexLocation> <StreamLocation>^DC.Demo.InheritsIndicesS</StreamLocation> <Type>%Storage.Persistent</Type> } }
Key points:
go to post
Simple solution:
Create a class extending %CSP.Page with:
From the %CSP.SessionEvents subclass, in OnStartRequest:
go to post
Here's the problem:
The solution might be using a custom error page too.
go to post
So fun fact: in JavaScript, the string "0" is truthy (although the number 0 is falsy). That's what you're seeing here.
go to post
@Michael Davidovich you could/should definitely do that validation on the client as well. No need to go to the server to compare two dates.
To work as written, the ObjectScript method itself should return a truthy/falsy result (e.g., quit 0 or quit 1) rather than doing that return in JS.
If you turn on auditing for Terminate, Login, Logout, and Protect events you may see helpful things about what's happening with the JOB command (e.g., if it hits an error).
go to post
@Michael Davidovich it might be helpful to look under the hood - specifically, at the class generated for the CSP page ("View Other" in Studio/VSCode).
OnPreHTTP is special in that it runs before the page is rendered (and can e.g. redirect you somewhere else). Generally, I would put code that runs on form submit / POST in OnPreHTTP.
Where you just have <script language="Cache" runat="server">, that'll run as the page is rendered whenever it gets to that block. This would generally be used to render more complex content for which other tag-based CSP options are in sufficient. If you're familiar with PHP, this is equivalent to the <?php ... ?> block in:
<script language="Cache" method="SomeMethod"> would be used in hyperevents (i.e., #server(..SomeMethod())# and #call(..SomeMethod())#).
From a coding/design best practices perspective: you should be able to do input validation on the client to provide a friendly error message without needing to go back to the server (e.g., via #server). BUT you should also do validation on the server to make sure that even if the user (maliciously or otherwise) bypasses the client-side validation, they can't submit invalid data.
go to post
It was a whitespace issue - needed trim().
go to post
It was a whitespace issue - needed trim().