go to post André-Claude Gendron · May 13, 2024 That would work and is a clean solution. This is what I expected from the the framework.
go to post André-Claude Gendron · May 10, 2024 I appreciate the suggestion. However this would only work for a JSON Export and not a JSON Import.
go to post André-Claude Gendron · Apr 11, 2024 Here we are using the mocking framework that we developed (GitHub - GendronAC/InterSystems-UnitTest-Mocking: This project contains a mocking framework to use with InterSystems' Products written in ObjectScript Have a look at the https://github.com/GendronAC/InterSystems-UnitTest-Mocking/blob/master/S... class. Instead of calling ..SendRequestAsync we do ..ensHost.SendRequestAsync(...) Doing so enables us to create Expectations (..Expect(..ensHost.SendRequestAsync(.... Here a code sample : Class Sample.Src.CExampleService Extends Ens.BusinessService { /// The type of adapter used to communicate with external systems Parameter ADAPTER = "Ens.InboundAdapter"; Property TargetConfigName As %String(MAXLEN = 1000); Parameter SETTINGS = "TargetConfigName:Basic:selector?multiSelect=0&context={Ens.ContextSearch/ProductionItems?targets=1&productionName=@productionId}"; // -- Injected dependencies for unit tests Property ensService As Ens.BusinessService [ Private ]; /// initialize Business Host object Method %OnNew( pConfigName As %String, ensService As Ens.BusinessService = {$This}) As %Status { set ..ensService = ensService return ##super(pConfigName) } /// Override this method to process incoming data. Do not call SendRequestSync/Async() from outside this method (e.g. in a SOAP Service or a CSP page). Method OnProcessInput( pInput As %RegisteredObject, Output pOutput As %RegisteredObject, ByRef pHint As %String) As %Status { set output = ##class(Ens.StringContainer).%New("Blabla") return ..ensService.SendRequestAsync(..TargetConfigName, output) } } Import Sample.Src Class Sample.Test.CTestExampleService Extends Tests.Fw.CUnitTestBase { Property exampleService As CExampleService [ Private ]; Property ensService As Ens.BusinessService [ Private ]; ClassMethod RunTests() { do ##super() } Method OnBeforeOneTest(testName As %String) As %Status { set ..ensService = ..CreateMock() set ..exampleService = ##class(CExampleService).%New("Unit test", ..ensService) set ..exampleService.TargetConfigName = "Some test target" return ##super(testName) } // -- OnProcessInput tests -- Method TestOnProcessInput() { do ..Expect(..ensService.SendRequestAsync("Some test target", ..NotNullObject(##class(Ens.StringContainer).%ClassName(1))) ).AndReturn($$$OK) do ..ReplayAllMocks() do $$$AssertStatusOK(..exampleService.OnProcessInput()) do ..VerifyAllMocks() } Method TestOnProcessInputFailure() { do ..Expect(..ensService.SendRequestAsync("Some test target", ..NotNullObject(##class(Ens.StringContainer).%ClassName(1))) ).AndReturn($$$ERROR($$$GeneralError, "Some error")) do ..ReplayAllMocks() do $$$AssertStatusNotOK(..exampleService.OnProcessInput()) do ..VerifyAllMocks() } }
go to post André-Claude Gendron · Nov 15, 2023 We are sending SMS to Twilio through a generic http operation in an Ensemble Production. Works well. We wrote a simple Process that catches HTTP 429 errors (their API documentation has a requirement about this).
go to post André-Claude Gendron · May 10, 2023 You could have a 0 day Ens.Util.Purge task running every 5 mins and clearing the production messages. That way you could use only built-in components such as the hl7 tcp service and hl7 file operation
go to post André-Claude Gendron · Apr 12, 2023 ClassMethod GetContentJSON() { set xData = ##class(%Dictionary.CompiledXData).%OpenId(..%ClassName(1) _ "||Content") set jsonObj = [].%FromJSON(xData.Data) write jsonObj.%ToJSON() } XData Content [ MimeType = application/json ] { [[12,33], [88,44]] }
go to post André-Claude Gendron · Nov 25, 2022 Here are a few code samples that could help : Class YourPackage.REST.CSoapAuthenticator Extends %CSP.REST { Parameter CONTENTTYPE = "text/xml"; XData UrlMap [ XMLNamespace = "http://www.intersystems.com/urlmap" ] { <Routes> <Route Url="/:soapService" Method="POST" Call="PostSOAP"/> </Routes> } ClassMethod PostSOAP( strSoapService As %String = "", test As %Integer = 0) As %Status { #Dim %request As %CSP.Request #Dim %response As %CSP.Response #Dim httpClient As %Net.HttpRequest = ..GetLoopbackSOAPClient() do httpClient.EntityBody.Write(..UpdateSoapBody(%request.Content.Read($$$MaxStringLength))) do httpClient.SetHeader("SOAPAction", %request.SoapAction) do httpClient.Post($System.CSP.GetDefaultApp($Namespace) _ "/" _ strSoapService, test) set %response.ContentType = "text/xml" write httpClient.HttpResponse.Data.Read($$$MaxStringLength) return $$$OK } // -- Private utils -- ClassMethod GetLoopbackSOAPClient() As %Net.HttpRequest [ Private ] { set httpClient = ##class(%Net.HttpRequest).%New() set httpClient.Server = ... set httpClient.Port = ... set httpClient.Timeout = 5 set httpClient.Https = 1 set httpClient.SSLConfiguration = ... return httpClient } ClassMethod UpdateSoapBody(strInput As %String) As %String [ Private ] { #Dim strSoap As %String = "" #Dim username As %String = ... (Extract from Input) #Dim password As %String = ... (Extract from Input) set strSoap = strSoap _ ... (Copy soap enveloppe from input) set strSoap = strSoap _ " <soap:Header>" _ ..GenerateSecurityHeader(username, password) _ " </soap:Header>" set strSoap = strSoap _ " <soap:Body>" ... set strSoap = strSoap _ " </soap:Body>" set strSoap = strSoap _ "</soap:Envelope>" return strSoap } ClassMethod GenerateSecurityHeader( strUsername As %String, strPassword As %String) As %String [ Private ] { set header = ##class(%SOAP.Security.Header).%New() set usernameToken = ##class(%SOAP.Security.UsernameToken).Create(strUsername, strPassword) do header.AddSecurityElement(usernameToken) return ... (Use XML Writer to Output header to a String.) } }
go to post André-Claude Gendron · Nov 16, 2022 I ended-up creating a %CSP.Rest class that acts as a proxy which reordered the fields in order to generate a standard SOAP request with the proper headers. Works great for a minimum of code.
go to post André-Claude Gendron · May 13, 2022 I just remembered, I fixed this but was waiting for a review. I merged it this morning. https://github.com/GendronAC/InterSystems-UnitTest-Mocking/pull/3 (code was sent to github per InterSystems request) Latest code is here : https://github.com/GendronAC/InterSystems-UnitTest-Mocking Let me know if you need something else. Have a look at the CTestCustomPassthroughOperation.cls class
go to post André-Claude Gendron · May 13, 2022 Yes the mocking framework is still under active development here. I'm sorry there are missing classes in the provided example. I'll completely forgot about my reply a year ago... Yes testing business hosts works very well with it. I'll try to arrange something today and I'll reply here. If I don't, reply back !
go to post André-Claude Gendron · Sep 15, 2021 Is is still recommended to separate the Globals and Routines ? What's the major benefit of it ? Rapid deployment by switching the Routine database ?
go to post André-Claude Gendron · Jun 18, 2021 I would be very much interested in your findings. I already started something that is producing a CSV file with a summary of a production. Perhaps this could be helpful to the community, contact me in private since I can't attach a file. This is not ment for Archi mate but perhaps you can be inspired by it.
go to post André-Claude Gendron · May 26, 2021 Sorry about that, I will commit them in the next few days or perhaps tonight. At the time they were not added to the repo because of dependencies but I'm sure I can arrange something. Plus I'll add the latest development we did at CIUSSSE-CHUS. I'm glad someone else uses it ! Kind regards, AC
go to post André-Claude Gendron · Oct 14, 2020 I know this is an old post and I don't expect a reply but is there a way to enable SNI or are the headers added by default ?
go to post André-Claude Gendron · Feb 26, 2019 Thank you, I will have a look at that and also, I'm replicating my setup on a redhat gitlab-runner. I'll update this post if I find my way out of this on Windows. I also noticed that the "ENVIRONMENT" variables were not passed appropriately in a way that csession understands. The $system.Util.GetEnviron("CI_PROJECT_DIR") and $system.Util.GetEnviron("CI_COMMIT_SHA") calls both returns an empty string. Perhaps the <NOTOPEN> is related to the way the stdout is read in windows.
go to post André-Claude Gendron · Feb 26, 2019 Hi Eduard,I had a look at your continuous delivery articles and found them awesome! I tried to set up a similar environment but I'm struggling with a detail... Hope you'll be able to help me out.I currently have a working gitlab-runner installed on my Windows Laptop with a working Ensemble 2018.1.1 with the isc.gitlab package you provided.C:\Users\gena6950>csession ENS2K18 -U ENSCHSPROD1 "##class(isc.git.GitLab).test()"===============================================================================Directory: C:\Gitlab-Runner\builds\ijGUv41q\0\ciussse-drit-srd\ensemble-continuous-integration-tests\Src\ENSCHS1\Tests\Unit\===============================================================================[...]Use the following URL to view the result:http://10.225.31.79:8971/csp/sys/%25UnitTest.Portal.Indices.cls?Index=23&$NAMESPACE=ENSCHSPROD1All PASSEDDC:\Users\gena6950>I had to manually "alter" the .yml file because of a new bug with parenthesis in the gitlab-runner shell commands (see https://gitlab.com/gitlab-org/gitlab-runner/issues/1941). Relevant parts of this file are there (the file itself is larger but I think it's irrelevant). I put a "Echo" there to see how the command was received by the runner.stages: - load - test - packagevariables: LOAD_DIFF_CMD: "##class(isc.git.GitLab).loadDiff()" TEST_CMD: "##class(isc.git.GitLab).test()" PACKAGE_CMD: "##class(isc.git.GitLab).package()".script_test: &script_test stage: test script: - echo csession ENS2K18 -U ENSCHSPROD1 "%TEST_CMD%" - csession ENS2K18 -U ENSCHSPROD1 "%TEST_CMD%" artifacts: paths: - tests.htmlAnd this is the output seen by the gitlab output : Running with gitlab-runner 11.7.0 (8bb608ff) on Laptop ACGendron ijGUv41qUsing Shell executor...Running on CH05CHUSHDP1609...Fetching changes...Removing tests.htmlHEAD is now at b1ef284 Ajout du fichier de config du pipeline GitlabChecking out b1ef284e as master...Skipping Git submodules setup$ echo csession ENS2K18 -U ENSCHSPROD1 "%TEST_CMD%"csession ENS2K18 -U ENSCHSPROD1 "##class(isc.git.GitLab).test()"$ csession ENS2K18 -U ENSCHSPROD1 "%TEST_CMD%"<NOTOPEN>>ERROR: Job failed: exit status 1I'm pretty sure it must be a small thing but I can't put my finger on it!Hope you'll be able to help!Kind regardsAndre-Claude