Stefan Cronje · Feb 2, 2022 go to post

The files are .cls.

I have noticed now a popup error on the bottom right regarding the Java Runtime Environment and sonarlint.
I will look into this first, I probably missed instructions somewhere.

I installed the latest JDK, then updated the sonarlint JavaHome setting to align.

I am getting the following now, and I have no idea on how to resolve it.
Unable to load component class org.sonarsource.sonarlint.core.analyzer.sensor.PhaseExecutor

Stupid question: Do I need to be running a SonarQube locally?

Stefan Cronje · Jan 19, 2022 go to post

Hi all,

I am also having an issue on the code coverage. On my side, there is not an error, but there are no results. 
Version: IRIS 2021.1

===============================================================================
Directory: C:\Tmp\UnitTests\MLI2\Ens\Helper\
===============================================================================
  MLI2\Ens\Helper begins ...
List items in directory started on 01/19/2022 14:18:42 '*.xml;*.XML;*.cls;*.mac;*.int;*.inc;*.CLS;*.MAC;*.INT;*.INC' Listing file C:\Tmp\UnitTests\MLI2\Ens\Helper\UnitTests.cls as udl
List finished successfully.     MLI2.Ens.Helper.UnitTests begins ...
      TestCheckAndLoadJSON() begins ...
        AssertStatusOK:Invalid Content-type. Status = OK (passed)
        AssertNotTrue:Invalid Content-type. Object = nulloref (passed)
        AssertStatusNotOK:Invalid Content-type. Validation Status = Error (passed)
        AssertEquals:Invalid Content-type. Validation SC Code(5913) = 5913 (passed)
        AssertStatusOK:No Content. Status = OK (passed)
        AssertNotTrue:No Contente. Object = nulloref (passed)
        AssertStatusNotOK:No Content. Validation Status = Error (passed)
        AssertEquals:No Content. Validation SC Code(16003) = 16003 (passed)
        AssertStatusOK:Invalid class name arg. Status = OK (passed)
        AssertNotTrue:Invalid class name arg. Object = nulloref (passed)
        AssertStatusNotOK:Invalid class name arg. Validation Status = Error (passed)
        AssertEquals:Invalid class name arg. Validation SC Code(5760) = 5760 (passed)
        AssertStatusOK:Invalid JSON. Status = OK (passed)
        AssertNotTrue:Invalid JSON. Object = nulloref (passed)
        AssertStatusNotOK:Invalid JSON. Validation Status = Error (passed)
        LogMessage:Validation SC: ERROR #5035: General exception Name 'Parsing error' Code '3' Data ''
        AssertStatusOK:Invalid Property Value. Status = OK (passed)
        AssertNotTrue:Invalid Property Value. Object = nulloref (passed)
        AssertStatusNotOK:Invalid Property Value. Validation Status = Error (passed)
        AssertEquals:Invalid property value. Validation SC Code(5802) = 5802 (passed)
        AssertStatusOK:Positive. Status = OK (passed)
        AssertTrue:Positive. Object Is Valid (passed)
        AssertStatusOK:Positive. Validation Status = OK (passed)
        AssertEquals:Positive. Object Name = MLI2.Ens.Helper.UnitTests.JSONObject (passed)
        AssertEquals:Positive. tObj.Name = Jon (passed)
        AssertEquals:Positive. tObj.Surname = Snow (passed)
        AssertEquals:Positive. tObj.Age = 35 (passed)
        LogMessage:Duration of execution: .00114 sec.
      TestCheckAndLoadJSON passed
      TestCreateJSONOutput() begins ...
        AssertStatusNotOK:Non-JSON Obj. Status = Error (passed)
        AssertEquals:Non-JSON Obj. Out Stream size = 0 (passed)
        AssertStatusOK:JSON Obj. Status = OK (passed)
        AssertEquals:JSON Obj. Out Stream = expected JSON output (passed)
        LogMessage:Duration of execution: .002102 sec.
      TestCreateJSONOutput passed
      TestGetCSPSessionId() begins ...
        AssertStatusOK:No %session. sc = OK (passed)
        AssertNotTrue:No %session. IsCSP = 0 (passed)
        AssertEquals:No %session. SessionId = "" (passed)
        AssertStatusOK:Has %session. sc = OK (passed)
        AssertTrue:Has %session. IsCSP = 1 (passed)
        AssertEquals:Has %session. SessionId = 12DFzjjakl (passed)
        LogMessage:Duration of execution: .000125 sec.
      TestGetCSPSessionId passed
    MLI2.Ens.Helper.UnitTests passed
  Skipping deleting classes 
  MLI2/Ens/Helper passed ===============================================================================
Directory: C:\Tmp\UnitTests\MLI2\Ens\Helper\UnitTests\
===============================================================================
  MLI2\Ens\Helper\UnitTests begins ...
List items in directory started on 01/19/2022 14:18:42 '*.xml;*.XML;*.cls;*.mac;*.int;*.inc;*.CLS;*.MAC;*.INT;*.INC' Listing file C:\Tmp\UnitTests\MLI2\Ens\Helper\UnitTests\FauxCSPSession.cls as udl
Listing file C:\Tmp\UnitTests\MLI2\Ens\Helper\UnitTests\JSONObject.cls as udl
Listing file C:\Tmp\UnitTests\MLI2\Ens\Helper\UnitTests\NonJSONObject.cls as udl
List finished successfully.   Skipping deleting classes 
  MLI2/Ens/Helper/UnitTests passed Mapping to class/routine coverage: .000221 seconds
Aggregating coverage data: .000185 seconds
No code coverage found (!) Use the following URL to view the result:
http://192.168.8.198:52773/csp/sys/%25UnitTest.Portal.Indices.cls?Index=147&$NAMESPACE=LIBSDEPO
Use the following URL to view test coverage data:
http://LAPTOP-H4GR74VJ:52773/csp/libsdepo/TestCoverage.UI.AggregateResultViewer.cls?Index=22
All PASSED

I've tried this this with RunTest and RunAllTests.
After running the tests:

LIBSDEPO>w $System.Status.GetErrorText(%objlasterror)
ERROR #6061: The Monitor is not running

Any advice will be appreciated.

Stefan Cronje · Oct 30, 2021 go to post

Good answer. If I may add.

You can't use Output or ByRef arguments on these functions, or let me rather say that I have not gotten it to work.

What you can do is return a collection type property, or you can pass in the context as a parameter to set properties on the context.
If you are wondering how to reference a context in a ruleset, add a property to you context of type %RegisteredObject and call it something like RefToSelf. Set the property to the OREF of the context once the context has been created.
Then in the rulefunction call, you pass in RefToSelf.

Stefan Cronje · Sep 29, 2021 go to post

Hi,

My 2c on this, and maybe I am missing something or do not know how to use these VSCode extensions correctly.
The single source of truth principle can't really be applied when using these extensions, as BPLs, transformations, and rulesets should still be edited in the Management Portal or in Studio.

Because there is not a sync functionality, I have seen devs overwriting changes on BPLs, etc., when they import and compile from VSCode. You have to explicitly export it on the server explorer.

Please correct me if I'm mistaking.

Stefan Cronje · Jun 11, 2021 go to post

Just to keep you informed.

I did a few tests. The more columns selected, the slower the output is, and quite significantly.

Stefan Cronje · Jun 10, 2021 go to post

Thanks. I do not need a sample. I was just hoping I do not have to code it. But it is simple enough to do.

It is the per process memory where the limitation comes in I think. If you do that test with limited per process memory, it might be a different story. It may even be a difference in how files are handled within Cache on Windows vs. Unix.

Stefan Cronje · Mar 2, 2021 go to post

Thank you for all the information and guidelines. I would like to go the IAM route within the cluster, which I think will be the most practical.
If you do have time available, I will take you up on the offer for an IAM example.

Stefan Cronje · Feb 25, 2021 go to post

I have a question regarding productionized deployments.
Can the internal IRIS web-server be used, i.e. Port 52773?
Or should there still be a web-gateway between IAM and the IRIS instance?

Regarding Kubernetes:
I would think that IAM should be the ingress, is that correct?

Stefan Cronje · Jan 13, 2021 go to post

Thank you for the answers.

I've only used the XML format up to now, where we create builds by exporting projects to XML and then import. The OBJ Load seems like it is what I need.

Thank you again.

Stefan Cronje · Jan 13, 2021 go to post

It is not as straightforward as a Docker's solution. Even if using a container, the code will need to be pulled from github and loaded into Cache/Ensemble/IRIS. r

In the multi-developer environment, with multiple packages in different repositories, and projects using their own repos with dependencies on the packages from other repos, it is necessary to be able to take the "raw" source from github and importing it. The only way I know of importing code, is using the XML format.

The simplest will be if Cache/Ensemble/IRIS had a tool to create an XML in the correct format from the source files.
Another more difficult way is to write code that uses the code api in Cache to load the code and then export it to XML.
This is a lot of work with possible defects that will slow the process down. The idea behind tools like github and TravisCI, is to make work less, not more.

I think in order to make CI/CD with real-world SDLC processes and source control easier to utilise, that a tool like this should come standard with the IS products. If there is already a way which I do not know of, it will be great. If not, this is quite a short-fall in the product that canv run containerised and promotes CI/CD.

Stefan Cronje · Oct 8, 2020 go to post

Try it with between 1 and 5 on the %VID. Just as slow. It is not about the 0 result, but about the time it takes.

The count on prop1=2 is around 2.7M/

Regarding the index:
Index idx On (prop1, prop3) [ Type = bitmap ];

I can't create an index on every possible filter and order by combination. The client selects what to filter on and what to order by.

We use single field indices to cater for this, and combined field indexes for uniqueness constraints. 

Stefan Cronje · Oct 8, 2020 go to post

Let's change the data and then test it with an order by:
Prop1 is i %Integer with valuelist of 1 to 10. Populated randomly, with 60% of the values being 2.
Prop2 is can stay as is and not relevant in this test.
Prop3 is a %String of length 20. Populate with 4M random values.
Prop1 has a bitmap index.
Prop2 has a bitmap index.
Prop3 has an index.

To use order by, it needs to look like this, and this is a lot slower:
select %ID,prop3 
from mp.test 
where %ID in 
  (SELECT * FROM 
    (SELECT TOP ALL %ID
     FROM mp.test 
     WHERE prop1 = 2
     ORDER BY prop3
  
  WHERE %VID BETWEEN 3000000 AND 30000200
)

Class mp.test Extends (%Persistent, %Populate)
{

Property prop1 As %Integer(POPSPEC = ".PopulateProp1()", VALUELIST = ",1,2,3,4,5,6,7,8,9,10");

Property prop2 As %Boolean(POPSPEC = "Integer(0,1)");

Property prop3 As %String(MAXLEN = "", POPSPEC = "LastName()");

Index prop1Index On prop1 [ Type = bitmap ];

Index prop2Index On prop2 [ Type = bitmap ];

Index prop3Index On prop3;

ClassMethod Fill(total)
{
    ;d DISABLE^%NOJRN
    ;d ..%KillExtent()
    ;do ..Populate(5000000)
}

Method PopulateProp1() As %Integer
{
    set tInt = $random(19) + 1
    set:(tInt > 10) tInt = 2
    return tInt
}

ClassMethod Query()
{
    s sql=##class(%SQL.Statement).%New()
    s query = "select %ID,prop3 from mp.test where %ID in  (SELECT * FROM  (SELECT TOP ALL %ID FROM mp.test  WHERE prop1 = 2 ORDER BY prop3) WHERE %VID BETWEEN 3000000 AND 30000005)"
    w !,"Query Before Prepare:  ",$zh
    s sc=sql.%Prepare(query)
    w !,"Query After Prepare:  ",$zh
    i $$$ISOK(sc) {
        s rset=sql.%Execute()
        w !,"Query After Execute:  ",$zh
        i 'rset.%SQLCODE {
            s t1=$zh
            d rset.%Next()
            w $zh-t1,!
            d rset.%Display()
        }
        w !,"Query All Processed:  ",$zh
    } else {
        w $System.Status.GetErrorText(sc)
    }
}

/// d ##class(mp.test).Test()
ClassMethod Test()
{
    w !,"Before fill: ",$zh
    d ..Fill()
    w !,"After fill: ",$zh
    do ..Query()
}

}

Terminal Output:

DEV>d ##class(mp.test).Test()
 
Before fill: 84807.575139
After fill: 84807.575144
Query Before Prepare:  84807.575158
Query After Prepare:  84807.666853
Query After Execute:  84807.6669688.009005
ID      prop3
 
0 Rows(s) Affected
Query All Processed:  84815.676129

Stefan Cronje · Oct 7, 2020 go to post

Have you tried that with an order by on one of the fields?

When doing the order by, you need to select a top all on the inner query so that it can order by. 

The sorting needs to happen before the %VID filters areapplied.
Example: Filter on a property that has a bitmap index for many records.
order by another property wich is an alphanumeric value, which is not unique.

Stefan Cronje · Oct 7, 2020 go to post

Yes. The top all kills the performance.

59.516 seconds from 7.8 seconds without the order by and top all.

Stefan Cronje · Oct 7, 2020 go to post

I am having similar issues.
The speed is faster, but the order by is necessary.

Our table holds around 5M entries, with the select done as per above, it still takes 7 to 8 seconds to load each page, which is unacceptable for my client.

Stefan Cronje · Oct 25, 2018 go to post

I have not looked at RESTForms, so I can only provide a biased opinion on the DynamicObject Adapter.

We have used this for REST CRUD interfaces. This enabled us to use the same message structure classes for SOAP, REST XML and REST JSON interfaces. On the REST interfaces we use the ContentType to determine whether we should use the XML Reader to parse or the DynamicObject adapter. After the parsing, we encapsulate the message instance in an Ensemble message to invoke a business service in the cases where it is not just CRUD.

Stefan Cronje · Oct 25, 2018 go to post

Resolved this by adding a Rule Function and using it in the Rule Set.

Rule Class:

Class Test.TestRuleFunction Extends Ens.Rule.FunctionSet
{

/// GetAt implementation for rulesets
ClassMethod CollectionGetAt(ByRef pCollection, pKey As %String) As %Integer [ CodeMode = expression, Final ]
{
pCollection.GetAt(pKey)
}

}

Rule set expression

CollectionGetAt(ReturnValues,"CalculatedValue")

Stefan Cronje · Oct 23, 2018 go to post

Great stuff. Thanks. Where can I get the sample files and/or some instructions on the use of Kubernetes as demonstrated?

Stefan Cronje · Oct 21, 2018 go to post

Thanks. I think that is one of the sessions I wanted to attend, but never got to it. I still need to go watch all the ones I wanted to attend, but had to choose between sessions or got pulled into meetings.

Stefan Cronje · Oct 20, 2018 go to post

Thanks for the post. I am looking forward to 2019.1.

Regarding the following statement:
"application>.disp: dispatch class ready to use in the CSP application. It extends %CSP.REST and define the XData UrlMap. This class is read-only and marked as system class (by default is hidden in Atelier)."
- My opinion is that is should not be hidden by default. I would like to add it to the git repo to package it with a version.

A question on the "impl" file. What happens if I have implementation code in it already and get an updates Swagger and generate it again? Does is overwrite the code or does it keep my code and add the new methods, etc.?

Stefan Cronje · Oct 20, 2018 go to post

You cab create a new include file or add the following to one of your existing include files
#define true 1
#define false 0

Then in your class, include this include file and use as follows:
set varName = $$$true

Stefan Cronje · Oct 20, 2018 go to post

Hi Evgeny,

Thank you for the suggestion.

We still then need to keep on developing primarily on Ensemble and once we release, then we create a release file for IRIS, which sounds good. This does create the risk of testing something on Ensemble and it maybe does not work on IRIS.

Every project has its own set of classes as well in addition to the shared code libraries. On these project specific classes, we may want to use new IRIS features. This creates the issue that I can't develop on Ensemble and only build and IRIS release. Not sure if you understand what I am getting at. The idea was that if a dev works on one of these projects, he/she only changes the server connection in Atelier, synchronise, compile and work. If that person needs to work on another project on Ensemble, the repeats the steps above. The git repo takes care of the source management, even though we are on different InterSystems products.

We use a local git repository on one of our servers.

Stefan Cronje · Oct 13, 2018 go to post

Missed that bit. I was only looking at the part I wanted. Such a typical developer thing to do wink

Stefan Cronje · Oct 13, 2018 go to post

Thanks. Appreciate it. If  I'm writing a method that uses this class in another namespace, I should be able to just zn to %SYS in the code in order to use the class.

Stefan Cronje · Oct 13, 2018 go to post

Thanks. I will try from the %SYS namespace. I was trying to access it in another namespace. It also does not show in the class explorer. One of those "hidden" features.

Stefan Cronje · Oct 13, 2018 go to post

I am using Ensemble 2017.2 and the Config.MapGlobals query is not available.

Do you know how I can list the mapped globals of a namespace on 2017.2?

Stefan Cronje · Oct 8, 2018 go to post

To implement a pause prior to continuing the loop, use the hang statement.

The code provided above is perfect for all the other requirement. After the closing bracket of the "catch", add "hang 10" for a ten second "sleep".

You should also add a mechanism to stop this iteration somehow. It will be good practice.

ClassMethod Start()
{

  
    While (^RunMyApp = 1) {
        try {
            do ..YourMainMethod()
        } catch err {
            //log error here
        }
        hang 10
    }

If you then want to stop your code from running, open another terminal or use the Management Portal and set the global value:
set ^RunMyApp = 0