2022-07-13 13:40:34 +00:00
|
|
|
package state
|
|
|
|
|
|
|
|
import (
|
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
|
2022-07-19 13:37:46 +00:00
|
|
|
"github.com/hashicorp/go-memdb"
|
2022-07-13 13:40:34 +00:00
|
|
|
"github.com/hashicorp/nomad/ci"
|
|
|
|
"github.com/hashicorp/nomad/helper/pointer"
|
|
|
|
"github.com/hashicorp/nomad/nomad/mock"
|
|
|
|
"github.com/hashicorp/nomad/nomad/structs"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
)
|
|
|
|
|
|
|
|
func TestStateStore_ACLTokensByExpired(t *testing.T) {
|
|
|
|
ci.Parallel(t)
|
|
|
|
testState := testStateStore(t)
|
|
|
|
|
2022-07-19 13:37:46 +00:00
|
|
|
// This function provides an easy way to get all tokens out of the
|
|
|
|
// iterator.
|
|
|
|
fromIteratorFunc := func(iter memdb.ResultIterator) []*structs.ACLToken {
|
|
|
|
var tokens []*structs.ACLToken
|
|
|
|
for raw := iter.Next(); raw != nil; raw = iter.Next() {
|
|
|
|
tokens = append(tokens, raw.(*structs.ACLToken))
|
|
|
|
}
|
|
|
|
return tokens
|
|
|
|
}
|
|
|
|
|
2022-07-13 13:40:34 +00:00
|
|
|
// This time is the threshold for all expiry calls to be based on. All
|
|
|
|
// tokens with expiry can use this as their base and use Add().
|
|
|
|
expiryTimeThreshold := time.Date(2022, time.April, 27, 14, 50, 0, 0, time.UTC)
|
|
|
|
|
|
|
|
// Generate two tokens without an expiry time. These tokens should never
|
|
|
|
// show up in calls to ACLTokensByExpired.
|
|
|
|
neverExpireLocalToken := mock.ACLToken()
|
|
|
|
neverExpireGlobalToken := mock.ACLToken()
|
|
|
|
neverExpireLocalToken.Global = true
|
|
|
|
|
|
|
|
// Upsert the tokens into state and perform a global and local read of
|
|
|
|
// the state.
|
|
|
|
err := testState.UpsertACLTokens(structs.MsgTypeTestSetup, 10, []*structs.ACLToken{
|
|
|
|
neverExpireLocalToken, neverExpireGlobalToken})
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
2022-07-19 13:37:46 +00:00
|
|
|
iter, err := testState.ACLTokensByExpired(true)
|
2022-07-13 13:40:34 +00:00
|
|
|
require.NoError(t, err)
|
2022-07-19 13:37:46 +00:00
|
|
|
tokens := fromIteratorFunc(iter)
|
|
|
|
require.Len(t, tokens, 0)
|
2022-07-13 13:40:34 +00:00
|
|
|
|
2022-07-19 13:37:46 +00:00
|
|
|
iter, err = testState.ACLTokensByExpired(false)
|
2022-07-13 13:40:34 +00:00
|
|
|
require.NoError(t, err)
|
2022-07-19 13:37:46 +00:00
|
|
|
tokens = fromIteratorFunc(iter)
|
|
|
|
require.Len(t, tokens, 0)
|
2022-07-13 13:40:34 +00:00
|
|
|
|
|
|
|
// Generate, upsert, and test an expired local token. This token expired
|
|
|
|
// long ago and therefore before all others coming in the tests. It should
|
|
|
|
// therefore always be the first out.
|
|
|
|
expiredLocalToken := mock.ACLToken()
|
|
|
|
expiredLocalToken.ExpirationTime = pointer.Of(expiryTimeThreshold.Add(-48 * time.Hour))
|
|
|
|
|
|
|
|
err = testState.UpsertACLTokens(structs.MsgTypeTestSetup, 20, []*structs.ACLToken{expiredLocalToken})
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
2022-07-19 13:37:46 +00:00
|
|
|
iter, err = testState.ACLTokensByExpired(false)
|
2022-07-13 13:40:34 +00:00
|
|
|
require.NoError(t, err)
|
2022-07-19 13:37:46 +00:00
|
|
|
tokens = fromIteratorFunc(iter)
|
|
|
|
require.Len(t, tokens, 1)
|
|
|
|
require.Equal(t, expiredLocalToken.AccessorID, tokens[0].AccessorID)
|
2022-07-13 13:40:34 +00:00
|
|
|
|
|
|
|
// Generate, upsert, and test an expired global token. This token expired
|
|
|
|
// long ago and therefore before all others coming in the tests. It should
|
|
|
|
// therefore always be the first out.
|
|
|
|
expiredGlobalToken := mock.ACLToken()
|
|
|
|
expiredGlobalToken.Global = true
|
|
|
|
expiredGlobalToken.ExpirationTime = pointer.Of(expiryTimeThreshold.Add(-48 * time.Hour))
|
|
|
|
|
|
|
|
err = testState.UpsertACLTokens(structs.MsgTypeTestSetup, 30, []*structs.ACLToken{expiredGlobalToken})
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
2022-07-19 13:37:46 +00:00
|
|
|
iter, err = testState.ACLTokensByExpired(true)
|
2022-07-13 13:40:34 +00:00
|
|
|
require.NoError(t, err)
|
2022-07-19 13:37:46 +00:00
|
|
|
tokens = fromIteratorFunc(iter)
|
|
|
|
require.Len(t, tokens, 1)
|
|
|
|
require.Equal(t, expiredGlobalToken.AccessorID, tokens[0].AccessorID)
|
2022-07-13 13:40:34 +00:00
|
|
|
|
|
|
|
// This test function allows us to run the same test for local and global
|
|
|
|
// tokens.
|
2022-07-19 13:37:46 +00:00
|
|
|
testFn := func(oldToken *structs.ACLToken, global bool) {
|
2022-07-13 13:40:34 +00:00
|
|
|
|
2022-07-19 13:37:46 +00:00
|
|
|
// Track all the expected expired ACL tokens, including the long
|
2022-07-13 13:40:34 +00:00
|
|
|
// expired token.
|
2022-07-19 13:37:46 +00:00
|
|
|
var expiredTokens []*structs.ACLToken
|
|
|
|
expiredTokens = append(expiredTokens, oldToken)
|
2022-07-13 13:40:34 +00:00
|
|
|
|
2022-07-19 13:37:46 +00:00
|
|
|
// Generate and upsert a number of mixed expired, non-expired tokens.
|
|
|
|
mixedTokens := make([]*structs.ACLToken, 20)
|
2022-07-13 13:40:34 +00:00
|
|
|
for i := 0; i < 20; i++ {
|
|
|
|
mockedToken := mock.ACLToken()
|
|
|
|
mockedToken.Global = global
|
|
|
|
if i%2 == 0 {
|
2022-07-19 13:37:46 +00:00
|
|
|
expiredTokens = append(expiredTokens, mockedToken)
|
2022-07-13 13:40:34 +00:00
|
|
|
mockedToken.ExpirationTime = pointer.Of(expiryTimeThreshold.Add(-24 * time.Hour))
|
|
|
|
} else {
|
|
|
|
mockedToken.ExpirationTime = pointer.Of(expiryTimeThreshold.Add(24 * time.Hour))
|
|
|
|
}
|
2022-07-19 13:37:46 +00:00
|
|
|
mixedTokens[i] = mockedToken
|
2022-07-13 13:40:34 +00:00
|
|
|
}
|
|
|
|
|
2022-07-19 13:37:46 +00:00
|
|
|
err = testState.UpsertACLTokens(structs.MsgTypeTestSetup, 40, mixedTokens)
|
2022-07-13 13:40:34 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
2022-07-19 13:37:46 +00:00
|
|
|
// Check the full listing works as expected as the first 11 elements
|
|
|
|
// should all be our expired tokens. Ensure our oldest expired token is
|
|
|
|
// first in the list.
|
|
|
|
iter, err = testState.ACLTokensByExpired(global)
|
2022-07-13 13:40:34 +00:00
|
|
|
require.NoError(t, err)
|
2022-07-19 13:37:46 +00:00
|
|
|
tokens = fromIteratorFunc(iter)
|
|
|
|
require.ElementsMatch(t, expiredTokens, tokens[:11])
|
|
|
|
require.Equal(t, tokens[0], oldToken)
|
2022-07-13 13:40:34 +00:00
|
|
|
}
|
|
|
|
|
2022-07-19 13:37:46 +00:00
|
|
|
testFn(expiredLocalToken, false)
|
|
|
|
testFn(expiredGlobalToken, true)
|
2022-07-13 13:40:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func Test_expiresIndexName(t *testing.T) {
|
|
|
|
testCases := []struct {
|
|
|
|
globalInput bool
|
|
|
|
expectedOutput string
|
|
|
|
name string
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
globalInput: false,
|
|
|
|
expectedOutput: indexExpiresLocal,
|
|
|
|
name: "local",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
globalInput: true,
|
|
|
|
expectedOutput: indexExpiresGlobal,
|
|
|
|
name: "global",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, tc := range testCases {
|
|
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
|
|
actualOutput := expiresIndexName(tc.globalInput)
|
|
|
|
require.Equal(t, tc.expectedOutput, actualOutput)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|