-
Notifications
You must be signed in to change notification settings - Fork 149
Add UnitTest for PaginateHistory #968
Conversation
Codecov Report
@@ Coverage Diff @@
## master #968 +/- ##
==========================================
+ Coverage 47.34% 49.55% +2.21%
==========================================
Files 28 28
Lines 2034 2030 -4
==========================================
+ Hits 963 1006 +43
+ Misses 894 843 -51
- Partials 177 181 +4
Continue to review full report at Codecov.
|
|
More unittests for Key Transparency. PTAL |
core/client/client.go
Outdated
|
|
||
| // Verifier is used to verify specific outputs from Key Transparency. | ||
| type Verifier interface { | ||
| // Index computes the index from a VRF proof. |
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.
What is VRF?
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.
VRF means Verifiable Random Function
KT has a VRF implementation in core/crypto/vrf/
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.
Ack, thank you.
pav-kv
left a comment
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.
Some nits.
core/client/client.go
Outdated
| type Verifier interface { | ||
| // Index computes the index from a VRF proof. | ||
| Index(vrfProof []byte, domainID, appID, userID string) ([]byte, error) | ||
| // VerifyGetEntryResponse verifies everything about a GetEntryResponse: |
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.
s/:/./
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.
done
core/client/client.go
Outdated
|
|
||
| // Verifier is used to verify specific outputs from Key Transparency. | ||
| type Verifier interface { | ||
| // Index computes the index from a VRF proof. |
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.
Ack, thank you.
core/client/client.go
Outdated
| epochsWant := end - start + 1 | ||
| for epochsReceived < epochsWant { | ||
| count := min(int32((end-start)+1), pageSize) | ||
| epochsWant := int(end - start + 1) |
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 am slightly nervous about this shrinking cast. How do you feel about doing the opposite - comparing int64s?
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.
Good idea. It produces a slightly nasty set of casts below, but it's probably safer.
core/testutil/mockserver.go
Outdated
| Addr string | ||
| } | ||
|
|
||
| // NewMockKT returns a new mock Key Transparency server listening on a random port . |
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.
nit: remove space before period
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.
done
core/testutil/mockserver.go
Outdated
|
|
||
| // NewMockKT returns a new mock Key Transparency server listening on a random port . | ||
| // Returns the started server, the listener it's using for connection and a | ||
| // close function that must be defer-called on the scope the server is meant to |
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'd drop the "defer-" bit because it doesn't look like a must (could simply call the function directly?), likewise the "scope" detail:
... that must be called to stop the server.
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.
yep
core/testutil/mockserver.go
Outdated
| } | ||
|
|
||
| // NewMockKT returns a new mock Key Transparency server listening on a random port . | ||
| // Returns the started server, the listener it's using for connection and a |
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.
The pure Listener object is not there, only the server wrapper.
Returns the started server, a client connected to it, and a close ...
core/client/verify.go
Outdated
| mapVerifier *tclient.MapVerifier | ||
| logVerifier *tclient.LogVerifier | ||
| // Verify is a client helper library for verifying request and responses. | ||
| type Verify struct { |
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.
Is there a way to name this with a noun? Some ideas:
- Call this
Verifierand the interface -IVerifier. Not sure whether Go naming conventions allows this. Verification(Client),VerifierImpl,VerifiedClient...
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 struggled with the naming conventions too.
is RealVerifier appropriate? The interface exists so we can have a FakeVerifier
| } | ||
| }) | ||
| } | ||
|
|
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.
nit: drop empty line?
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.
done
core/client/client_test.go
Outdated
| Start: r.wantStart, | ||
| PageSize: r.wantSize, | ||
| })). | ||
| Return(&pb.ListEntryHistoryResponse{ |
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.
nit: maybe merge this line with the previous one?
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.
That does look better.
core/client/client.go
Outdated
| count := min(int32((end-start)+1), pageSize) | ||
| for int64(len(allProfiles)) < epochsWant { | ||
| log.Printf("pageSize: %v", c.pageSize) | ||
| count := min(int32(epochsWant-int64(len(allProfiles))), c.pageSize) |
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.
Hm, this bit is just as problematic as the previous version due to shrinking cast. Probably making a min function for int64 is too much hassle. Instead, how about rewinding this back, and simply checking end-start+1 for an overflow before casting it down to int32 in line 175?
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.
Making min accept int64 is actually the better solution. It defers the downcast till the end when we expect the value to be small.
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.
Oh, I agree. Wasn't aware that the min function was used only here.
|
This now LGTM. One general question. I noticed you use both |
| vrf vrf.PublicKey | ||
| mapVerifier *tclient.MapVerifier | ||
| logVerifier *tclient.LogVerifier | ||
| // RealVerifier is a client helper library for verifying request and responses. |
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.
Maybe you could make a note that this implements Verifier? That would explain the seemingly unclear Real bit.
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.
Done
|
Kat, would you mind taking a look? |
core/client/client.go
Outdated
|
|
||
| // Verifier is used to verify specific outputs from Key Transparency. | ||
| type Verifier interface { | ||
| // Index computes the index from a VRF proof. |
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.
Index computes the index of what? Add to the comment to make it really clear :)
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.
Index computes the index of an appID, userID pair from a VRF proof, obtained from the server.
| // VerifyGetEntryResponse verifies everything about a GetEntryResponse. | ||
| VerifyGetEntryResponse(ctx context.Context, domainID, appID, userID string, trusted types.LogRootV1, in *pb.GetEntryResponse) (*types.MapRootV1, *types.LogRootV1, error) | ||
| // VerifyEpoch verifies that epoch is correctly signed and included in the append only log. | ||
| // VerifyEpoch also verifies that epoch.LogRoot is consistent with the last trusted SignedLogRoot. |
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.
Did the *pb.Epoch parameter used to be called 'epoch' or something? Maybe capitalize in these comments to make it clear you're talking about the type rather than the variable name - 'VerifyEpoch verifies that the Epoch is correctly...', 'VerifyEpoch also verifies that Epoch.LogRoot is ....'
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'll just rename in to epoch :-)
…y into test/listhistory * 'test/listhistory' of github.com:gdbelvin/keytransparency: Use DomainID rather than mapID during authorization (google#970) Strengthen CreateDomain (google#969)
core/client/client_test.go
Outdated
| }, nil) | ||
| } | ||
|
|
||
| if _, _, err = c.PaginateHistory(ctx, appID, userID, tc.start, tc.end); err != tc.wantErr { |
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 method of testing PaginateHistory seems odd, given you could test based on state - i.e. just test PaginateHistory based on its inputs and outputs, rather than checking that it's calling the correct server endpoints with the right arguments.... In fact, by doing the way you currently are explicitly doesn't test some of the logic within PaginateHistory outside of what it sends/receives to/from the server.
In addition to this, (and as discussed separately from this PR,) use of gomock (and mocks in general) tends to be discouraged from a readability standpoint, preferring real objects or fakes.
If you were to test PaginateHistory based on inputs and outputs (and compare them to expected outputs) you could just fake the one rpc it calls (ListEntryHistory is it?), which would remove the need for mocking, making the test code much simpler. (Although incidentally it looks like the PaginateHistory code doesn't call that directly, but instead calls client.VerifiedListHistory, which then calls ListEntryHistory - I couldn't find a test for VerifiedListHistory, so using this method of testing could also be appropriate for that function too.)
This method of testing would be specifically testing the PaginateHistory code, and assuming the underlying functions that it calls work as expected.
…y into test/listhistory * 'test/listhistory' of github.com:gdbelvin/keytransparency: Missing masterPassword input in post.go (google#971)
|
Yay! the mocks have been removed. Thanks @taknira for helping keep up the code excellence. |
taknira
left a comment
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.
Looks good, and easier to follow now :)
core/client/client_test.go
Outdated
| } | ||
| s, stop, err := testutil.NewFakeKT(srv) | ||
| if err != nil { | ||
| t.Fatalf("NewMockKT(): %v", err) |
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.
It's not a mock anymore :P
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 got, want := values, tc.wantValues; !reflect.DeepEqual(got, want) { | ||
| t.Errorf("PaginateHistory().values: \n%#v, want \n%#v, diff: \n%v", | ||
| got, want, pretty.Compare(got, want)) |
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.
(Optional) Is there any chance at all that pretty.Compare and reflect.DeepEqual would return different results? Might be worth using pretty.Compare for the initial comparison too, and checking the diff is empty of something? Completely up to you though, as the two funcs will likely be in agreement the majority of the time. Just a musing :)
d0cb53c to
cdee1f7
Compare
If the client always asks for the maximum amount from the server, 1. The total number of requests will be smaller. 2. The logic for determining the number of items to return is simpler.
cdee1f7 to
ff25cbf
Compare
* master: Move authentication to grpc interceptor (google#973) Add UnitTest for PaginateHistory (google#968) Remove unused `UserProfile` message (google#972) Update default paths (google#910)
This PR adds a long overdue unit test and unittesting framework for client operations.
Included:
pageSize. It's now a client variable.