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

Issue #385: Increase coverage for Lwt_mvar #448

Merged
merged 5 commits into from
Jul 18, 2017

Conversation

jsthomas
Copy link
Contributor

@jsthomas jsthomas commented Jul 14, 2017

This change adds some unit tests for mailbox variables (Lwt_mvar), bringing coverage up to 100%.

(fun () ->
let x = Lwt_mvar.create 0 in
let y = Lwt_mvar.put x 1 >>= (fun _ -> return 1) in
return (y != Lwt.return 1)
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this intentionally using != rather than <>?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No, that was a typo. Thanks for catching that.

let _ = Lwt_mvar.take y >>= (fun z -> Lwt_mvar.put x z); in
() in
let _ = Lwt.on_cancel r1 after_cancel in
Lwt.cancel r1;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Changing this test should allow you to get that remaining line fully covered. Indeed, I think in this form, this test doesn't add anything beyond the tests above.

Since t is still pending at this point, when you cancel r1, it cancels t, and the bind that creates r1 falls through bind's exception-forwarding case. So the function that puts 2 to y is simply never called, the put is never even started or tried, and this is only testing how bind responds to cancel.

To trigger that line, what this test should do is get rid of t, and define r1 as just that put y 2. It is put y 2 that has an on_cancel handler added to it in Lwt_mvar (and we currently never call it).

This will also be a pending promise, because y already has 1 at that moment. You'll want to cancel r1, take from y, check that it's 1, take again, and check that the taker is blocked the second time.

I don't think x is necessary.

The reader test below has a similar issue.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks, that worked and is a lot simpler than the original.

Copy link
Collaborator

@aantron aantron left a comment

Choose a reason for hiding this comment

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

Thanks, looks good :) I left some optional improvement/nit comments, but they don't affect the correctness of the code, so feel free not to apply them – and let me know if you want me to go ahead and merge.

(fun () ->
let x = Lwt_mvar.create 0 in
let y = Lwt_mvar.put x 1 >>= (fun _ -> return 1) in
return (y <> Lwt.return 1)
Copy link
Collaborator

Choose a reason for hiding this comment

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

This is optional (the test is correct regardless), but I believe you could do:

(* ... *)
let y = Lwt_mvar.put x 1 in
Lwt.return (Lwt.state y = Lwt.Sleep)

This makes the test slightly clearer, and it would be directly testing that y is pending. Actually, I would recommend always checking the state of promises with Lwt.state rather than comparing to another promise, as comparing with another promise will fail if the internal definition of promises ever changes to include, say, unique ids for tracing.

Sorry about the name Lwt.Sleep for "pending," that's a historical holdover :)

*)

open Test
open Lwt
Copy link
Collaborator

Choose a reason for hiding this comment

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

This is optional, but I recommend removing this (sorry if you saw it used in another test suite). Your code already nicely uses Lwt. in most places, removing it would, I think, just make the returns at the end of each test more explicit.

let x = Lwt_mvar.create 0 in
let _ = Lwt_mvar.take x in
let z = Lwt_mvar.put x 1 >>= (fun _ -> return 2) in
return (z = Lwt.return 2)
Copy link
Collaborator

Choose a reason for hiding this comment

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

The above optional suggestion about Lwt.state would save a bind here as well, and the need for 2 :) Another way is to compare with Lwt.return (), but... Lwt.state :)

let r1 = Lwt_mvar.put y 2 in
Lwt.cancel r1;
return ((Lwt_mvar.take y = Lwt.return 1)
&& (Lwt_mvar.take y >>= (fun _ -> Lwt.return 2) <> Lwt.return 2)))
Copy link
Collaborator

Choose a reason for hiding this comment

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

Lwt.state should make this final condition substantially clearer.

@aantron
Copy link
Collaborator

aantron commented Jul 17, 2017

(Also want to link this with #385, GitHub only creates a link if you mention the issue number in a comment, not in the PR title).

@jsthomas
Copy link
Contributor Author

Thanks for the feedback; Lwt.state really helped simplify those tests a lot. In light of the comment about open Lwt, I went back and corrected the tests I submitted earlier for Lwt_result as well.

@aantron aantron merged commit a8c1554 into ocsigen:master Jul 18, 2017
@aantron
Copy link
Collaborator

aantron commented Jul 18, 2017

Thanks, this is excellent!

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.

3 participants