Skip to content
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

unit test and fix for null values in rendered JSON in UserProfile #1292

Merged
merged 2 commits into from
Dec 16, 2020

Conversation

jschaul
Copy link
Member

@jschaul jschaul commented Dec 16, 2020

While omitting a json field, or setting the field to null parses the
same for Haskell, that is not the case for other programming languages,
which can easily trip up over a change in behaviour.

The problem was accidentally introduced in #1281, resulting in null
values instead of omitting fields for unset values in UserProfile json, e.g.

{
   "deleted" : null,
   "picture" : [],
   "email" : null,
   "accent_id" : 1,
   "team" : null,
   "handle" : "test1",
   "expires_at" : null,
   "locale" : "en-US",
   "qualified_id" : {
      "id" : "d93f2555-e4b7-4051-8d84-2bcf59ea6066",
      "domain" : "staging.zinfra.io"
   },
   "service" : null,
   "name" : "test",
   "id" : "d93f2555-e4b7-4051-8d84-2bcf59ea6066",
   "assets" : [
      {
         "type" : "image",
         "size" : "preview",
         "key" : "3-1-43978d07-040c-4f49-be7e-06e2560701fd"
      },
      {
         "type" : "image",
         "key" : "3-1-f3039a69-a0b8-45a5-bc6b-3da087b680c7",
         "size" : "complete"
      }
   ]
}

This caused a problem as described in https://wearezeta.atlassian.net/browse/SQCORE-351

This PR reverts the offending change, and adds one manual unit test for
this particular data type. We may wish to add more tests for other data
types as well in future PRs to catch some backwards compatibility changes.

While omitting a json field, or setting the field to null parses the
same for Haskell, that is not the case for other programming languages,
which can easily trip up over a change in behaviour.

The problem was accidentally introduced in #1281, resulting in null
values instead of omitting fields for UserProfile json, e.g.

{
   "deleted" : null,
   "picture" : [],
   "email" : null,
   "accent_id" : 1,
   "team" : null,
   "handle" : "test1",
   "expires_at" : null,
   "locale" : "en-US",
   "qualified_id" : {
      "id" : "d93f2555-e4b7-4051-8d84-2bcf59ea6066",
      "domain" : "staging.zinfra.io"
   },
   "service" : null,
   "name" : "test",
   "id" : "d93f2555-e4b7-4051-8d84-2bcf59ea6066",
   "assets" : [
      {
         "type" : "image",
         "size" : "preview",
         "key" : "3-1-43978d07-040c-4f49-be7e-06e2560701fd"
      },
      {
         "type" : "image",
         "key" : "3-1-f3039a69-a0b8-45a5-bc6b-3da087b680c7",
         "size" : "complete"
      }
   ]
}

This PR reverts the offending change, and adds one manual unit test for
this particular data type. We may wish to add more tests for other data
types as well in future PRs to catch some backwards compatibility changes.
@jschaul jschaul requested a review from akshaymankar December 16, 2020 19:35
# "assets" .= profileAssets u
# "accent_id" .= profileAccentId u
# "deleted" .= (if profileDeleted u then Just True else Nothing)
# "service" .= profileService u
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pair

Copy link
Contributor

@fisx fisx left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks good, you can ignore my nit-pick(s).

let userProfile = UserProfile (Qualified uid domain) (Name "name") (Pict []) [] colour False Nothing Nothing Nothing Nothing Nothing Nothing
let profileJSONAsText = Text.pack $ show $ Aeson.encode userProfile
let msg = Text.unpack $ "toJSON encoding must not convert Nothing to null, but instead omit those json fields for backwards compatibility. UserProfileJSON:" <> profileJSONAsText
assertBool msg (not $ "null" `Text.isInfixOf` profileJSONAsText)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would have just pasted the offending json into a QQ-block, fixed it, and make a round-trip test from json to haskell and back out of it. But this works, too.

Copy link
Member Author

@jschaul jschaul Dec 16, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We already have JSON roundtrip tests. They don't catch this problem, so they are somewhat useless (for this purpose of checking there are no null values), as they don't make a difference between fields being omitted and fields being set to null, since Aeson accepts either and interprets them the same.
I'm not sure how you can write a roundtrip test to fail when there are null values. Do you have an example?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I read your PR :) i meant:

sample = [json|{"field": 3}|] -- omitting the null fields
test = encode (decode sample) `shouldBe` sample

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But I'm not saying you should change the test you have, which works fine. Just thinking out loud.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the more i think about it, the better i like my approach. it's very easy to read, and it potentially catches other mistakes we haven't even thought about here. on the other hand, it gives you more room for errors when crafting the samples. donno. but i want to have 2 or 3 samples for every type now, everywhere. :)

libs/wire-api/test/unit/Test/Wire/API/User.hs Outdated Show resolved Hide resolved
@jschaul jschaul merged commit 49b4402 into develop Dec 16, 2020
@jschaul jschaul deleted the fix-null-json branch December 16, 2020 23:23
@fisx fisx mentioned this pull request Dec 21, 2020
pcapriotti added a commit that referenced this pull request Apr 29, 2021
In most cases we want optional fields to not appear at all in the serialised
object (see for example #1292). Using the `opt` combinator achieves this
behaviour.
pcapriotti added a commit that referenced this pull request Apr 30, 2021
In most cases we want optional fields to not appear at all in the serialised
object (see for example #1292). Using the `opt` combinator achieves this
behaviour.
pcapriotti added a commit that referenced this pull request May 3, 2021
In most cases we want optional fields to not appear at all in the serialised
object (see for example #1292). Using the `opt` combinator achieves this
behaviour.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants