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

Introduce VersionNumber newtype. #3075

Merged
merged 42 commits into from
Mar 7, 2023
Merged

Introduce VersionNumber newtype. #3075

merged 42 commits into from
Mar 7, 2023

Conversation

fisx
Copy link
Contributor

@fisx fisx commented Feb 10, 2023

See /libs/wire-api/test/unit/Test/Wire/API/Routes/Version.hs for explanation.

Checklist

  • Add a new entry in an appropriate subdirectory of changelog.d
  • Read and follow the PR guidelines

@zebot zebot added the ok-to-test Approved for running tests in CI, overrides not-ok-to-test if both labels exist label Feb 10, 2023
fisx added 2 commits February 11, 2023 16:15
See `/libs/wire-api/test/unit/Test/Wire/API/Routes/Version.hs` for explanation.
@fisx fisx force-pushed the play-with-version-types branch from 2017a86 to 31c9889 Compare February 11, 2023 15:18
@fisx fisx marked this pull request as ready for review February 11, 2023 20:56
.hlint.yaml Outdated
# . allVersionNumbers @=? cs . toByteString'
# <$> allVersionNumbers)
# ```
- ignore: { name: Functor law }
Copy link
Contributor

@elland elland Feb 13, 2023

Choose a reason for hiding this comment

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

Maybe we don't want to ignore Functor law everywhere, but rather where hlint gets tripped up, which seems to be when using the Bilge Assert combinators? 🤔

I wish hlint made it easy for us to disable some stuff per module/target.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'd prefer to turn off broken laws. It's not like either side of the law is wrong, it's merely an aesthetic preference. Anyone case to weigh in either way?

Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe it's just me who sometimes write "dumb" functor code and waits for hlint to clean it for me. 🤔

Copy link
Contributor

Choose a reason for hiding this comment

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

When I comes to dumb mistakes, I'm a good candidate, too 😉

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ok, i'm outweighed. :) will fix!

@fisx fisx requested a review from elland February 13, 2023 08:27
deriving (Arbitrary) via (GenericUniform Version)

versionString :: IsString a => Version -> a
versionString V0 = "v0"
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this could be implemented with fromEnum.

The benefit would be that you won't have to touch this function when a new version is introduced. The drawback is that Version constructors have to be sorted.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

i used to agree, but been there! :)

Copy link
Contributor

Choose a reason for hiding this comment

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

This simple version is fine with me, too 😸

Copy link
Contributor

Choose a reason for hiding this comment

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

But surely it could be implemented in terms of versionInt.

versionString V2 = "v2"
versionString V3 = "v3"

versionInt :: Integral i => Version -> i
Copy link
Contributor

Choose a reason for hiding this comment

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

Same here: Could be implemented with fromEnum.

parseVersion :: Request -> Maybe (Request, Integer)
data ParseVersionError = NoVersion | BadVersion Text

parseVersion :: Request -> Either ParseVersionError (Request, Version)
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm wondering if this function cannot be generalized regarding its Monad: Shouldn't a constraint MonadError m => ... be sufficient?

(This is nitpicking as far as nitpicking can get ... 😉 )

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yes, that would be sufficient, but i intentionally decided against it. i like both the abstract interpretation and the precise type that offers exactly what's needed, and not more.

always happy to nit-pick, though! :)

Copy link
Contributor

@supersven supersven left a comment

Choose a reason for hiding this comment

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

Being able to state if we're referring to an API version or only its number seems to be an improvement to me. 👍

Please feel free to get into my nitpicks or ignore them.

Copy link
Contributor

@elland elland left a comment

Choose a reason for hiding this comment

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

LGTM, just unsure about the hlint changes, although not a blocker.

Copy link
Contributor

@pcapriotti pcapriotti left a comment

Choose a reason for hiding this comment

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

I would organise this differently:

  • I wouldn't use the Enum instance of Version to define the schemas, as that is bound to cause confusion. Instead, we can have a list allVersions :: [Version] somewhere and use that. In fact, we should probably remove the Enum instance.
  • versionString and versionInt can then be defined in terms of the schema instance, as they were (implicitly) before.

deriving (Arbitrary) via (GenericUniform Version)

versionString :: IsString a => Version -> a
versionString V0 = "v0"
Copy link
Contributor

Choose a reason for hiding this comment

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

But surely it could be implemented in terms of versionInt.

@fisx
Copy link
Contributor Author

fisx commented Feb 15, 2023

I would organise this differently:

* I wouldn't use the `Enum` instance of `Version` to define the schemas, as that is bound to cause confusion. Instead, we can have a list `allVersions :: [Version]` somewhere and use that. In fact, we should probably remove the `Enum` instance.

* `versionString` and `versionInt` can then be defined in terms of the schema instance, as they were (implicitly) before.

I don't disagree, but I don't understand either: what's the confusion that is caused by the Enum instance?

I think versionString and versionInt are internal and only needed as a place where we can write down explicitly which Int belongs to which Version in order to support removing old versions.

@fisx
Copy link
Contributor Author

fisx commented Mar 6, 2023

federator>   Federator.Remote
federator>     can get response with valid certificate
federator>       when hostname=localhost and certificate-for=localhost:                                                       FAIL (0.03s)
federator>         Error message: Unexpected remote error: RemoteError (SrvTarget {srvTargetDomain = "localhost", srvTargetPort = 34749}) (FederatorClientHTTP2Exception (BadThingHappen ProtocolError "error:05800074:x509 certificate routines::key values mismatch"))
federator>         CallStack (from HasCallStack):
federator>           assertFailure, called at test/unit/Test/Federator/Remote.hs:76:15 in main:Test.Federator.Remote
federator>         Use -p '/when hostname=localhost and certificate-for=localhost/' to rerun this test only.

Happens reproducibly on CI, but I can't reproduce it locally.

$ make c test=1 package=federator TASTY_PATTERN='/when hostname=localhost and certificate-for=localhost/'

@fisx
Copy link
Contributor Author

fisx commented Mar 6, 2023

retried to reproduce locally (only the one test) 15878 times. got the sibling test to fail locally after 57 re-runs:

  Federator.Remote
    can get response with valid certificate
      when hostname=localhost and certificate-for=localhost:                                                       OK (0.10s)
      when hostname=localhost. and certificate-for=localhost:                                                      FAIL (0.03s)
        Error message: Unexpected remote error: RemoteError (SrvTarget {srvTargetDomain = "localhost.", srvTargetPort = 45027}) (FederatorClientHTTP2Exception (BadThingHappen ProtocolError "error:05800074:x509 certificate routines::key values mismatch"))
        
        CallStack (from HasCallStack):
          assertFailure, called at test/unit/Test/Federator/Remote.hs:76:15 in main:Test.Federator.Remote
        Use -p '$0=="Tests.Federator.Remote.can get response with valid certificate.when hostname=localhost. and certificate-for=localhost"' to rerun this test only.
      when hostname=localhost. and certificate-for=localhost.:                                                     OK (0.02s)

@fisx
Copy link
Contributor Author

fisx commented Mar 6, 2023

ok, we established the test is flaky and unrelated. i'll merge once i get lucky with the re-runs.

@fisx fisx force-pushed the play-with-version-types branch from 8e02002 to 759750f Compare March 7, 2023 15:58
fisx added 3 commits March 7, 2023 17:05
…types

 Conflicts:
        libs/wire-api/src/Wire/API/Routes/Version.hs
        tools/stern/src/Stern/Intra.hs
@fisx
Copy link
Contributor Author

fisx commented Mar 7, 2023

Failures:


  test-integration/Test/Spar/Scim/AuthSpec.hs:132:38: 

  1) WireIdPAPIV1.Spar.Scim.Auth, POST /auth-tokens, works with verification code

       uncaught exception: ErrorCall

       Error executing request: responseJsonUnsafeWithMsg: Value Error in $: parsing ASCII failed, expected String, but encountered Null

       CallStack (from HasCallStack):

         error, called at src/Bilge/Response.hs:145:7 in bilge-0.22.0-L77WXGV80XFJMqJLnvaA1h:Bilge.Response

         responseJsonUnsafeWithMsg, called at src/Bilge/Response.hs:134:22 in bilge-0.22.0-L77WXGV80XFJMqJLnvaA1h:Bilge.Response

         responseJsonUnsafe, called at test-integration/Test/Spar/Scim/AuthSpec.hs:163:10 in main:Test.Spar.Scim.AuthSpec

@fisx fisx merged commit 4456e29 into develop Mar 7, 2023
@fisx fisx deleted the play-with-version-types branch March 7, 2023 22:06
lepsa pushed a commit to lepsa/wire-server that referenced this pull request Nov 28, 2023
* Introduce VersionNumber newtype.

See `/libs/wire-api/test/unit/Test/Wire/API/Routes/Version.hs` for explanation.

Co-authored-by: Sven Tennie <sven.tennie@wire.com>
Co-authored-by: Paolo Capriotti <paolo@capriotti.io>
Co-authored-by: Stefan Matting <stefan@wire.com>
Co-authored-by: Leif Battermann <leif.battermann@wire.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
ok-to-test Approved for running tests in CI, overrides not-ok-to-test if both labels exist
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants