unit test: fix oidc periodicfunc flaky test (#15320)

* unit test: fix oidc periodicfunc flaky test

* update cycle 1 for two test cases
This commit is contained in:
John-Michael Faircloth 2022-05-09 13:43:23 -05:00 committed by GitHub
parent 51cf5acf4d
commit 72643c70e8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -1019,93 +1019,87 @@ func TestOIDC_SignIDToken_NilSigningKey(t *testing.T) {
expectStrings(t, []string{err.Error()}, expectedStrings) expectStrings(t, []string{err.Error()}, expectedStrings)
} }
func testNamedKey(name string) *namedKey {
return &namedKey{
name: name,
Algorithm: "RS256",
VerificationTTL: 1 * time.Second,
RotationPeriod: 2 * time.Second,
KeyRing: nil,
SigningKey: nil,
NextSigningKey: nil,
NextRotation: time.Now(),
}
}
// TestOIDC_PeriodicFunc tests timing logic for running key // TestOIDC_PeriodicFunc tests timing logic for running key
// rotations and expiration actions. // rotations and expiration actions.
func TestOIDC_PeriodicFunc(t *testing.T) { func TestOIDC_PeriodicFunc(t *testing.T) {
// Prepare a storage to run through periodicFunc type testCase struct {
c, _, _ := TestCoreUnsealed(t) cycle int
ctx := namespace.RootContext(nil) numKeys int
numPublicKeys int
cyclePeriod := 2 * time.Second }
testSets := []struct { testSets := []struct {
namedKey *namedKey namedKey *namedKey
expectedKeyCount int expectedKeyCount int
setSigningKey bool setSigningKey bool
setNextSigningKey bool setNextSigningKey bool
cycles int testCases []testCase
}{ }{
{ {
namedKey: &namedKey{ namedKey: testNamedKey("test-key"),
name: "test-key",
Algorithm: "RS256",
VerificationTTL: 1 * cyclePeriod,
RotationPeriod: 1 * cyclePeriod,
KeyRing: nil,
SigningKey: nil,
NextSigningKey: nil,
NextRotation: time.Now(),
},
expectedKeyCount: 3,
setSigningKey: true, setSigningKey: true,
setNextSigningKey: true, setNextSigningKey: true,
cycles: 4, testCases: []testCase{
{1, 2, 2},
{2, 2, 4},
{3, 2, 4},
{4, 2, 4},
},
}, },
{ {
// don't set SigningKey to ensure its non-existence can be handled // don't set SigningKey to ensure its non-existence can be handled
namedKey: &namedKey{ namedKey: testNamedKey("test-key-nil-signing-key"),
name: "test-key-nil-signing-key",
Algorithm: "RS256",
VerificationTTL: 1 * cyclePeriod,
RotationPeriod: 1 * cyclePeriod,
KeyRing: nil,
SigningKey: nil,
NextSigningKey: nil,
NextRotation: time.Now(),
},
expectedKeyCount: 2,
setSigningKey: false, setSigningKey: false,
setNextSigningKey: true, setNextSigningKey: true,
cycles: 2, testCases: []testCase{
{1, 1, 2},
{2, 2, 4},
},
}, },
{ {
// don't set NextSigningKey to ensure its non-existence can be handled // don't set NextSigningKey to ensure its non-existence can be handled
namedKey: &namedKey{ namedKey: testNamedKey("test-key-nil-next-signing-key"),
name: "test-key-nil-next-signing-key",
Algorithm: "RS256",
VerificationTTL: 1 * cyclePeriod,
RotationPeriod: 1 * cyclePeriod,
KeyRing: nil,
SigningKey: nil,
NextSigningKey: nil,
NextRotation: time.Now(),
},
expectedKeyCount: 2,
setSigningKey: true, setSigningKey: true,
setNextSigningKey: false, setNextSigningKey: false,
cycles: 2, testCases: []testCase{
{1, 1, 2},
{2, 2, 4},
},
}, },
{ {
// don't set keys to ensure non-existence can be handled // don't set keys to ensure non-existence can be handled
namedKey: &namedKey{ namedKey: testNamedKey("test-key-nil-signing-and-next-signing-key"),
name: "test-key-nil-signing-and-next-signing-key",
Algorithm: "RS256",
VerificationTTL: 1 * cyclePeriod,
RotationPeriod: 1 * cyclePeriod,
KeyRing: nil,
SigningKey: nil,
NextSigningKey: nil,
NextRotation: time.Now(),
},
expectedKeyCount: 2,
setSigningKey: false, setSigningKey: false,
setNextSigningKey: false, setNextSigningKey: false,
cycles: 2, testCases: []testCase{
{1, 0, 2},
{2, 2, 4},
},
}, },
} }
for _, testSet := range testSets { for _, testSet := range testSets {
testSet := testSet
t.Run(testSet.namedKey.name, func(t *testing.T) {
t.Parallel()
// Prepare a storage to run through periodicFunc
c, _, _ := TestCoreUnsealed(t)
ctx := namespace.RootContext(nil)
storage := c.router.MatchingStorageByAPIPath(ctx, "identity/oidc") storage := c.router.MatchingStorageByAPIPath(ctx, "identity/oidc")
if testSet.setSigningKey { if testSet.setSigningKey {
if err := testSet.namedKey.generateAndSetKey(ctx, hclog.NewNullLogger(), storage); err != nil { if err := testSet.namedKey.generateAndSetKey(ctx, hclog.NewNullLogger(), storage); err != nil {
t.Fatalf("failed to set signing key") t.Fatalf("failed to set signing key")
@ -1116,21 +1110,24 @@ func TestOIDC_PeriodicFunc(t *testing.T) {
t.Fatalf("failed to set next signing key") t.Fatalf("failed to set next signing key")
} }
} }
testSet.namedKey.NextRotation = time.Now().Add(testSet.namedKey.RotationPeriod)
// Store namedKey // Store namedKey
entry, _ := logical.StorageEntryJSON(namedKeyConfigPath+testSet.namedKey.name, testSet.namedKey) entry, _ := logical.StorageEntryJSON(namedKeyConfigPath+testSet.namedKey.name, testSet.namedKey)
if err := storage.Put(ctx, entry); err != nil { if err := storage.Put(ctx, entry); err != nil {
t.Fatalf("writing to in mem storage failed") t.Fatalf("writing to in mem storage failed")
} }
currentCycle := 0 currentCycle := 1
lastCycle := testSet.cycles - 1 numCases := len(testSet.testCases)
namedKeySamples := make([]*logical.StorageEntry, testSet.cycles) lastCycle := testSet.testCases[numCases-1].cycle
publicKeysSamples := make([][]string, testSet.cycles) namedKeySamples := make([]*logical.StorageEntry, numCases)
publicKeysSamples := make([][]string, numCases)
i := 0 i := 0
for currentCycle <= lastCycle { for currentCycle <= lastCycle {
c.identityStore.oidcPeriodicFunc(ctx) c.identityStore.oidcPeriodicFunc(ctx)
if currentCycle == i { if currentCycle == testSet.testCases[i].cycle {
namedKeyEntry, _ := storage.Get(ctx, namedKeyConfigPath+testSet.namedKey.name) namedKeyEntry, _ := storage.Get(ctx, namedKeyConfigPath+testSet.namedKey.name)
publicKeysEntry, _ := storage.List(ctx, publicKeysConfigPath) publicKeysEntry, _ := storage.List(ctx, publicKeysConfigPath)
namedKeySamples[i] = namedKeyEntry namedKeySamples[i] = namedKeyEntry
@ -1150,26 +1147,27 @@ func TestOIDC_PeriodicFunc(t *testing.T) {
} }
// measure collected samples // measure collected samples
for i := 0; i < testSet.cycles; i++ { for i := range testSet.testCases {
cycle := i + 1 expectedKeyCount := testSet.testCases[i].numKeys
namedKeySamples[i].DecodeJSON(&testSet.namedKey) namedKeySamples[i].DecodeJSON(&testSet.namedKey)
actualKeyRingLen := len(testSet.namedKey.KeyRing) actualKeyRingLen := len(testSet.namedKey.KeyRing)
if actualKeyRingLen < testSet.expectedKeyCount { if actualKeyRingLen < expectedKeyCount {
t.Errorf( t.Errorf(
"For key: %s at cycle: %d expected namedKey's KeyRing to be at least of length %d but was: %d", "For key: %s at cycle: %d expected namedKey's KeyRing to be at least of length %d but was: %d",
testSet.namedKey.name, testSet.namedKey.name,
cycle, testSet.testCases[i].cycle,
testSet.expectedKeyCount, expectedKeyCount,
actualKeyRingLen, actualKeyRingLen,
) )
} }
expectedPublicKeyCount := testSet.testCases[i].numPublicKeys
actualPubKeysLen := len(publicKeysSamples[i]) actualPubKeysLen := len(publicKeysSamples[i])
if actualPubKeysLen < testSet.expectedKeyCount { if actualPubKeysLen < expectedPublicKeyCount {
t.Errorf( t.Errorf(
"For key: %s at cycle: %d expected public keys to be at least of length %d but was: %d", "For key: %s at cycle: %d expected public keys to be at least of length %d but was: %d",
testSet.namedKey.name, testSet.namedKey.name,
cycle, testSet.testCases[i].cycle,
testSet.expectedKeyCount, expectedPublicKeyCount,
actualPubKeysLen, actualPubKeysLen,
) )
} }
@ -1178,6 +1176,7 @@ func TestOIDC_PeriodicFunc(t *testing.T) {
if err := storage.Delete(ctx, namedKeyConfigPath+testSet.namedKey.name); err != nil { if err := storage.Delete(ctx, namedKeyConfigPath+testSet.namedKey.name); err != nil {
t.Fatalf("deleting from in mem storage failed") t.Fatalf("deleting from in mem storage failed")
} }
})
} }
} }