-
Notifications
You must be signed in to change notification settings - Fork 36
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add JSON Payload coverage tests for REST endpoints #1890
Conversation
1472260
to
9e807be
Compare
df1bf77
to
50612a1
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have looked at this and have some comments what can be improved.
...vanced-reactive/src/main/java/io/quarkus/ts/http/advanced/reactive/FootballTeamResource.java
Outdated
Show resolved
Hide resolved
...vanced-reactive/src/main/java/io/quarkus/ts/http/advanced/reactive/FootballTeamResource.java
Outdated
Show resolved
Hide resolved
...vanced-reactive/src/main/java/io/quarkus/ts/http/advanced/reactive/FootballTeamResource.java
Outdated
Show resolved
Hide resolved
...vanced-reactive/src/main/java/io/quarkus/ts/http/advanced/reactive/FootballTeamResource.java
Show resolved
Hide resolved
...vanced-reactive/src/main/java/io/quarkus/ts/http/advanced/reactive/FootballTeamResource.java
Show resolved
Hide resolved
...http-advanced-reactive/src/test/java/io/quarkus/ts/http/advanced/reactive/JsonPayloadIT.java
Outdated
Show resolved
Hide resolved
...http-advanced-reactive/src/test/java/io/quarkus/ts/http/advanced/reactive/JsonPayloadIT.java
Outdated
Show resolved
Hide resolved
...http-advanced-reactive/src/test/java/io/quarkus/ts/http/advanced/reactive/JsonPayloadIT.java
Outdated
Show resolved
Hide resolved
...http-advanced-reactive/src/test/java/io/quarkus/ts/http/advanced/reactive/JsonPayloadIT.java
Outdated
Show resolved
Hide resolved
...http-advanced-reactive/src/test/java/io/quarkus/ts/http/advanced/reactive/JsonPayloadIT.java
Outdated
Show resolved
Hide resolved
I also looked on the TP and see that for large JSON you want to use POST and GET. Will be GET method added or should be TP updated? |
Also one more question. In TP you state you want test it with |
633647c
to
9d1c50e
Compare
Currently is added to the PersonResource and it's used, thanks. |
I've used the approach we talked about, so currently it's tested with both libraries. Thanks. |
9d432f9
to
dd80888
Compare
run tests |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I review it and it's look good. Just have few small suggestion.
...vanced-reactive/src/main/java/io/quarkus/ts/http/advanced/reactive/FootballTeamResource.java
Outdated
Show resolved
Hide resolved
...ttp-advanced-reactive/src/test/java/io/quarkus/ts/http/advanced/reactive/JsonBPayloadIT.java
Outdated
Show resolved
Hide resolved
...vanced-reactive/src/test/java/io/quarkus/ts/http/advanced/reactive/JsonJacksonPayloadIT.java
Outdated
Show resolved
Hide resolved
...nced-reactive/src/test/java/io/quarkus/ts/http/advanced/reactive/OpenShiftJsonPayloadIT.java
Outdated
Show resolved
Hide resolved
...http-advanced-reactive/src/test/java/io/quarkus/ts/http/advanced/reactive/JsonPayloadIT.java
Outdated
Show resolved
Hide resolved
...http-advanced-reactive/src/test/java/io/quarkus/ts/http/advanced/reactive/JsonPayloadIT.java
Outdated
Show resolved
Hide resolved
...http-advanced-reactive/src/test/java/io/quarkus/ts/http/advanced/reactive/JsonPayloadIT.java
Outdated
Show resolved
Hide resolved
Also jsut a note before merge I would like to see full CI run. ATM it's blocked because problem with releasing new framework version. |
45f0aff
to
5697363
Compare
...ttp-advanced-reactive/src/test/java/io/quarkus/ts/http/advanced/reactive/JsonBPayloadIT.java
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I add final comment.
Also can you rebase it to main as the latest framework bump was merged. So we can see tests.
...vanced-reactive/src/test/java/io/quarkus/ts/http/advanced/reactive/JsonJacksonPayloadIT.java
Outdated
Show resolved
Hide resolved
...nced-reactive/src/test/java/io/quarkus/ts/http/advanced/reactive/OpenShiftJsonPayloadIT.java
Show resolved
Hide resolved
9e3a389
to
15e5924
Compare
1cdb27e
to
9fd51dd
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the update. It's look good to me. Hopefully CI will be fine!
run tests |
1 similar comment
run tests |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mjurc can you look at the FootballTeamResource
and PersonResource
and tell me if this implements quarkus-qe/quarkus-test-plans#179 ?
Because if so, IMHO the test plan was wrong.
My opinion:
- this is using Jackson library (not an extension!) everywhere, newly added tests (maybe with consumes/produces annotations) would work without rest-jackson and rest-jsonb extensions anyway
- it is instantiating
ObjectMapper
instead of using managed one - it serializes and deserializes
everythingpart of the things manually - so when test plan says https://github.com/quarkus-qe/quarkus-test-plans/blob/main/QQE-379.md?plain=1#L40 that you expect 400 for invalid paylod, well, these resources set 400 response for invalid payload, so of course you are going to receive it? what exactly is it testing, that
Response
object works? - I expect users to actually use message writers/readers instead of doing this manually, if we want to test
com.fasterxml.jackson
then it should be clear this is what these tests are about, not something likeJsonBPayloadIT
etc.
|
||
@Test | ||
public void shouldPickJackson() { | ||
assertTrue(app.logs().forQuarkus().installedFeatures().contains(REST_JACKSON)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't shouldPickJackson
testing that rest-jackson
feature is present? If you compare logs of JsonJacksonPayloadIT
:
2024-07-24T08:07:28.0863296Z 08:07:28,083 INFO [app] 08:07:26,210 Installed features: [cdi, keycloak-authorization, micrometer, oidc, reactive-routes, rest, rest-client, rest-jackson, rest-jaxb, rest-jsonb, security, smallrye-context-propagation, smallrye-health, smallrye-openapi, vertx]
with JsonBPayloadIT
logs:
2024-07-24T08:07:19.4630743Z 08:07:19,461 INFO [app] 08:07:17,767 Installed features: [cdi, keycloak-authorization, micrometer, oidc, reactive-routes, rest, rest-client, rest-jaxb, rest-jsonb, security, smallrye-context-propagation, smallrye-health, smallrye-openapi, vertx]
but both of these tests have rest-jsonb
feature present as well.
Based on what can you determine that these 2 tests are using different serializers? Let alone that you are not actually using these extensions to serialize/deserialize payload, but that's a different story.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When reviewing this I didn't realized that @Dependency(artifactId = "quarkus-" + REST_JACKSON)
add it but the extension defined in pom stay there as well (probably that I was looking at GreetingResourceIT and didn't look at the pom there).
Based on what can you determine that these 2 tests are using different serializers?
Now I can say we can't say for sure. As I described above I was thinking that there is only that one extension.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it still can be sure that Quarkus REST Jackson serializers have a higher priority, but I simply don't know it and we don't assert it, therefore we need a way to assert it. Thank you
return Uni.createFrom() | ||
.item(() -> { | ||
Map<String, Object> responseMap = new HashMap<>(); | ||
responseMap.put("teams", footballTeamSet); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
here I can see object that is going to be serialized, I missed that one before and I am going to correct my comment above. @jedla97 @jcarranzan how do you know whether Jackson / JsonB serializers are going to be used?
if (personSet.isEmpty()) { | ||
return Uni.createFrom().item(Response.status(Response.Status.NOT_FOUND).build()); | ||
} else { | ||
return Uni.createFrom().item(Response.ok(personSet).build()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jedla97 @jcarranzan I also missed this one, apologizes. How do you know which serializer if going to be used? Jackson or JsonB?
@POST | ||
@Consumes(MediaType.APPLICATION_JSON) | ||
@Produces(MediaType.APPLICATION_JSON) | ||
public Uni<Response> processJson(String jsonData) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jcarranzan @jedla97 TP https://github.com/quarkus-qe/quarkus-test-plans/blob/main/QQE-379.md?plain=1#L31 says Deserialization: Ensure accurate conversion of JSON payloads, that it's performed using the configured JSON libraries (quarkus-rest-jackson, quarkus-rest-jsonb).
I don't see any deserialization performed by quarkus-rest-jackson
or quarkus-rest-jsonb
. AFAICT it is always performed manually. Am I wrong?
@jcarranzan @jedla97 I have corrected my original comment as I can see that serialization is partially tested, I apologize. Still, I am unhappy with this PR. Please have a look at my comments and answer. I suppose it can be determined from writers/readers priority which one is picked, but you actually don't test that. I think the way to test this is to actually fail serialization/deserialization and inspect stacktrace in the exception mapper. |
} | ||
|
||
@Test | ||
public void sendSpecialCharactersJSONPayload() throws Exception { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test is sending plain text (it is a String
) via client, received String
in REST endpoint. Special characters or not, you are testing your own instance of ObjectMapper
.
As far as extensions deserializers are concerned - none used
As far as extension serializers are concerned - teams
should be serialized, but that is not tested at all, what is tested is that text containes Teams added successfully
. So you are not testing whether special characters are handled properly by serializers, but you are testing that no exception is raised. If there was any encoding issue, you wouldn't know.
/** | ||
* | ||
* When a JSON extension is installed such as quarkus-rest-jackson or quarkus-rest-jsonb | ||
* Quarkus will use the application/json media type by default for most return values |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comment is true https://quarkus.io/guides/rest#declaring-endpoints-representation-content-types however I can't see relation to this resource as there is just one endpoint that consumes/produces something else than HTTP status (no entity), that is uploadFootballJson
and there, you explicitly delcare these annotations.
So, why to state what is default if you override it and don't test it?
This is definitely a correct assessment, as in we don't support standalone libs added to Quarkus. This is not an extension test. We need to add integration tests rather than unit tests for the library. |
Ok, thank you @michalvavrik for your question points, I'll do a refactor of these tests. |
Cool, let's give me 10 more minutes, I'll add few comments that you can consider. It is optional. |
|
||
private static final Logger LOG = Logger.getLogger(FootballTeamResource.class); | ||
|
||
private Set<FootballTeam> footballTeamSet = Collections.synchronizedSet(new LinkedHashSet<>()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
flow is:
String data
is deserialized withSet<FootballTeam> teamSet = objectMapper.readValue(data, new TypeReference<Set<FootballTeam>>() {});
- you have
Set<FootballTeam> teamSet
- then you do validation (that part is ok)
- then you copy it into a class member synchronized set
- then you use the synchronized set to return the response
- then you have separate call that deletes a football team set
Things that I don't understand:
- it's synchronized but there is no concurrency, you never call it more than once at time
- you copy
teamSet
intofootballTeamSet
that is kept outside of/upload-football-json
, but you never use it; instead you only use it to "delete it"; what is the point of copying it into thefootballTeamSet
- you need to manage
footballTeamSet
but it's not useful for you
} catch (JsonProcessingException e) { | ||
LOG.error(e.getMessage()); | ||
return Uni.createFrom().item( | ||
Response.status(400).entity("Invalid JSON - JsonProcessingException : " + e.getOriginalMessage()).build()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO your intention is to see that Quarkus responds with some response status. I say some, because I suspect that it is going to be 500 unless you customize that exception. For which reason, I think when test plan says HTTP Status Code: Expect 400 Bad request for invalid payloads. that is wrong expectation.
The point is, you know that you are able to set a response status based on business logic (like invalid argument), but this PR is verifying JSON payload handling and that is different then testing feature that allows you to set a response status.
this.favoriteFruit = favoriteFruit; | ||
} | ||
|
||
public String get_id() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if you verify a JSON payload, you are probably interested in commonly used features like ignored field etc. Anyway, that's a side note. Why is this called get_id
? I wonder into which field is it going to be turned by a serializer. Is it really going to be id
field? You might want to check.
.post("/football/upload-football-json") | ||
.then() | ||
.statusCode(CREATION_STATUS_CODE) | ||
.body(containsString("Teams added successfully")); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
None of tests in this test class is testing that response was serialized correctly. You don't test that JSON response is valid, just that response contains some string. Additionally,if tests are sending special chars, you might want to check that they are serialized/deserialized correctly.
Summary
This PR adds coverage tests to the http/http-advanced-reactive Quarkus module to ensure proper handling of JSON data in REST endpoints. Test scenarios include:
For more detailed info see the test plan for details: PR-179
Please select the relevant options.
run tests
phrase in comment)Checklist: