MockMvc perform, array response assertion fail - spring-boot

I am implementing integration tests for Spring Boot. One of my endpoint gives back all the users, even the deleted ones. Here deleted means the deleted boolean attribute is set to true on AppUser Entity (~soft delete).
The endpoint works perfectly, I have manual tested with Postman (you can see below the response). The code:
#Test
void testGetAllAppUsers_whenAuthorizedOnlyActiveFalse_gotDeletedUser() throws Exception {
String token = jwtProvider.generateToken(TestUtils.ACCOUNT_MANAGER_USERNAME);
String url = "/api/account/user";
mvc.perform(get(url)
.header("Authorization", token)
.param("only-active", "false"))
.andExpect(status().isOk())
.andExpect(jsonPath("$[*].deleted").value(Matchers.arrayContaining(true)));
}
the response:
...
Body = [{"id":7,"username":"ablabadmin#account.com","fullName":"Alpha Beta Lab Admin","deleted":false,"labsAsUser":[],"labsAsAdmin":[],"roles":[],"managedLabs":[]},{"id":11,"username":"ablabdeleteduser#account.com","fullName":"Alpha Beta Lab Deleted User","deleted":true,"labsAsUser":[],"labsAsAdmin":[],"roles":[],"managedLabs":[]},{"id":4,"username":"ablabman#account.com","fullName":"Alpha Beta Lab Manager","deleted":false,"labsAsUser":[],"labsAsAdmin":[],"roles":[],"managedLabs":[{"id":1,"key":"alab","name":"Alpha Lab","deleted":false,"createdAt":"2021-06-09","updatedAt":null,"labManagerUsernames":["alabman#account.com","ablabman#account.com"]},{"id":2,"key":"blab","name":"Beta Lab","deleted":false,"createdAt":"2021-06-09","updatedAt":null,"labManagerUsernames":["blabman#account.com","ablabman#account.com"]}]},{"id":10,"username":"ablabuser#account.com","fullName":"Alpha Beta Lab User","deleted":false,"labsAsUser":[],"labsAsAdmin":[],"roles":[],"managedLabs":[]},{"id":5,"username":"alabadmin#account.com","fullName":"Alpha Lab Admin","deleted":false,"labsAsUser":[],"labsAsAdmin":[],"roles":[],"managedLabs":[]},{"id":2,"username":"alabman#account.com","fullName":"Alpha Lab Manager","deleted":false,"labsAsUser":[],"labsAsAdmin":[],"roles":[],"managedLabs":[{"id":1,"key":"alab","name":"Alpha Lab","deleted":false,"createdAt":"2021-06-09","updatedAt":null,"labManagerUsernames":["alabman#account.com","ablabman#account.com"]}]},{"id":8,"username":"alabuser#account.com","fullName":"Alpha Lab User","deleted":false,"labsAsUser":[],"labsAsAdmin":[],"roles":[],"managedLabs":[]},{"id":1,"username":"aman#account.com","fullName":"Account Manager","deleted":false,"labsAsUser":[],"labsAsAdmin":[],"roles":[{"id":1,"role":"ACCOUNT_MANAGER"}],"managedLabs":[]},{"id":6,"username":"blabadmin#account.com","fullName":"Beta Lab Admin","deleted":false,"labsAsUser":[],"labsAsAdmin":[],"roles":[],"managedLabs":[]},{"id":3,"username":"blabman#account.com","fullName":"Beta Lab Manager","deleted":false,"labsAsUser":[],"labsAsAdmin":[],"roles":[],"managedLabs":[{"id":2,"key":"blab","name":"Beta Lab","deleted":false,"createdAt":"2021-06-09","updatedAt":null,"labManagerUsernames":["blabman#account.com","ablabman#account.com"]}]},{"id":9,"username":"blabuser#account.com","fullName":"Beta Lab User","deleted":false,"labsAsUser":[],"labsAsAdmin":[],"roles":[],"managedLabs":[]}]
Forwarded URL = null
Redirected URL = null
Cookies = []
java.lang.AssertionError: JSON path "$[*].deleted"
Expected: [<true>]
but: was a net.minidev.json.JSONArray (<[false,true,false,false,false,false,false,false,false,false,false]>)
Expected :[<true>]
Actual :a net.minidev.json.JSONArray (<[false,true,false,false,false,false,false,false,false,false,false]>)
...
I have tried out many other arguments: "true", false I have tried out contains method, and I ave tried out with "$[*].username" regex with an existing username, but every time I got AssertionError.
Can you please help me? There is definitely something I am missing. Also any advice is welcomed, since I am relatively new in Spring integration testing. Thanks in advance!

arrayContainingInAnyOrder(true,false) should work in this case.
But,
The test case would not have any value, even if it works with arrayContainingInAnyOrder(true,false).
As you can see, that [*].deleted returns value of deleted for all objects present in the response. The test must verify specific value.
For Example, If you are expecting that first user should have true then assert that $.[?(#.id ==1)].deleted is true.

Related

coVerify fails when running multiple tests but succeeds if the test is run alone

I am using open weather map to get weather data. For this I call the api like this:
openWeatherMapAPI.oneCall().historical()
.byCoordinateAndTimestamp(
Coordinate.of(latitude.toDouble(), longitude.toDouble()),
startDateTime.toEpochSecond()
)
.language(Language.ENGLISH)
.unitSystem(UnitSystem.METRIC)
.retrieve()
.asJava()
To mock this I use
mockkConstructor(OpenWeatherMapClient::class)
coEvery {
anyConstructed<OpenWeatherMapClient>().oneCall()
.historical().byCoordinateAndTimestamp(any(), any())
.language(Language.ENGLISH)
.unitSystem(UnitSystem.METRIC)
.retrieve()
.asJava()
} returns testUtilsImplementation.getSuccessfulHistoricalWeatherResponse()
And to verify calls this:
coVerify(exactly = 5) {
anyConstructed<OpenWeatherMapClient>().oneCall()
.historical().byCoordinateAndTimestamp(any(), any())
.language(Language.ENGLISH)
.unitSystem(UnitSystem.METRIC)
.retrieve()
.asJava()
}
If I run this test alone, everything is fine but when I run multiple tests at the same time the coVerify fails.
Verification failed: call 1 of 7: OpenWeatherMapClient(mockkConstructor<OpenWeatherMapClient>()).oneCall()) was not called
The things I dont understand are:
I would expect it to fail because of too many calls. But according to the message it isnt even called once
where is the 7 coming from?
Adding unmockkConstructor(OpenWeatherMapClient::class) or unMockAll() or clearAllMocks() changes nothing
Can anyone point me in a direction?

MIP SDK fails to protect files

I'm using MIP file sample command line interface to apply labelling.
When trying to apply a label that has protection set, i got "Label requires ad-hoc protection, but protection has not yet been set" error.
Therefore, I tried protecting the file using "--protect" option and got the following error message:
"Something bad happened: The service didn't accept the auth token. Challenge:['Bearer resource="https://aadrm.com", realm="", authorization="https://login.windows.net/common/oauth2/authorize"'], CorrelationId=ce732e4a-249a-47ec-a7c2-04f4d68357da, CorrelationId.Description=ProtectionEngine, CorrelationId=6ff992dc-91b3-4610-a24d-d57e13902114, CorrelationId.Description=FileHandler"
This is my auth.py file:
def main(argv):
client_id = str(argv[0])
tenant_id = str(argv[1])
secret = str(argv[2])
authority = "https://login.microsoftonline.com/{}".format(tenant_id)
app = msal.ConfidentialClientApplication(client_id, authority=authority, client_credential=secret)
result = None
scope = ["https://psor.o365syncservice.com/.default"]
result = app.acquire_token_silent(scope, account=None)
if not result:
logging.info("No suitable token exists in cache. Let's get a new one from AAD.")
result = app.acquire_token_for_client(scopes=scope)
if "access_token" in result:
sys.stdout.write(result['access_token'])
else:
print(result.get("error"))
print(result.get("error_description"))
print(result.get("correlation_id")) # You may need this when reporting a bug
if __name__ == '__main__':
main(sys.argv[1:])
I tried to change the scope to ["https://aadrm.com/.default"] and then I was able to protect the file, but when I try getting the file status or try applying label on it I get the same error message with bad auth token.
These are the permissions as configured in azure portal:
Thank you
I think that scope you have is incorrect: https://psor.o365syncservice.com/.default
It should be https://syncservice.o365syncservice.com/.default.
A good way to handle this is to just append .default to whatever resource the AcquireToken() call gets in the resource param. Something like this.

Spring boot - JPA matcher not working when I set the "username" variable

I starting to learn the spring boot. I tried many times that I haven't been solved one problem. Users class has username variable. I want to check if username exist our database and throw exception as error message.
ExampleMatcher matcher = ExampleMatcher.matchingAll()
.withMatcher("username", exact())
.withIgnorePaths("id");
Example<Users> example = Example.of(users, matcher);
List<Users> find = usersRepository.findAll(example);
System.out.println("Find users: "+find.size());
I set the username variable on matchers. when I run the api and show the log. you can see below:
User payload: Users{id=0, firstName='Homer', lastName='Simpsons', username='bart.skate', email='homer.sleeper#gmail.com', password='#bcd1234'}
Find users: 0
User payload: Users{id=0, firstName='Homer', lastName='Simpsons', username='bart.skate', email='homer.simpsons#gmail.com', password='#bcd1234'}
Find users: 0
First users has been created. so I tried to create new user again same username. it wasn't find the username.
I hope someone help to explain for me. Thanks!

Simulate session using WithServer

I am trying to port tests from using FakeRequest to using WithServer.
In order to simulate a session with FakeRequest, it is possible to use WithSession("key", "value") as suggested in this post: Testing controller with fake session
However when using WithServer, the test now looks like:
"render the users page" in WithServer {
val users = await(WS.url("http://localhost:" + port + "/users").get)
users.status must equalTo(OK)
users.body must contain("Users")
}
Since there is no WithSession(..) method available, I tried instead WithHeaders(..) (does that even make sense?), to no avail.
Any ideas?
Thanks
So I found this question, which is relatively old:
Add values to Session during testing (FakeRequest, FakeApplication)
The first answer to that question seems to have been a pull request to add .WithSession(...) to FakeRequest, but it was not applicable to WS.url
The second answer seems to give me what I need:
Create cookie:
val sessionCookie = Session.encodeAsCookie(Session(Map("key" -> "value")))
Create and execute request:
val users = await(WS.url("http://localhost:" + port + "/users")
.withHeaders(play.api.http.HeaderNames.COOKIE -> Cookies.encodeCookieHeader(Seq(sessionCookie))).get())
users.status must equalTo(OK)
users.body must contain("Users")
Finally, the assertions will pass properly, instead of redirecting me to the login page
Note: I am using Play 2.4, so I use Cookies.encodeCookieHeader, because Cookies.encode is deprecated

Sending An HTTP Request using Intersystems Cache

I have the following Business Process defined within a Production on an Intersystems Cache Installation
/// Makes a call to Merlin based on the message sent to it from the pre-processor
Class sgh.Process.MerlinProcessor Extends Ens.BusinessProcess [ ClassType = persistent, ProcedureBlock ]
{
Property WorkingDirectory As %String;
Property WebServer As %String;
Property CacheServer As %String;
Property Port As %String;
Property Location As %String;
Parameter SETTINGS = "WorkingDirectory,WebServer,Location,Port,CacheServer";
Method OnRequest(pRequest As sgh.Message.MerlinTransmissionRequest, Output pResponse As Ens.Response) As %Status
{
Set tSC=$$$OK
Do ##class(sgh.Utils.Debug).LogDebugMsg("Packaging an HTTP request for Saved form "_pRequest.DateTimeSaved)
Set dateTimeSaved = pRequest.DateTimeSaved
Set patientId = pRequest.PatientId
Set latestDateTimeSaved = pRequest.LatestDateTimeSaved
Set formName = pRequest.FormName
Set formId = pRequest.FormId
Set episodeNumber = pRequest.EpisodeNumber
Set sentElectronically = pRequest.SentElectronically
Set styleSheet = pRequest.PrintName
Do ##class(sgh.Utils.Debug).LogDebugMsg("Creating HTTP Request Class")
set HTTPReq = ##class(%Net.HttpRequest).%New()
Set HTTPReq.Server = ..WebServer
Set HTTPReq.Port = ..Port
do HTTPReq.InsertParam("DateTimeSaved",dateTimeSaved)
do HTTPReq.InsertParam("HospitalNumber",patientId)
do HTTPReq.InsertParam("Episode",episodeNumber)
do HTTPReq.InsertParam("Stylesheet",styleSheet)
do HTTPReq.InsertParam("Server",..CacheServer)
Set Status = HTTPReq.Post(..Location,0) Quit:$$$ISERR(tSC)
Do ##class(sgh.Utils.Debug).LogDebugMsg("Sent the following request: "_Status)
Quit tSC
}
}
The thing is when I check the debug value (which is defined as a global) all I get is the number '1' - I have no idea therefore if the request has succeeded or even what is wrong (if it has not)
What do I need to do to find out
A) What is the actual web call being made?
B) What the response is?
There is a really slick way to get the answer the two questions you've asked, regardless of where you're using the code. Check the documentation out on the %Net.HttpRequest object here: http://docs.intersystems.com/ens20102/csp/docbook/DocBook.UI.Page.cls?KEY=GNET_http and the class reference here: http://docs.intersystems.com/ens20102/csp/documatic/%25CSP.Documatic.cls?APP=1&LIBRARY=ENSLIB&CLASSNAME=%25Net.HttpRequest
The class reference for the Post method has a parameter called test, that will do what you're looking for. Here's the excerpt:
method Post(location As %String = "", test As %Integer = 0, reset As %Boolean = 1) as %Status
Issue the Http 'post' request, this is used to send data to the web server such as the results of a form, or upload a file. If this completes correctly the response to this request will be in the HttpResponse. The location is the url to request, e.g. '/test.html'. This can contain parameters which are assumed to be already URL escaped, e.g. '/test.html?PARAM=%25VALUE' sets PARAM to %VALUE. If test is 1 then instead of connecting to a remote machine it will just output what it would have send to the web server to the current device, if test is 2 then it will output the response to the current device after the Post. This can be used to check that it will send what you are expecting. This calls Reset automatically after reading the response, except in test=1 mode or if reset=0.
I recommend moving this code to a test routine to view the output properly in terminal. It would look something like this:
// To view the REQUEST you are sending
Set sc = request.Post("/someserver/servlet/webmethod",1)
// To view the RESPONSE you are receiving
Set sc = request.Post("/someserver/servlet/webmethod",2)
// You could also do something like this to parse your RESPONSE stream
Write request.HttpResponse.Data.Read()
I believe the answer you want to A) is in the Server and Location properties of your %Net.HttpRequest object (e.g., HTTPReq.Server and HTTPReq.Location).
For B), the response information should be in the %Net.HttpResponse object stored in the HttpResponse property (e.g. HTTPReq.HttpResponse) after your call is completed.
I hope this helps!
-Derek
(edited for formatting)
From that code sample it looks like you're using Ensemble, not straight-up Cache.
In that case you should be doing this HTTP call in a Business Operation that uses the HTTP Outbound Adapter, not in your Business Process.
See this link for more info on HTTP Adapters:
http://docs.intersystems.com/ens20102/csp/docbook/DocBook.UI.Page.cls?KEY=EHTP
You should also look into how to use the Ensemble Message Browser. That should help with your logging needs.

Resources