Add unit tests around the new ocspServers field#3699
Add unit tests around the new ocspServers field#3699jetstack-bot merged 4 commits intocert-manager:masterfrom
Conversation
93eff53 to
3e37bd1
Compare
| ))), | ||
| givenNamespace: "default", | ||
| assertSignedCert: func(t *testing.T, got *x509.Certificate) { | ||
| assert.Equal(t, time.Now().UTC().Add(30*time.Minute), got.NotAfter) |
There was a problem hiding this comment.
I get a mismatch here, am I misunderstanding the role of cr.Spec.Duration? Why does the returned signed certificate have a 0 time on its NotAfter field?
% go test ./pkg/controller/certificaterequests/ca/ -run TestCA_Sign
I0223 20:32:06.072826 16843 ca.go:128] cert-manager "msg"="certificate issued"
I0223 20:32:06.075193 16843 ca.go:128] cert-manager "msg"="certificate issued"
I0223 20:32:06.077904 16843 ca.go:128] cert-manager "msg"="certificate issued"
I0223 20:32:06.080078 16843 ca.go:128] cert-manager "msg"="certificate issued"
--- FAIL: TestCA_Sign (0.38s)
--- FAIL: TestCA_Sign/when_the_CertificateRequest_has_the_duration_field_set,_it_should_appear_as_notAfter_on_the_signed_ca (0.00s)
ca_test.go:440:
Error Trace: ca_test.go:440
ca_test.go:545
Error: Not equal:
expected: time.Time{wall:0x459e058, ext:63749707326, loc:(*time.Location)(nil)}
actual : time.Time{wall:0x0, ext:63749707326, loc:(*time.Location)(nil)}
Diff:
--- Expected
+++ Actual
@@ -1,3 +1,3 @@
(time.Time) {
- wall: (uint64) 72999000,
+ wall: (uint64) 0,
ext: (int64) 63749707326,
Test: TestCA_Sign/when_the_CertificateRequest_has_the_duration_field_set,_it_should_appear_as_notAfter_on_the_signed_ca
FAIL
FAIL github.com/jetstack/cert-manager/pkg/controller/certificaterequests/ca 0.411s
FAILThere was a problem hiding this comment.
I think this is happening because time.Now() gives you a value to a higher precision than what ends up on the cert.
If I modify time.Now().UTC().Add(30*time.Minute) -> time.Now().UTC().Add(30*time.Minute).Round(time.Second *2) this test passes.
Not sure why the assertion shows it as 0.
There was a problem hiding this comment.
Oohh thank you! I added String() in order to see a human-readable time, we can see the difference:
expected: 2021-02-24 14:26:38.587263 +0000 UTC
actual: 2021-02-24 14:26:38 +0000 UTC
I'll use your tip to fix the test case!
There was a problem hiding this comment.
I used Truncate instead of Round, here is how I went:
// The notAfter field uses a precision of 1 second; the current time is
// truncated before adding the certificate request's duration value.
assert.Equal(t, time.Now().UTC().Truncate(1*time.Second).Add(30*time.Minute).String(), got.NotAfter.String())There was a problem hiding this comment.
Ah, yes truncating is obviously a better approach than rounding 😄
String() makes it more readable, but maybe asserting the equality of the actual structs (rather than strings) is more important?
There was a problem hiding this comment.
OK, I'll do that then, and will show the .String() values in the error message instead
3e37bd1 to
77619e1
Compare
Signed-off-by: Maël Valais <mael@vls.dev>
77619e1 to
c9dcae2
Compare
Signed-off-by: Maël Valais <mael@vls.dev> Co-authored-by: Irbe Krumina <irbekrm@gmail.com>
Also removed the unused "givenNamespace" Signed-off-by: Maël Valais <mael@vls.dev> Co-authored-by: Irbe Krumina <irbekrm@gmail.com>
irbekrm
left a comment
There was a problem hiding this comment.
Looks good to me, I added a few comments. Happy to lgtm, if the 'return' is to stay 😄
| gotIssueResp, gotErr := c.Sign(context.Background(), test.givenCR, test.givenCAIssuer) | ||
| if test.wantErr != "" { | ||
| assert.EqualError(t, gotErr, test.wantErr) | ||
| return |
There was a problem hiding this comment.
Suggestion: is there maybe a way how we can not return here and still run the other checks even when we expect an error (i.e by testing that gotCert is nil etc)?
I feel like it is a little confusing that we return in a test- but happy to be convinced otherwise.
There was a problem hiding this comment.
I also realize that returning here potentially "skips" below assertions that might have to be checked even if an error is returned...
Would it make sense to do the following instead:
if test.wantErr != "" {
assert.EqualError(t, gotErr, test.wantErr)
} else {
require.NoError(t, gotErr)
require.NotNil(t, gotIssueResp)
gotCert, err := pki.DecodeX509CertificateBytes(gotIssueResp.Certificate)
require.NoError(t, err)
test.assertSignedCert(t, gotCert)
}There was a problem hiding this comment.
I think this is clearer! I am always torn between whether I actually want to check error strings and whether I want to verify for example that gotIssuerResp is nil in case of an error.
I personally have a slight preference for not having else blocks and not comparing error strings only types if possible:
// given that `wantsErr` is boolean and `gotErr` is error
if test.wantsErr != (test.gotErr != nil) {
// unexpected presence error or the lack of it, fail
}
require.Equal(test.IssuerResp, gotIssuerResp) // check both that it's correct when there's no error and nil when there is error
if gotIssuerResp != nil {
gotCert, err := pki.DecodeX509CertificateBytes(gotIssueResp.Certificate)
require.NoError(t, err)
test.assertSignedCert(t, gotCert)
} But I don't think this ^ is better, just different, so your fix looks good to me.
Signed-off-by: Maël Valais <mael@vls.dev> Co-authored-by: Irbe Krumina <irbekrm@gmail.com>
|
/lgtm |
|
I think it still wants a release note. |
Not sure but I think that Tide will also expect a "Github PR approval"; by default it does not require one, and as soon as one person gives a review then Tide waits until that person gives a Github approval: Try giving a Github PR approval just to see? |
|
/approve |
|
please approve 😆 |
|
Perhaps I need to assign myself before approving /assign @irbekrm |
|
/approve |
|
Ohh, I am not in the OWNERS file https://github.com/jetstack/cert-manager/blob/master/OWNERS |
|
soo.. 🥁 ... /approve |
|
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: irbekrm, maelvls The full list of commands accepted by this bot can be found here. The pull request process is described here DetailsNeeds approval from an approver in each of these files:
Approvers can indicate their approval by writing |
| expectNotAfter := time.Now().UTC().Truncate(1 * time.Second).Add(30 * time.Minute) | ||
| assert.Equalf(t, expectNotAfter, got.NotAfter, "time mismatch, expect='%s', got='%s'", expectNotAfter.String(), got.NotAfter.String()) |
There was a problem hiding this comment.
Apparently this requires some additional tolerance as it was reported off by 1:
#3475 (comment)
There was a problem hiding this comment.
Yes, I might want to check that got.NotAfter is within the range
[expectNotAfter - 2 time.Second, expectNotAfter + 2 * time.Second]
or something like that 😅
There was a problem hiding this comment.
In the long term, if the API is malleable, maybe you change:
https://github.com/jetstack/cert-manager/blob/923eec2d1bce1e2bc865fb7c5557c38ad0bd045f/pkg/util/pki/csr.go#L320-L321 so that you can provide a time provider instead of being forced to live in real time.
n.b. even if you don't do that, someone should fix it so that time.Now() is only called once. It's introducing drift between the two function calls which is arguably wrong.

In order to release cert-manager v1.2, we decided to leave some unit testing behind as detailed in #3636.
This PR adds a couple of unit tests:
ocspServersset, it should appear on the signed certificatecrlDistributionPointsset, it should appear on the signed certificate→ this one is failing, not sure why, I might have misunderstood the role of the cr.Spec.Duration?
Note to the reviewer:
TestSign.TestSigndoes not allow for setting assertions on the signed certificate.Signas opposed to the full controller flow, which means I did not have to rely on the fake clientsets (i.e., the testbuilder package)Closes #3636