Replies:

Hi Eduard,

Much appreciate your fast response.

OK... That makes sense... so I assume the Tutorials are assuming you have a server instance on a local machine and hence the local files would then work...

Cheers,

Gordon

Hi George, Robert, Sean,

Thanks all for responding so promptly.

All comments have combined into what I needed...

Cheers,

Gordon

Code follows:

Class RestApi.Ris Extends %CSP.REST
{

XData UrlMap [ XMLNamespace = "http://www.intersystems.com/urlmap]
{
<Routes>

<Route Url="/(.*)" Method="GET" Call="RestApi.Ris:ProcessUrl"/>
<Route Url="/(.*)" Method="POST" Call="RestApi.Ris:ProcessUrl"/>
<Route Url="/(.*)" Method="PUT" Call="RestApi.Ris:ProcessUrl"/>
<Route Url="/(.*)" Method="DELETE" Call="RestApi.Ris:ProcessUrl"/>

</Routes>
}

ClassMethod ProcessUrl(capturedUrlData As %String = "", debugCspRequest As %CSP.Request = "") As %Status
{
#dim %request As %CSP.Request
#dim %response As %CSP.Response

if ((debugCspRequest '= "") && ($IsObject(debugCspRequest)) && ($ClassName(debugCspRequest) = "%CSP.Request"))
{
set %request = debugCspRequest
set %response = ##class(%CSP.Response).%New()
}

Method Implementation continues...

 

Class UnitTests.RestApi.Ris.RisUnitTests Extends Atomic.UnitTest.TestHelper
{

/*

Method OnBeforeOneTest() As %Status
{
/// Code to run Before Test/s
///
/// Quit $$$OK
}

*/
ClassMethod MockCspRequest(requestMethod As %String = "", requestUri As %String = "", jsonPayload As %String = "", authorizationToken As %String = "") As %Net.HttpRequest
{
#dim status As %Status
#dim cspRequest As %CSP.Request = ##class(%CSP.Request).%New()
set cspRequest.CharSet = "UTF-8"

if (('$Data(requestMethod)) || ($IsObject(requestMethod)) || (requestMethod = "")) return ""
if (('$Data(requestUri)) || ($IsObject(requestUri)) || (requestUri = "")) return ""

if (('$Data(jsonPayload)) || ($IsObject(jsonPayload)) || ($zStrip(jsonPayload, "<>", " ") = "")) set jsonPayload = ""

if (('$Data(authorizationToken)) || ($IsObject(authorizationToken)) || ($zStrip(authorizationToken, "<>", " ") = "")) set authorizationToken = ""
if ((authorizationToken '= "") && ('##class(RestApi.Helpers.String).IsValidGuid(authorizationToken))) return ""

#dim patternRequestMethod as %String = "\A(?i)Get|Post|Put|Delete\z"

#dim regex as %Regex.Matcher = ##class(%Regex.Matcher).%New(patternRequestMethod, requestMethod)
#dim isMatch as %Boolean = regex.Locate()

if ('isMatch) return ""

// Request Method
set requestMethod = $zConvert(requestMethod, "U")
set cspRequest.CgiEnvs("REQUEST_METHOD") = requestMethod
set cspRequest.Method = requestMethod


// URI Endpoint validation
#dim patternEndpoint as %String = "(?i)\A(https?|ftp)://([-A-Z0-9.]+)(?::(\d{1,5}))?(/[-A-Z0-9+&@#/%=~_|!:,.;]*)?(\?[A-Z0-9+&@#/%=~_|!:,.;]*)?\z"
// Standard Naming (G1 Protocol) (G2 Domain ) (G3 Port) (G4 File ) (G5 QueryParameters )
// Caché Doco Naming (G1 Protocol) (G2 Server ) (G3 Port) (G4 Location ) (G5 QueryParameters )


set regex = ##class(%Regex.Matcher).%New(patternEndpoint, requestUri)
set isMatch = regex.Locate()

if ('isMatch) return ""

#dim protocol as %String = $zConvert(regex.GroupGet(1),"L")
#dim server as %String = regex.GroupGet(2)
#dim port as %String = regex.GroupGet(3)
#dim location as %String = regex.GroupGet(4)
#dim queryParams as %String = regex.GroupGet(5)

if (protocol = "ftp") return ""
if (port > 65535) return ""


set cspRequest.CgiEnvs("REQUEST_SCHEME") = protocol

set cspRequest.CgiEnvs("REQUEST_URI") = requestUri
set cspRequest.URL = location

if (authorizationToken '= "")
{
set cspRequest.CgiEnvs("HTTP_AUTHORIZATION") = authorizationToken
}

if ((jsonPayload '= "") && (requestMethod '= "GET"))
{
#dim cspStream As %CSP.Stream = ##class(%CSP.CharacterStream).%New()

set cspStream.CharSet = "utf-8"
set cspStream.ContentType = "application/json"
set status = cspStream.MimeSectionSet(jsonPayload)

set cspRequest.Content = cspStream
}

set queryParams = $zStrip(queryParams, "<>", " ")
if (queryParams = "") return cspRequest


#dim kvpData as %String = queryParams 

#dim kvpElement as %String 
#dim key as %String 
#dim value as %String 

#dim patternKvpElement as %String = "(?i)(\??(?:[a-z0-9]*?=[a-z0-9]*?)(?:&|\z))"
#dim patternKvp as %String = "(?i)(?:\??([a-z0-9]*?)=([a-z0-9]*?)(?:&|\z))"

set regex = ##class(%Regex.Matcher).%New(patternKvpElement, kvpData)
#dim isMatchKvpElement As %Boolean = regex.Locate()

while (isMatchKvpElement)
{
set kvpElement = regex.GroupGet(1)

set regex = ##class(%Regex.Matcher).%New(patternKvp, kvpElement)
set isMatch = regex.Locate()

if (isMatch)
{
set key = regex.GroupGet(1)
set value = regex.GroupGet(2)

Set cspRequest.Data("Name",$Order(cspRequest.Data(key, ""), -1) +1) = value 
}

// Get Next KvpElement
set kvpData = $Extract(kvpData, ($Length(kvpElement) + 1), *-0)

if (kvpData '= "")
{
set regex = ##class(%Regex.Matcher).%New(patternKvpElement, kvpData)
set isMatchKvpElement = regex.Locate()
}
else
{
set isMatchKvpElement = 0
}
}

return cspRequest
}

Method TestProcessUrl()
{
// -------------------------------------------------------------------------------------------------------------------
// Arrange

#dim resultActual As %Status 
#dim resultExpected As %Status

#dim status As %Status

#dim queryString As %String = "?qParam01=123456&qParam02=ABCDEF"
#dim mockUrl As %String = "http://1.2.3.4:80/SomeLocation"_queryString


#dim dq As %String = $Char(34)
#dim message As %String = "Unit Test REST API method without Web Server and complete line by line debug"

#dim jsonPayload As %String = "{"
set jsonPayload = jsonPayload_dq_"source"_dq_":"_dq_"Gordo"_dq _","
set jsonPayload = jsonPayload_dq_"urlMethod"_dq_":"_dq_"UnitTest"_dq _","
set jsonPayload = jsonPayload_dq_"text"_dq_":"_dq_message_dq
set jsonPayload = jsonPayload_"}"


#dim cspRequest As %CSP.Request = ..MockCspRequest("Post", mockUrl, jsonPayload)
  Do $$$AssertTrue($IsObject(cspRequest), "cspRequest instance created")

#dim cspUrl As %String = cspRequest.URL
#dim cspMethod As %String = cspRequest.Method

#dim cspContentType As %String = cspRequest.ContentType



#dim patternRouteCaptue as %String = "/(.*)" // <Route Url="/(.*)"
#dim regex as %Regex.Matcher = ##class(%Regex.Matcher).%New(patternRouteCaptue, cspUrl)
#dim isMatch as %Boolean = regex.Locate()
  Do $$$AssertTrue(isMatch, "Route has capturedUrlData")
 
  #dim capturedUrlData As %String = regex.GroupGet(1)


// -------------------------------------------------------------------------------------------------------------------
// Act / Assert

set resultActual = ##class(RestApi.Ris).ProcessUrl(capturedUrlData, cspRequest)

Method Implementation continues...
 

Hi George,

I'm most interested in your Question on Unit Testing a REST service.

The approach I've taken seems similar to yours. Unfortunately I've not yet cracked a working Unit Test implementation for this scenario.

Equally I had already studied the documentation that 'Robert Cemper' suggested in his answer links. Also I note in the following link:
 http://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY=...

that a bunch of the %CSP.Stream methods are being deprecated from 2016.1 on. I have been unable to locate their replacement or alternative approach.

If you, Robert or anyone in the community can supply a working code sample of how to set the parameters of a %CSP.Request object would be much appreciated. 

The following code compiles but fails on execution.

    #dim status As %Status

    #dim cspRequest As %CSP.Request = ##class(%CSP.Request).%New()

    set status = cspRequest.Content.ContentTypeSet("application/json") => Fails => OREF Failure => I assume to do with %CSP.Stream


My aim with the Unit Test is to somehow have the class that Extends %CSP.REST be instansiated or ingest the cspRequest As %CSP.Request. This would allow for directly debugging the ClassMethods of the %CSP.REST class.

Much appreciate your assistance.

Cheers,

Gordon
 

Followers:
Gordon has no followers yet.
Following:
Gordon has not followed anybody yet.
Global Masters badges:
Gordon has no Global Masters badges yet.