2022-01-14 18:49:22 +00:00
// Copyright 2020-2022 the Pinniped contributors. All Rights Reserved.
2020-11-17 16:42:11 +00:00
// SPDX-License-Identifier: Apache-2.0
package crud
import (
"context"
"errors"
2020-12-04 22:31:06 +00:00
"fmt"
2020-11-17 16:42:11 +00:00
"testing"
2020-12-10 20:15:40 +00:00
"time"
2020-11-17 16:42:11 +00:00
"github.com/ory/fosite/compose"
"github.com/stretchr/testify/require"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/api/validation"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/kubernetes/fake"
coretesting "k8s.io/client-go/testing"
2021-12-10 22:22:36 +00:00
clocktesting "k8s.io/utils/clock/testing"
2020-11-17 16:42:11 +00:00
)
func TestStorage ( t * testing . T ) {
ctx := context . Background ( )
secretsGVR := schema . GroupVersionResource {
Group : "" ,
Version : "v1" ,
Resource : "secrets" ,
}
type testJSON struct {
Data string
}
type mocker interface {
AddReactor ( verb , resource string , reaction coretesting . ReactionFunc )
PrependReactor ( verb , resource string , reaction coretesting . ReactionFunc )
Tracker ( ) coretesting . ObjectTracker
}
hmac := compose . NewOAuth2HMACStrategy ( & compose . Config { } , [ ] byte ( "super-secret-32-byte-for-testing" ) , nil )
// test data generation via:
// code, signature, err := hmac.GenerateAuthorizeCode(ctx, nil)
validateSecretName := validation . NameIsDNSSubdomain // matches k/k
2020-12-10 22:47:58 +00:00
fakeNow := time . Date ( 2030 , time . January , 1 , 0 , 0 , 0 , 0 , time . UTC )
lifetime := time . Minute * 10
fakeNowPlusLifetimeAsString := metav1 . Time { Time : fakeNow . Add ( lifetime ) } . Format ( time . RFC3339 )
2020-12-10 20:15:40 +00:00
2020-11-17 16:42:11 +00:00
const (
namespace = "test-ns"
authorizationCode1 = "81qE408EKL-e99gcXo3UnXBz9W05yGm92_hBmvXeadM.R5h38Bmw7yOaWNy0ypB3feh9toM-3T2zlwMXQyeE9B0"
authorizationCode2 = "p7aIiOLy-btBBlCro5RWm1QABANKCiC0JmDPhUtfOY4.XXJsYsMWhnSMJi9TXJcPO6SDVO2R_QXImwroxxnQPA8"
authorizationCode3 = "skKp1RjGgIwZhT3vaB_k1F3cIj2yp7U8a7UD0xAaemU.5aUhdNmfWLW3yKX8Zfz5ztS5IiiWBgu36Gja-o2xl0I"
)
tests := [ ] struct {
name string
resource string
mocks func ( * testing . T , mocker )
2021-12-10 22:22:36 +00:00
run func ( * testing . T , Storage , * clocktesting . FakeClock ) error
2020-11-17 16:42:11 +00:00
wantActions [ ] coretesting . Action
wantSecrets [ ] corev1 . Secret
wantErr string
} {
{
name : "get non-existent" ,
2020-12-01 19:01:23 +00:00
resource : "authcode" ,
2020-11-17 16:42:11 +00:00
mocks : nil ,
2021-12-10 22:22:36 +00:00
run : func ( t * testing . T , storage Storage , fakeClock * clocktesting . FakeClock ) error {
2020-11-17 16:42:11 +00:00
_ , err := storage . Get ( ctx , "not-exists" , nil )
return err
} ,
wantActions : [ ] coretesting . Action {
2020-12-01 19:01:23 +00:00
coretesting . NewGetAction ( secretsGVR , namespace , "pinniped-storage-authcode-t2fx46yyvs3a" ) ,
2020-11-17 16:42:11 +00:00
} ,
wantSecrets : nil ,
2020-12-01 19:01:23 +00:00
wantErr : ` failed to get authcode for signature not-exists: secrets "pinniped-storage-authcode-t2fx46yyvs3a" not found ` ,
2020-11-17 16:42:11 +00:00
} ,
{
name : "delete non-existent" ,
resource : "tokens" ,
mocks : nil ,
2021-12-10 22:22:36 +00:00
run : func ( t * testing . T , storage Storage , fakeClock * clocktesting . FakeClock ) error {
2020-11-17 16:42:11 +00:00
return storage . Delete ( ctx , "not-a-token" )
} ,
wantActions : [ ] coretesting . Action {
coretesting . NewDeleteAction ( secretsGVR , namespace , "pinniped-storage-tokens-t2fx427lnci6s" ) ,
} ,
wantSecrets : nil ,
wantErr : ` failed to delete tokens for signature not-a-token: secrets "pinniped-storage-tokens-t2fx427lnci6s" not found ` ,
} ,
2020-12-10 22:47:58 +00:00
{
name : "delete non-existent by label" ,
resource : "tokens" ,
mocks : nil ,
2021-12-10 22:22:36 +00:00
run : func ( t * testing . T , storage Storage , fakeClock * clocktesting . FakeClock ) error {
2020-12-10 22:47:58 +00:00
return storage . DeleteByLabel ( ctx , "additionalLabel" , "matching-value" )
} ,
wantActions : [ ] coretesting . Action {
coretesting . NewListAction ( secretsGVR , schema . GroupVersionKind { Group : "" , Version : "v1" , Kind : "Secret" } , namespace , metav1 . ListOptions {
LabelSelector : "storage.pinniped.dev/type=tokens,additionalLabel=matching-value" ,
} ) ,
} ,
wantSecrets : nil ,
wantErr : ` failed to delete secrets for resource "tokens" matching label "additionalLabel=matching-value": none found ` ,
} ,
2020-11-17 16:42:11 +00:00
{
name : "create and get" ,
resource : "access-tokens" ,
mocks : nil ,
2021-12-10 22:22:36 +00:00
run : func ( t * testing . T , storage Storage , fakeClock * clocktesting . FakeClock ) error {
2020-11-17 16:42:11 +00:00
signature := hmac . AuthorizeCodeSignature ( authorizationCode1 )
require . NotEmpty ( t , signature )
require . NotEmpty ( t , validateSecretName ( signature , false ) ) // signature is not valid secret name as-is
data := & testJSON { Data : "create-and-get" }
2020-12-04 22:31:06 +00:00
rv1 , err := storage . Create ( ctx , signature , data , nil )
2020-11-17 16:42:11 +00:00
require . Empty ( t , rv1 ) // fake client does not set this
require . NoError ( t , err )
out := & testJSON { }
rv2 , err := storage . Get ( ctx , signature , out )
require . Empty ( t , rv2 ) // fake client does not set this
require . NoError ( t , err )
require . Equal ( t , data , out )
return nil
} ,
wantActions : [ ] coretesting . Action {
coretesting . NewCreateAction ( secretsGVR , namespace , & corev1 . Secret {
ObjectMeta : metav1 . ObjectMeta {
Name : "pinniped-storage-access-tokens-i6mhp4azwdxshgsy3s2mvedxpxuh3nudh3ot3m4xamlugj4e6qoq" ,
ResourceVersion : "" ,
Labels : map [ string ] string {
2020-12-04 22:39:11 +00:00
"storage.pinniped.dev/type" : "access-tokens" ,
2020-11-17 16:42:11 +00:00
} ,
2020-12-10 20:15:40 +00:00
Annotations : map [ string ] string {
2020-12-10 22:47:58 +00:00
"storage.pinniped.dev/garbage-collect-after" : fakeNowPlusLifetimeAsString ,
2020-12-10 20:15:40 +00:00
} ,
2020-11-17 16:42:11 +00:00
} ,
Data : map [ string ] [ ] byte {
"pinniped-storage-data" : [ ] byte ( ` { "Data":"create-and-get"} ` ) ,
"pinniped-storage-version" : [ ] byte ( "1" ) ,
} ,
Type : "storage.pinniped.dev/access-tokens" ,
} ) ,
coretesting . NewGetAction ( secretsGVR , namespace , "pinniped-storage-access-tokens-i6mhp4azwdxshgsy3s2mvedxpxuh3nudh3ot3m4xamlugj4e6qoq" ) ,
} ,
wantSecrets : [ ] corev1 . Secret {
{
ObjectMeta : metav1 . ObjectMeta {
Name : "pinniped-storage-access-tokens-i6mhp4azwdxshgsy3s2mvedxpxuh3nudh3ot3m4xamlugj4e6qoq" ,
Namespace : namespace ,
ResourceVersion : "" ,
Labels : map [ string ] string {
2020-12-04 22:39:11 +00:00
"storage.pinniped.dev/type" : "access-tokens" ,
2020-11-17 16:42:11 +00:00
} ,
2020-12-10 20:15:40 +00:00
Annotations : map [ string ] string {
2020-12-10 22:47:58 +00:00
"storage.pinniped.dev/garbage-collect-after" : fakeNowPlusLifetimeAsString ,
2020-12-10 20:15:40 +00:00
} ,
2020-11-17 16:42:11 +00:00
} ,
Data : map [ string ] [ ] byte {
"pinniped-storage-data" : [ ] byte ( ` { "Data":"create-and-get"} ` ) ,
"pinniped-storage-version" : [ ] byte ( "1" ) ,
} ,
Type : "storage.pinniped.dev/access-tokens" ,
} ,
} ,
wantErr : "" ,
} ,
2020-12-10 22:47:58 +00:00
{
name : "create multiple, each gets the correct lifetime timestamp" ,
resource : "access-tokens" ,
mocks : nil ,
2021-12-10 22:22:36 +00:00
run : func ( t * testing . T , storage Storage , fakeClock * clocktesting . FakeClock ) error {
2020-12-10 22:47:58 +00:00
data := & testJSON { Data : "create1" }
rv1 , err := storage . Create ( ctx , "sig1" , data , nil )
require . Empty ( t , rv1 ) // fake client does not set this
require . NoError ( t , err )
fakeClock . Step ( 42 * time . Minute ) // simulate that a known amount of time has passed
data = & testJSON { Data : "create2" }
rv1 , err = storage . Create ( ctx , "sig2" , data , nil )
require . Empty ( t , rv1 ) // fake client does not set this
require . NoError ( t , err )
return nil
} ,
wantActions : [ ] coretesting . Action {
coretesting . NewCreateAction ( secretsGVR , namespace , & corev1 . Secret {
ObjectMeta : metav1 . ObjectMeta {
Name : "pinniped-storage-access-tokens-wiudk" ,
ResourceVersion : "" ,
Labels : map [ string ] string {
"storage.pinniped.dev/type" : "access-tokens" ,
} ,
Annotations : map [ string ] string {
"storage.pinniped.dev/garbage-collect-after" : fakeNowPlusLifetimeAsString ,
} ,
} ,
Data : map [ string ] [ ] byte {
"pinniped-storage-data" : [ ] byte ( ` { "Data":"create1"} ` ) ,
"pinniped-storage-version" : [ ] byte ( "1" ) ,
} ,
Type : "storage.pinniped.dev/access-tokens" ,
} ) ,
coretesting . NewCreateAction ( secretsGVR , namespace , & corev1 . Secret {
ObjectMeta : metav1 . ObjectMeta {
Name : "pinniped-storage-access-tokens-wiudm" ,
ResourceVersion : "" ,
Labels : map [ string ] string {
"storage.pinniped.dev/type" : "access-tokens" ,
} ,
Annotations : map [ string ] string {
"storage.pinniped.dev/garbage-collect-after" : metav1 . Time { Time : fakeNow . Add ( 42 * time . Minute ) . Add ( lifetime ) } . Format ( time . RFC3339 ) ,
} ,
} ,
Data : map [ string ] [ ] byte {
"pinniped-storage-data" : [ ] byte ( ` { "Data":"create2"} ` ) ,
"pinniped-storage-version" : [ ] byte ( "1" ) ,
} ,
Type : "storage.pinniped.dev/access-tokens" ,
} ) ,
} ,
wantSecrets : [ ] corev1 . Secret {
{
ObjectMeta : metav1 . ObjectMeta {
Name : "pinniped-storage-access-tokens-wiudk" ,
Namespace : namespace ,
ResourceVersion : "" ,
Labels : map [ string ] string {
"storage.pinniped.dev/type" : "access-tokens" ,
} ,
Annotations : map [ string ] string {
"storage.pinniped.dev/garbage-collect-after" : fakeNowPlusLifetimeAsString ,
} ,
} ,
Data : map [ string ] [ ] byte {
"pinniped-storage-data" : [ ] byte ( ` { "Data":"create1"} ` ) ,
"pinniped-storage-version" : [ ] byte ( "1" ) ,
} ,
Type : "storage.pinniped.dev/access-tokens" ,
} ,
{
ObjectMeta : metav1 . ObjectMeta {
Name : "pinniped-storage-access-tokens-wiudm" ,
Namespace : namespace ,
ResourceVersion : "" ,
Labels : map [ string ] string {
"storage.pinniped.dev/type" : "access-tokens" ,
} ,
Annotations : map [ string ] string {
"storage.pinniped.dev/garbage-collect-after" : metav1 . Time { Time : fakeNow . Add ( 42 * time . Minute ) . Add ( lifetime ) } . Format ( time . RFC3339 ) ,
} ,
} ,
Data : map [ string ] [ ] byte {
"pinniped-storage-data" : [ ] byte ( ` { "Data":"create2"} ` ) ,
"pinniped-storage-version" : [ ] byte ( "1" ) ,
} ,
Type : "storage.pinniped.dev/access-tokens" ,
} ,
} ,
wantErr : "" ,
} ,
2020-12-04 22:31:06 +00:00
{
name : "create and get with additional labels" ,
resource : "access-tokens" ,
mocks : nil ,
2021-12-10 22:22:36 +00:00
run : func ( t * testing . T , storage Storage , fakeClock * clocktesting . FakeClock ) error {
2020-12-04 22:31:06 +00:00
signature := hmac . AuthorizeCodeSignature ( authorizationCode1 )
require . NotEmpty ( t , signature )
require . NotEmpty ( t , validateSecretName ( signature , false ) ) // signature is not valid secret name as-is
data := & testJSON { Data : "create-and-get" }
rv1 , err := storage . Create ( ctx , signature , data , map [ string ] string { "label1" : "value1" , "label2" : "value2" } )
require . Empty ( t , rv1 ) // fake client does not set this
require . NoError ( t , err )
out := & testJSON { }
rv2 , err := storage . Get ( ctx , signature , out )
require . Empty ( t , rv2 ) // fake client does not set this
require . NoError ( t , err )
require . Equal ( t , data , out )
return nil
} ,
wantActions : [ ] coretesting . Action {
coretesting . NewCreateAction ( secretsGVR , namespace , & corev1 . Secret {
ObjectMeta : metav1 . ObjectMeta {
Name : "pinniped-storage-access-tokens-i6mhp4azwdxshgsy3s2mvedxpxuh3nudh3ot3m4xamlugj4e6qoq" ,
ResourceVersion : "" ,
Labels : map [ string ] string {
2020-12-04 22:39:11 +00:00
"storage.pinniped.dev/type" : "access-tokens" ,
"label1" : "value1" ,
"label2" : "value2" ,
2020-12-04 22:31:06 +00:00
} ,
2020-12-10 20:15:40 +00:00
Annotations : map [ string ] string {
2020-12-10 22:47:58 +00:00
"storage.pinniped.dev/garbage-collect-after" : fakeNowPlusLifetimeAsString ,
2020-12-10 20:15:40 +00:00
} ,
2020-12-04 22:31:06 +00:00
} ,
Data : map [ string ] [ ] byte {
"pinniped-storage-data" : [ ] byte ( ` { "Data":"create-and-get"} ` ) ,
"pinniped-storage-version" : [ ] byte ( "1" ) ,
} ,
Type : "storage.pinniped.dev/access-tokens" ,
} ) ,
coretesting . NewGetAction ( secretsGVR , namespace , "pinniped-storage-access-tokens-i6mhp4azwdxshgsy3s2mvedxpxuh3nudh3ot3m4xamlugj4e6qoq" ) ,
} ,
wantSecrets : [ ] corev1 . Secret {
{
ObjectMeta : metav1 . ObjectMeta {
Name : "pinniped-storage-access-tokens-i6mhp4azwdxshgsy3s2mvedxpxuh3nudh3ot3m4xamlugj4e6qoq" ,
Namespace : namespace ,
ResourceVersion : "" ,
Labels : map [ string ] string {
2020-12-04 22:39:11 +00:00
"storage.pinniped.dev/type" : "access-tokens" ,
"label1" : "value1" ,
"label2" : "value2" ,
2020-12-04 22:31:06 +00:00
} ,
2020-12-10 20:15:40 +00:00
Annotations : map [ string ] string {
2020-12-10 22:47:58 +00:00
"storage.pinniped.dev/garbage-collect-after" : fakeNowPlusLifetimeAsString ,
2020-12-10 20:15:40 +00:00
} ,
2020-12-04 22:31:06 +00:00
} ,
Data : map [ string ] [ ] byte {
"pinniped-storage-data" : [ ] byte ( ` { "Data":"create-and-get"} ` ) ,
"pinniped-storage-version" : [ ] byte ( "1" ) ,
} ,
Type : "storage.pinniped.dev/access-tokens" ,
} ,
} ,
wantErr : "" ,
} ,
2020-11-17 16:42:11 +00:00
{
name : "get existing" ,
resource : "pandas-are-best" ,
mocks : func ( t * testing . T , mock mocker ) {
err := mock . Tracker ( ) . Add ( & corev1 . Secret {
ObjectMeta : metav1 . ObjectMeta {
Name : "pinniped-storage-pandas-are-best-lvzgyywdc2dhjdbgf5jvzfyphosigvhnsh6qlse3blumogoqhqhq" ,
Namespace : namespace ,
ResourceVersion : "" ,
Labels : map [ string ] string {
2020-12-04 22:39:11 +00:00
"storage.pinniped.dev/type" : "pandas-are-best" ,
2020-11-17 16:42:11 +00:00
} ,
2020-12-10 20:15:40 +00:00
Annotations : map [ string ] string {
2020-12-10 22:47:58 +00:00
"storage.pinniped.dev/garbage-collect-after" : fakeNowPlusLifetimeAsString ,
2020-12-10 20:15:40 +00:00
} ,
2020-11-17 16:42:11 +00:00
} ,
Data : map [ string ] [ ] byte {
"pinniped-storage-data" : [ ] byte ( ` { "Data":"snorlax"} ` ) ,
"pinniped-storage-version" : [ ] byte ( "1" ) ,
} ,
Type : "storage.pinniped.dev/pandas-are-best" ,
} )
require . NoError ( t , err )
} ,
2021-12-10 22:22:36 +00:00
run : func ( t * testing . T , storage Storage , fakeClock * clocktesting . FakeClock ) error {
2020-11-17 16:42:11 +00:00
signature := hmac . AuthorizeCodeSignature ( authorizationCode2 )
require . NotEmpty ( t , signature )
require . NotEmpty ( t , validateSecretName ( signature , false ) ) // signature is not valid secret name as-is
data := & testJSON { Data : "snorlax" }
out := & testJSON { }
rv1 , err := storage . Get ( ctx , signature , out )
require . Empty ( t , rv1 ) // fake client does not set this
require . NoError ( t , err )
require . Equal ( t , data , out )
return nil
} ,
wantActions : [ ] coretesting . Action {
coretesting . NewGetAction ( secretsGVR , namespace , "pinniped-storage-pandas-are-best-lvzgyywdc2dhjdbgf5jvzfyphosigvhnsh6qlse3blumogoqhqhq" ) ,
} ,
wantSecrets : [ ] corev1 . Secret {
{
ObjectMeta : metav1 . ObjectMeta {
Name : "pinniped-storage-pandas-are-best-lvzgyywdc2dhjdbgf5jvzfyphosigvhnsh6qlse3blumogoqhqhq" ,
Namespace : namespace ,
ResourceVersion : "" ,
Labels : map [ string ] string {
2020-12-04 22:39:11 +00:00
"storage.pinniped.dev/type" : "pandas-are-best" ,
2020-11-17 16:42:11 +00:00
} ,
2020-12-10 20:15:40 +00:00
Annotations : map [ string ] string {
2020-12-10 22:47:58 +00:00
"storage.pinniped.dev/garbage-collect-after" : fakeNowPlusLifetimeAsString ,
2020-12-10 20:15:40 +00:00
} ,
2020-11-17 16:42:11 +00:00
} ,
Data : map [ string ] [ ] byte {
"pinniped-storage-data" : [ ] byte ( ` { "Data":"snorlax"} ` ) ,
"pinniped-storage-version" : [ ] byte ( "1" ) ,
} ,
Type : "storage.pinniped.dev/pandas-are-best" ,
} ,
} ,
wantErr : "" ,
} ,
{
name : "update existing" ,
resource : "stores" ,
mocks : func ( t * testing . T , mock mocker ) {
err := mock . Tracker ( ) . Add ( & corev1 . Secret {
ObjectMeta : metav1 . ObjectMeta {
Name : "pinniped-storage-stores-4wssc5gzt5mlln6iux6gl7hzz3klsirisydaxn7indnpvdnrs5ba" ,
Namespace : namespace ,
ResourceVersion : "35" ,
Labels : map [ string ] string {
2020-12-04 22:39:11 +00:00
"storage.pinniped.dev/type" : "stores" ,
2020-11-17 16:42:11 +00:00
} ,
2020-12-10 20:15:40 +00:00
Annotations : map [ string ] string {
2020-12-10 22:47:58 +00:00
"storage.pinniped.dev/garbage-collect-after" : fakeNowPlusLifetimeAsString ,
2020-12-10 20:15:40 +00:00
} ,
2020-11-17 16:42:11 +00:00
} ,
Data : map [ string ] [ ] byte {
"pinniped-storage-data" : [ ] byte ( ` { "Data":"pants"} ` ) ,
"pinniped-storage-version" : [ ] byte ( "1" ) ,
} ,
Type : "storage.pinniped.dev/stores" ,
} )
require . NoError ( t , err )
mock . PrependReactor ( "update" , "secrets" , func ( action coretesting . Action ) ( handled bool , ret runtime . Object , err error ) {
secret := action . ( coretesting . UpdateAction ) . GetObject ( ) . ( * corev1 . Secret )
secret . ResourceVersion = "45"
return false , nil , nil // we mutated the secret in place but we do not "handle" it
} )
} ,
2021-12-10 22:22:36 +00:00
run : func ( t * testing . T , storage Storage , fakeClock * clocktesting . FakeClock ) error {
2020-11-17 16:42:11 +00:00
signature := hmac . AuthorizeCodeSignature ( authorizationCode3 )
require . NotEmpty ( t , signature )
require . NotEmpty ( t , validateSecretName ( signature , false ) ) // signature is not valid secret name as-is
data := & testJSON { Data : "pants" }
out := & testJSON { }
rv1 , err := storage . Get ( ctx , signature , out )
require . Equal ( t , "35" , rv1 ) // set in mock above
require . NoError ( t , err )
require . Equal ( t , data , out )
newData := & testJSON { Data : "shirts" }
rv2 , err := storage . Update ( ctx , signature , rv1 , newData )
require . Equal ( t , "45" , rv2 ) // mock sets to a higher value on update
require . NoError ( t , err )
newOut := & testJSON { }
rv3 , err := storage . Get ( ctx , signature , newOut )
require . Equal ( t , "45" , rv3 ) // we should see new rv now
require . NoError ( t , err )
require . Equal ( t , newData , newOut )
return nil
} ,
wantActions : [ ] coretesting . Action {
coretesting . NewGetAction ( secretsGVR , namespace , "pinniped-storage-stores-4wssc5gzt5mlln6iux6gl7hzz3klsirisydaxn7indnpvdnrs5ba" ) ,
coretesting . NewUpdateAction ( secretsGVR , namespace , & corev1 . Secret {
ObjectMeta : metav1 . ObjectMeta {
Name : "pinniped-storage-stores-4wssc5gzt5mlln6iux6gl7hzz3klsirisydaxn7indnpvdnrs5ba" ,
ResourceVersion : "35" , // update at initial RV
Labels : map [ string ] string {
2020-12-04 22:39:11 +00:00
"storage.pinniped.dev/type" : "stores" ,
2020-11-17 16:42:11 +00:00
} ,
2020-12-10 20:15:40 +00:00
Annotations : map [ string ] string {
2020-12-10 22:47:58 +00:00
"storage.pinniped.dev/garbage-collect-after" : fakeNowPlusLifetimeAsString ,
2020-12-10 20:15:40 +00:00
} ,
2020-11-17 16:42:11 +00:00
} ,
Data : map [ string ] [ ] byte {
"pinniped-storage-data" : [ ] byte ( ` { "Data":"shirts"} ` ) ,
"pinniped-storage-version" : [ ] byte ( "1" ) ,
} ,
Type : "storage.pinniped.dev/stores" ,
} ) ,
coretesting . NewGetAction ( secretsGVR , namespace , "pinniped-storage-stores-4wssc5gzt5mlln6iux6gl7hzz3klsirisydaxn7indnpvdnrs5ba" ) ,
} ,
wantSecrets : [ ] corev1 . Secret {
{
ObjectMeta : metav1 . ObjectMeta {
Name : "pinniped-storage-stores-4wssc5gzt5mlln6iux6gl7hzz3klsirisydaxn7indnpvdnrs5ba" ,
Namespace : namespace ,
ResourceVersion : "45" , // final list at new RV
Labels : map [ string ] string {
2020-12-04 22:39:11 +00:00
"storage.pinniped.dev/type" : "stores" ,
2020-11-17 16:42:11 +00:00
} ,
2020-12-10 20:15:40 +00:00
Annotations : map [ string ] string {
2020-12-10 22:47:58 +00:00
"storage.pinniped.dev/garbage-collect-after" : fakeNowPlusLifetimeAsString ,
2020-12-10 20:15:40 +00:00
} ,
2020-11-17 16:42:11 +00:00
} ,
Data : map [ string ] [ ] byte {
"pinniped-storage-data" : [ ] byte ( ` { "Data":"shirts"} ` ) ,
"pinniped-storage-version" : [ ] byte ( "1" ) ,
} ,
Type : "storage.pinniped.dev/stores" ,
} ,
} ,
wantErr : "" ,
} ,
{
name : "delete existing" ,
resource : "seals" ,
mocks : func ( t * testing . T , mock mocker ) {
err := mock . Tracker ( ) . Add ( & corev1 . Secret {
ObjectMeta : metav1 . ObjectMeta {
Name : "pinniped-storage-seals-lvzgyywdc2dhjdbgf5jvzfyphosigvhnsh6qlse3blumogoqhqhq" ,
Namespace : namespace ,
ResourceVersion : "" ,
Labels : map [ string ] string {
2020-12-04 22:39:11 +00:00
"storage.pinniped.dev/type" : "seals" ,
2020-11-17 16:42:11 +00:00
} ,
2020-12-10 20:15:40 +00:00
Annotations : map [ string ] string {
2020-12-10 22:47:58 +00:00
"storage.pinniped.dev/garbage-collect-after" : fakeNowPlusLifetimeAsString ,
2020-12-10 20:15:40 +00:00
} ,
2020-11-17 16:42:11 +00:00
} ,
Data : map [ string ] [ ] byte {
"pinniped-storage-data" : [ ] byte ( ` { "Data":"sad-seal"} ` ) ,
"pinniped-storage-version" : [ ] byte ( "1" ) ,
} ,
Type : "storage.pinniped.dev/seals" ,
} )
require . NoError ( t , err )
} ,
2021-12-10 22:22:36 +00:00
run : func ( t * testing . T , storage Storage , fakeClock * clocktesting . FakeClock ) error {
2020-11-17 16:42:11 +00:00
signature := hmac . AuthorizeCodeSignature ( authorizationCode2 )
require . NotEmpty ( t , signature )
require . NotEmpty ( t , validateSecretName ( signature , false ) ) // signature is not valid secret name as-is
return storage . Delete ( ctx , signature )
} ,
wantActions : [ ] coretesting . Action {
coretesting . NewDeleteAction ( secretsGVR , namespace , "pinniped-storage-seals-lvzgyywdc2dhjdbgf5jvzfyphosigvhnsh6qlse3blumogoqhqhq" ) ,
} ,
wantSecrets : nil ,
wantErr : "" ,
} ,
2020-12-04 22:31:06 +00:00
{
name : "delete existing by label" ,
resource : "seals" ,
mocks : func ( t * testing . T , mock mocker ) {
require . NoError ( t , mock . Tracker ( ) . Add ( & corev1 . Secret {
ObjectMeta : metav1 . ObjectMeta {
Name : "pinniped-storage-seals-lvzgyywdc2dhjdbgf5jvzfyphosigvhnsh6qlse3blumogoqhqhq" ,
Namespace : namespace ,
ResourceVersion : "" ,
Labels : map [ string ] string {
2020-12-04 22:39:11 +00:00
"storage.pinniped.dev/type" : "seals" ,
"additionalLabel" : "matching-value" ,
2020-12-04 22:31:06 +00:00
} ,
2020-12-10 20:15:40 +00:00
Annotations : map [ string ] string {
2020-12-10 22:47:58 +00:00
"storage.pinniped.dev/garbage-collect-after" : fakeNowPlusLifetimeAsString ,
2020-12-10 20:15:40 +00:00
} ,
2020-12-04 22:31:06 +00:00
} ,
Data : map [ string ] [ ] byte {
"pinniped-storage-data" : [ ] byte ( ` { "Data":"sad-seal"} ` ) ,
"pinniped-storage-version" : [ ] byte ( "1" ) ,
} ,
Type : "storage.pinniped.dev/seals" ,
} ) )
require . NoError ( t , mock . Tracker ( ) . Add ( & corev1 . Secret {
ObjectMeta : metav1 . ObjectMeta {
Name : "pinniped-storage-seals-abcdywdc2dhjdbgf5jvzfyphosigvhnsh6qlse3blumogoqhqhq" ,
Namespace : namespace ,
ResourceVersion : "" ,
Labels : map [ string ] string {
2020-12-04 22:39:11 +00:00
"storage.pinniped.dev/type" : "seals" ,
"additionalLabel" : "matching-value" ,
2020-12-04 22:31:06 +00:00
} ,
2020-12-10 20:15:40 +00:00
Annotations : map [ string ] string {
2020-12-10 22:47:58 +00:00
"storage.pinniped.dev/garbage-collect-after" : fakeNowPlusLifetimeAsString ,
2020-12-10 20:15:40 +00:00
} ,
2020-12-04 22:31:06 +00:00
} ,
Data : map [ string ] [ ] byte {
"pinniped-storage-data" : [ ] byte ( ` { "Data":"happy-seal"} ` ) ,
"pinniped-storage-version" : [ ] byte ( "1" ) ,
} ,
Type : "storage.pinniped.dev/seals" ,
} ) )
require . NoError ( t , mock . Tracker ( ) . Add ( & corev1 . Secret {
ObjectMeta : metav1 . ObjectMeta {
Name : "pinniped-storage-seals-12345wdc2dhjdbgf5jvzfyphosigvhnsh6qlse3blumogoqhqhq" ,
Namespace : namespace ,
ResourceVersion : "" ,
Labels : map [ string ] string {
2020-12-04 22:39:11 +00:00
"storage.pinniped.dev/type" : "seals" , // same type as above
"additionalLabel" : "non-matching-value" , // different value for the same label
2020-12-04 22:31:06 +00:00
} ,
2020-12-10 20:15:40 +00:00
Annotations : map [ string ] string {
2020-12-10 22:47:58 +00:00
"storage.pinniped.dev/garbage-collect-after" : fakeNowPlusLifetimeAsString ,
2020-12-10 20:15:40 +00:00
} ,
2020-12-04 22:31:06 +00:00
} ,
Data : map [ string ] [ ] byte {
"pinniped-storage-data" : [ ] byte ( ` { "Data":"sad-seal2"} ` ) ,
"pinniped-storage-version" : [ ] byte ( "1" ) ,
} ,
Type : "storage.pinniped.dev/seals" ,
} ) )
require . NoError ( t , mock . Tracker ( ) . Add ( & corev1 . Secret {
ObjectMeta : metav1 . ObjectMeta {
Name : "pinniped-storage-seals-54321wdc2dhjdbgf5jvzfyphosigvhnsh6qlse3blumogoqhqhq" ,
Namespace : namespace ,
ResourceVersion : "" ,
Labels : map [ string ] string {
2020-12-04 22:39:11 +00:00
"storage.pinniped.dev/type" : "walruses" , // different type from above
"additionalLabel" : "matching-value" , // same value for the same label as above
2020-12-04 22:31:06 +00:00
} ,
2020-12-10 20:15:40 +00:00
Annotations : map [ string ] string {
2020-12-10 22:47:58 +00:00
"storage.pinniped.dev/garbage-collect-after" : fakeNowPlusLifetimeAsString ,
2020-12-10 20:15:40 +00:00
} ,
2020-12-04 22:31:06 +00:00
} ,
Data : map [ string ] [ ] byte {
"pinniped-storage-data" : [ ] byte ( ` { "Data":"sad-seal3"} ` ) ,
"pinniped-storage-version" : [ ] byte ( "1" ) ,
} ,
Type : "storage.pinniped.dev/walruses" ,
} ) )
} ,
2021-12-10 22:22:36 +00:00
run : func ( t * testing . T , storage Storage , fakeClock * clocktesting . FakeClock ) error {
2020-12-04 22:31:06 +00:00
return storage . DeleteByLabel ( ctx , "additionalLabel" , "matching-value" )
} ,
wantActions : [ ] coretesting . Action {
coretesting . NewListAction ( secretsGVR , schema . GroupVersionKind { Group : "" , Version : "v1" , Kind : "Secret" } , namespace , metav1 . ListOptions {
2020-12-04 22:39:11 +00:00
LabelSelector : "storage.pinniped.dev/type=seals,additionalLabel=matching-value" ,
2020-12-04 22:31:06 +00:00
} ) ,
coretesting . NewDeleteAction ( secretsGVR , namespace , "pinniped-storage-seals-abcdywdc2dhjdbgf5jvzfyphosigvhnsh6qlse3blumogoqhqhq" ) ,
coretesting . NewDeleteAction ( secretsGVR , namespace , "pinniped-storage-seals-lvzgyywdc2dhjdbgf5jvzfyphosigvhnsh6qlse3blumogoqhqhq" ) ,
} ,
wantSecrets : [ ] corev1 . Secret {
// the secret of the same type whose label did not match is not deleted
{
ObjectMeta : metav1 . ObjectMeta {
Name : "pinniped-storage-seals-12345wdc2dhjdbgf5jvzfyphosigvhnsh6qlse3blumogoqhqhq" ,
Namespace : namespace ,
ResourceVersion : "" ,
Labels : map [ string ] string {
2020-12-04 22:39:11 +00:00
"storage.pinniped.dev/type" : "seals" , // same type as above
"additionalLabel" : "non-matching-value" , // different value for the same label
2020-12-04 22:31:06 +00:00
} ,
2020-12-10 20:15:40 +00:00
Annotations : map [ string ] string {
2020-12-10 22:47:58 +00:00
"storage.pinniped.dev/garbage-collect-after" : fakeNowPlusLifetimeAsString ,
2020-12-10 20:15:40 +00:00
} ,
2020-12-04 22:31:06 +00:00
} ,
Data : map [ string ] [ ] byte {
"pinniped-storage-data" : [ ] byte ( ` { "Data":"sad-seal2"} ` ) ,
"pinniped-storage-version" : [ ] byte ( "1" ) ,
} ,
Type : "storage.pinniped.dev/seals" ,
} ,
// the secrets of other types are not deleted, even if they have a matching label
{
ObjectMeta : metav1 . ObjectMeta {
Name : "pinniped-storage-seals-54321wdc2dhjdbgf5jvzfyphosigvhnsh6qlse3blumogoqhqhq" ,
Namespace : namespace ,
ResourceVersion : "" ,
Labels : map [ string ] string {
2020-12-04 22:39:11 +00:00
"storage.pinniped.dev/type" : "walruses" , // different type from above
"additionalLabel" : "matching-value" , // same value for the same label as above
2020-12-04 22:31:06 +00:00
} ,
2020-12-10 20:15:40 +00:00
Annotations : map [ string ] string {
2020-12-10 22:47:58 +00:00
"storage.pinniped.dev/garbage-collect-after" : fakeNowPlusLifetimeAsString ,
2020-12-10 20:15:40 +00:00
} ,
2020-12-04 22:31:06 +00:00
} ,
Data : map [ string ] [ ] byte {
"pinniped-storage-data" : [ ] byte ( ` { "Data":"sad-seal3"} ` ) ,
"pinniped-storage-version" : [ ] byte ( "1" ) ,
} ,
Type : "storage.pinniped.dev/walruses" ,
} ,
} ,
wantErr : "" ,
} ,
{
name : "when there is an error performing the delete while deleting by label" ,
resource : "seals" ,
mocks : func ( t * testing . T , mock mocker ) {
require . NoError ( t , mock . Tracker ( ) . Add ( & corev1 . Secret {
ObjectMeta : metav1 . ObjectMeta {
Name : "pinniped-storage-seals-lvzgyywdc2dhjdbgf5jvzfyphosigvhnsh6qlse3blumogoqhqhq" ,
Namespace : namespace ,
ResourceVersion : "" ,
Labels : map [ string ] string {
2020-12-04 22:39:11 +00:00
"storage.pinniped.dev/type" : "seals" ,
"additionalLabel" : "matching-value" ,
2020-12-04 22:31:06 +00:00
} ,
2020-12-10 20:15:40 +00:00
Annotations : map [ string ] string {
2020-12-10 22:47:58 +00:00
"storage.pinniped.dev/garbage-collect-after" : fakeNowPlusLifetimeAsString ,
2020-12-10 20:15:40 +00:00
} ,
2020-12-04 22:31:06 +00:00
} ,
Data : map [ string ] [ ] byte {
"pinniped-storage-data" : [ ] byte ( ` { "Data":"sad-seal"} ` ) ,
"pinniped-storage-version" : [ ] byte ( "1" ) ,
} ,
Type : "storage.pinniped.dev/seals" ,
} ) )
mock . PrependReactor ( "delete" , "secrets" , func ( action coretesting . Action ) ( handled bool , ret runtime . Object , err error ) {
return true , nil , fmt . Errorf ( "some delete error" )
} )
} ,
2021-12-10 22:22:36 +00:00
run : func ( t * testing . T , storage Storage , fakeClock * clocktesting . FakeClock ) error {
2020-12-04 22:31:06 +00:00
return storage . DeleteByLabel ( ctx , "additionalLabel" , "matching-value" )
} ,
wantActions : [ ] coretesting . Action {
coretesting . NewListAction ( secretsGVR , schema . GroupVersionKind { Group : "" , Version : "v1" , Kind : "Secret" } , namespace , metav1 . ListOptions {
2020-12-04 22:39:11 +00:00
LabelSelector : "storage.pinniped.dev/type=seals,additionalLabel=matching-value" ,
2020-12-04 22:31:06 +00:00
} ) ,
coretesting . NewDeleteAction ( secretsGVR , namespace , "pinniped-storage-seals-lvzgyywdc2dhjdbgf5jvzfyphosigvhnsh6qlse3blumogoqhqhq" ) ,
} ,
wantSecrets : [ ] corev1 . Secret {
{
ObjectMeta : metav1 . ObjectMeta {
Name : "pinniped-storage-seals-lvzgyywdc2dhjdbgf5jvzfyphosigvhnsh6qlse3blumogoqhqhq" ,
Namespace : namespace ,
ResourceVersion : "" ,
Labels : map [ string ] string {
2020-12-04 22:39:11 +00:00
"storage.pinniped.dev/type" : "seals" ,
"additionalLabel" : "matching-value" ,
2020-12-04 22:31:06 +00:00
} ,
2020-12-10 20:15:40 +00:00
Annotations : map [ string ] string {
2020-12-10 22:47:58 +00:00
"storage.pinniped.dev/garbage-collect-after" : fakeNowPlusLifetimeAsString ,
2020-12-10 20:15:40 +00:00
} ,
2020-12-04 22:31:06 +00:00
} ,
Data : map [ string ] [ ] byte {
"pinniped-storage-data" : [ ] byte ( ` { "Data":"sad-seal"} ` ) ,
"pinniped-storage-version" : [ ] byte ( "1" ) ,
} ,
Type : "storage.pinniped.dev/seals" ,
} ,
} ,
wantErr : ` failed to delete secrets for resource "seals" matching label "additionalLabel=matching-value" with name pinniped-storage-seals-lvzgyywdc2dhjdbgf5jvzfyphosigvhnsh6qlse3blumogoqhqhq: some delete error ` ,
} ,
{
name : "when there is an error listing secrets during a delete by label operation" ,
resource : "seals" ,
mocks : func ( t * testing . T , mock mocker ) {
mock . PrependReactor ( "list" , "secrets" , func ( action coretesting . Action ) ( handled bool , ret runtime . Object , err error ) {
listAction := action . ( coretesting . ListActionImpl )
labelRestrictions := listAction . GetListRestrictions ( ) . Labels
requiresExactMatch , found := labelRestrictions . RequiresExactMatch ( "additionalLabel" )
if ! found || requiresExactMatch != "matching-value" {
// this list action did not use label selector additionalLabel=matching-value, so allow it to proceed without intervention
return false , nil , nil
}
2020-12-04 22:39:11 +00:00
requiresExactMatch , found = labelRestrictions . RequiresExactMatch ( "storage.pinniped.dev/type" )
2020-12-04 22:31:06 +00:00
if ! found || requiresExactMatch != "seals" {
2020-12-04 22:39:11 +00:00
// this list action did not use label selector storage.pinniped.dev/type=seals, so allow it to proceed without intervention
2020-12-04 22:31:06 +00:00
return false , nil , nil
}
// this list action was the one that did use the expected label selectors so cause it to error
return true , nil , fmt . Errorf ( "some listing error" )
} )
} ,
2021-12-10 22:22:36 +00:00
run : func ( t * testing . T , storage Storage , fakeClock * clocktesting . FakeClock ) error {
2020-12-04 22:31:06 +00:00
return storage . DeleteByLabel ( ctx , "additionalLabel" , "matching-value" )
} ,
wantActions : [ ] coretesting . Action {
coretesting . NewListAction ( secretsGVR , schema . GroupVersionKind { Group : "" , Version : "v1" , Kind : "Secret" } , namespace , metav1 . ListOptions {
2020-12-04 22:39:11 +00:00
LabelSelector : "storage.pinniped.dev/type=seals,additionalLabel=matching-value" ,
2020-12-04 22:31:06 +00:00
} ) ,
} ,
wantErr : ` failed to list secrets for resource "seals" matching label "additionalLabel=matching-value": some listing error ` ,
} ,
2020-11-17 16:42:11 +00:00
{
name : "invalid exiting secret type" ,
resource : "candies" ,
mocks : func ( t * testing . T , mock mocker ) {
err := mock . Tracker ( ) . Add ( & corev1 . Secret {
ObjectMeta : metav1 . ObjectMeta {
Name : "pinniped-storage-candies-4wssc5gzt5mlln6iux6gl7hzz3klsirisydaxn7indnpvdnrs5ba" ,
Namespace : namespace ,
ResourceVersion : "55" ,
Labels : map [ string ] string {
2020-12-04 22:39:11 +00:00
"storage.pinniped.dev/type" : "candies" ,
2020-11-17 16:42:11 +00:00
} ,
2020-12-10 20:15:40 +00:00
Annotations : map [ string ] string {
2020-12-10 22:47:58 +00:00
"storage.pinniped.dev/garbage-collect-after" : fakeNowPlusLifetimeAsString ,
2020-12-10 20:15:40 +00:00
} ,
2020-11-17 16:42:11 +00:00
} ,
Data : map [ string ] [ ] byte {
"pinniped-storage-data" : [ ] byte ( ` { "Data":"twizzlers"} ` ) ,
"pinniped-storage-version" : [ ] byte ( "1" ) ,
} ,
Type : "storage.pinniped.dev/candies-not" ,
} )
require . NoError ( t , err )
} ,
2021-12-10 22:22:36 +00:00
run : func ( t * testing . T , storage Storage , fakeClock * clocktesting . FakeClock ) error {
2020-11-17 16:42:11 +00:00
signature := hmac . AuthorizeCodeSignature ( authorizationCode3 )
require . NotEmpty ( t , signature )
require . NotEmpty ( t , validateSecretName ( signature , false ) ) // signature is not valid secret name as-is
out := & testJSON { }
rv1 , err := storage . Get ( ctx , signature , out )
require . Empty ( t , rv1 )
require . Empty ( t , out . Data )
require . True ( t , errors . Is ( err , ErrSecretTypeMismatch ) )
2021-10-22 21:32:26 +00:00
require . EqualError ( t , err , "error during get for signature 5aUhdNmfWLW3yKX8Zfz5ztS5IiiWBgu36Gja-o2xl0I: " +
"secret storage data has incorrect type: storage.pinniped.dev/candies-not must equal storage.pinniped.dev/candies" )
2020-11-17 16:42:11 +00:00
return nil
} ,
wantActions : [ ] coretesting . Action {
coretesting . NewGetAction ( secretsGVR , namespace , "pinniped-storage-candies-4wssc5gzt5mlln6iux6gl7hzz3klsirisydaxn7indnpvdnrs5ba" ) ,
} ,
wantSecrets : [ ] corev1 . Secret {
{
ObjectMeta : metav1 . ObjectMeta {
Name : "pinniped-storage-candies-4wssc5gzt5mlln6iux6gl7hzz3klsirisydaxn7indnpvdnrs5ba" ,
Namespace : namespace ,
ResourceVersion : "55" ,
Labels : map [ string ] string {
2020-12-04 22:39:11 +00:00
"storage.pinniped.dev/type" : "candies" ,
2020-11-17 16:42:11 +00:00
} ,
2020-12-10 20:15:40 +00:00
Annotations : map [ string ] string {
2020-12-10 22:47:58 +00:00
"storage.pinniped.dev/garbage-collect-after" : fakeNowPlusLifetimeAsString ,
2020-12-10 20:15:40 +00:00
} ,
2020-11-17 16:42:11 +00:00
} ,
Data : map [ string ] [ ] byte {
"pinniped-storage-data" : [ ] byte ( ` { "Data":"twizzlers"} ` ) ,
"pinniped-storage-version" : [ ] byte ( "1" ) ,
} ,
Type : "storage.pinniped.dev/candies-not" ,
} ,
} ,
wantErr : "" ,
} ,
{
name : "invalid exiting secret wrong label" ,
resource : "candies" ,
mocks : func ( t * testing . T , mock mocker ) {
err := mock . Tracker ( ) . Add ( & corev1 . Secret {
ObjectMeta : metav1 . ObjectMeta {
Name : "pinniped-storage-candies-4wssc5gzt5mlln6iux6gl7hzz3klsirisydaxn7indnpvdnrs5ba" ,
Namespace : namespace ,
ResourceVersion : "55" ,
Labels : map [ string ] string {
2020-12-04 22:39:11 +00:00
"storage.pinniped.dev/type" : "candies-are-bad" ,
2020-11-17 16:42:11 +00:00
} ,
2020-12-10 20:15:40 +00:00
Annotations : map [ string ] string {
2020-12-10 22:47:58 +00:00
"storage.pinniped.dev/garbage-collect-after" : fakeNowPlusLifetimeAsString ,
2020-12-10 20:15:40 +00:00
} ,
2020-11-17 16:42:11 +00:00
} ,
Data : map [ string ] [ ] byte {
"pinniped-storage-data" : [ ] byte ( ` { "Data":"twizzlers"} ` ) ,
"pinniped-storage-version" : [ ] byte ( "1" ) ,
} ,
Type : "storage.pinniped.dev/candies" ,
} )
require . NoError ( t , err )
} ,
2021-12-10 22:22:36 +00:00
run : func ( t * testing . T , storage Storage , fakeClock * clocktesting . FakeClock ) error {
2020-11-17 16:42:11 +00:00
signature := hmac . AuthorizeCodeSignature ( authorizationCode3 )
require . NotEmpty ( t , signature )
require . NotEmpty ( t , validateSecretName ( signature , false ) ) // signature is not valid secret name as-is
out := & testJSON { }
rv1 , err := storage . Get ( ctx , signature , out )
require . Empty ( t , rv1 )
require . Empty ( t , out . Data )
require . True ( t , errors . Is ( err , ErrSecretLabelMismatch ) )
2021-10-22 21:32:26 +00:00
require . EqualError ( t , err , "error during get for signature 5aUhdNmfWLW3yKX8Zfz5ztS5IiiWBgu36Gja-o2xl0I: " +
"secret storage data has incorrect label: candies-are-bad must equal candies" )
2020-11-17 16:42:11 +00:00
return nil
} ,
wantActions : [ ] coretesting . Action {
coretesting . NewGetAction ( secretsGVR , namespace , "pinniped-storage-candies-4wssc5gzt5mlln6iux6gl7hzz3klsirisydaxn7indnpvdnrs5ba" ) ,
} ,
wantSecrets : [ ] corev1 . Secret {
{
ObjectMeta : metav1 . ObjectMeta {
Name : "pinniped-storage-candies-4wssc5gzt5mlln6iux6gl7hzz3klsirisydaxn7indnpvdnrs5ba" ,
Namespace : namespace ,
ResourceVersion : "55" ,
Labels : map [ string ] string {
2020-12-04 22:39:11 +00:00
"storage.pinniped.dev/type" : "candies-are-bad" ,
2020-11-17 16:42:11 +00:00
} ,
2020-12-10 20:15:40 +00:00
Annotations : map [ string ] string {
2020-12-10 22:47:58 +00:00
"storage.pinniped.dev/garbage-collect-after" : fakeNowPlusLifetimeAsString ,
2020-12-10 20:15:40 +00:00
} ,
2020-11-17 16:42:11 +00:00
} ,
Data : map [ string ] [ ] byte {
"pinniped-storage-data" : [ ] byte ( ` { "Data":"twizzlers"} ` ) ,
"pinniped-storage-version" : [ ] byte ( "1" ) ,
} ,
Type : "storage.pinniped.dev/candies" ,
} ,
} ,
wantErr : "" ,
} ,
{
name : "invalid exiting secret wrong version" ,
resource : "candies" ,
mocks : func ( t * testing . T , mock mocker ) {
err := mock . Tracker ( ) . Add ( & corev1 . Secret {
ObjectMeta : metav1 . ObjectMeta {
Name : "pinniped-storage-candies-4wssc5gzt5mlln6iux6gl7hzz3klsirisydaxn7indnpvdnrs5ba" ,
Namespace : namespace ,
ResourceVersion : "55" ,
Labels : map [ string ] string {
2020-12-04 22:39:11 +00:00
"storage.pinniped.dev/type" : "candies" ,
2020-11-17 16:42:11 +00:00
} ,
2020-12-10 20:15:40 +00:00
Annotations : map [ string ] string {
2020-12-10 22:47:58 +00:00
"storage.pinniped.dev/garbage-collect-after" : fakeNowPlusLifetimeAsString ,
2020-12-10 20:15:40 +00:00
} ,
2020-11-17 16:42:11 +00:00
} ,
Data : map [ string ] [ ] byte {
"pinniped-storage-data" : [ ] byte ( ` { "Data":"twizzlers"} ` ) ,
"pinniped-storage-version" : [ ] byte ( "77" ) ,
} ,
Type : "storage.pinniped.dev/candies" ,
} )
require . NoError ( t , err )
} ,
2021-12-10 22:22:36 +00:00
run : func ( t * testing . T , storage Storage , fakeClock * clocktesting . FakeClock ) error {
2020-11-17 16:42:11 +00:00
signature := hmac . AuthorizeCodeSignature ( authorizationCode3 )
require . NotEmpty ( t , signature )
require . NotEmpty ( t , validateSecretName ( signature , false ) ) // signature is not valid secret name as-is
out := & testJSON { }
rv1 , err := storage . Get ( ctx , signature , out )
require . Empty ( t , rv1 )
require . Empty ( t , out . Data )
require . True ( t , errors . Is ( err , ErrSecretVersionMismatch ) )
2021-10-22 21:32:26 +00:00
require . EqualError ( t , err , "error during get for signature 5aUhdNmfWLW3yKX8Zfz5ztS5IiiWBgu36Gja-o2xl0I: " +
"secret storage data has incorrect version" )
2020-11-17 16:42:11 +00:00
return nil
} ,
wantActions : [ ] coretesting . Action {
coretesting . NewGetAction ( secretsGVR , namespace , "pinniped-storage-candies-4wssc5gzt5mlln6iux6gl7hzz3klsirisydaxn7indnpvdnrs5ba" ) ,
} ,
wantSecrets : [ ] corev1 . Secret {
{
ObjectMeta : metav1 . ObjectMeta {
Name : "pinniped-storage-candies-4wssc5gzt5mlln6iux6gl7hzz3klsirisydaxn7indnpvdnrs5ba" ,
Namespace : namespace ,
ResourceVersion : "55" ,
Labels : map [ string ] string {
2020-12-04 22:39:11 +00:00
"storage.pinniped.dev/type" : "candies" ,
2020-11-17 16:42:11 +00:00
} ,
2020-12-10 20:15:40 +00:00
Annotations : map [ string ] string {
2020-12-10 22:47:58 +00:00
"storage.pinniped.dev/garbage-collect-after" : fakeNowPlusLifetimeAsString ,
2020-12-10 20:15:40 +00:00
} ,
2020-11-17 16:42:11 +00:00
} ,
Data : map [ string ] [ ] byte {
"pinniped-storage-data" : [ ] byte ( ` { "Data":"twizzlers"} ` ) ,
"pinniped-storage-version" : [ ] byte ( "77" ) ,
} ,
Type : "storage.pinniped.dev/candies" ,
} ,
} ,
wantErr : "" ,
} ,
{
name : "invalid exiting secret not json" ,
resource : "candies" ,
mocks : func ( t * testing . T , mock mocker ) {
err := mock . Tracker ( ) . Add ( & corev1 . Secret {
ObjectMeta : metav1 . ObjectMeta {
Name : "pinniped-storage-candies-4wssc5gzt5mlln6iux6gl7hzz3klsirisydaxn7indnpvdnrs5ba" ,
Namespace : namespace ,
ResourceVersion : "55" ,
Labels : map [ string ] string {
2020-12-04 22:39:11 +00:00
"storage.pinniped.dev/type" : "candies" ,
2020-11-17 16:42:11 +00:00
} ,
2020-12-10 20:15:40 +00:00
Annotations : map [ string ] string {
2020-12-10 22:47:58 +00:00
"storage.pinniped.dev/garbage-collect-after" : fakeNowPlusLifetimeAsString ,
2020-12-10 20:15:40 +00:00
} ,
2020-11-17 16:42:11 +00:00
} ,
Data : map [ string ] [ ] byte {
"pinniped-storage-data" : [ ] byte ( ` }}bad data {{ ` ) ,
"pinniped-storage-version" : [ ] byte ( "1" ) ,
} ,
Type : "storage.pinniped.dev/candies" ,
} )
require . NoError ( t , err )
} ,
2021-12-10 22:22:36 +00:00
run : func ( t * testing . T , storage Storage , fakeClock * clocktesting . FakeClock ) error {
2020-11-17 16:42:11 +00:00
signature := hmac . AuthorizeCodeSignature ( authorizationCode3 )
require . NotEmpty ( t , signature )
require . NotEmpty ( t , validateSecretName ( signature , false ) ) // signature is not valid secret name as-is
out := & testJSON { }
rv1 , err := storage . Get ( ctx , signature , out )
require . Empty ( t , rv1 )
require . Empty ( t , out . Data )
2021-10-22 21:32:26 +00:00
require . EqualError ( t , err , "error during get for signature 5aUhdNmfWLW3yKX8Zfz5ztS5IiiWBgu36Gja-o2xl0I: " +
"failed to decode candies: invalid character '}' looking for beginning of value" )
2020-11-17 16:42:11 +00:00
return nil
} ,
wantActions : [ ] coretesting . Action {
coretesting . NewGetAction ( secretsGVR , namespace , "pinniped-storage-candies-4wssc5gzt5mlln6iux6gl7hzz3klsirisydaxn7indnpvdnrs5ba" ) ,
} ,
wantSecrets : [ ] corev1 . Secret {
{
ObjectMeta : metav1 . ObjectMeta {
Name : "pinniped-storage-candies-4wssc5gzt5mlln6iux6gl7hzz3klsirisydaxn7indnpvdnrs5ba" ,
Namespace : namespace ,
ResourceVersion : "55" ,
Labels : map [ string ] string {
2020-12-04 22:39:11 +00:00
"storage.pinniped.dev/type" : "candies" ,
2020-11-17 16:42:11 +00:00
} ,
2020-12-10 20:15:40 +00:00
Annotations : map [ string ] string {
2020-12-10 22:47:58 +00:00
"storage.pinniped.dev/garbage-collect-after" : fakeNowPlusLifetimeAsString ,
2020-12-10 20:15:40 +00:00
} ,
2020-11-17 16:42:11 +00:00
} ,
Data : map [ string ] [ ] byte {
"pinniped-storage-data" : [ ] byte ( ` }}bad data {{ ` ) ,
"pinniped-storage-version" : [ ] byte ( "1" ) ,
} ,
Type : "storage.pinniped.dev/candies" ,
} ,
} ,
wantErr : "" ,
} ,
}
for _ , tt := range tests {
tt := tt
t . Run ( tt . name , func ( t * testing . T ) {
t . Parallel ( )
client := fake . NewSimpleClientset ( )
if tt . mocks != nil {
tt . mocks ( t , client )
}
secrets := client . CoreV1 ( ) . Secrets ( namespace )
2021-12-10 22:22:36 +00:00
fakeClock := clocktesting . NewFakeClock ( fakeNow )
2020-12-10 22:47:58 +00:00
storage := New ( tt . resource , secrets , fakeClock . Now , lifetime )
2020-11-17 16:42:11 +00:00
2020-12-10 22:47:58 +00:00
err := tt . run ( t , storage , fakeClock )
2020-11-17 16:42:11 +00:00
require . Equal ( t , tt . wantErr , errString ( err ) )
require . Equal ( t , tt . wantActions , client . Actions ( ) )
checkSecretActionNames ( t , client . Actions ( ) )
actualSecrets , err := secrets . List ( ctx , metav1 . ListOptions { } )
require . NoError ( t , err )
require . Equal ( t , tt . wantSecrets , actualSecrets . Items )
checkSecretListNames ( t , actualSecrets . Items )
} )
}
}
func checkSecretActionNames ( t * testing . T , actions [ ] coretesting . Action ) {
t . Helper ( )
for _ , action := range actions {
2020-12-04 22:31:06 +00:00
_ , ok := action . ( coretesting . ListActionImpl )
if ! ok { // list action don't have names, so skip these assertions for list actions
name := getName ( t , action )
assertValidName ( t , name )
}
2020-11-17 16:42:11 +00:00
}
}
func checkSecretListNames ( t * testing . T , secrets [ ] corev1 . Secret ) {
t . Helper ( )
for _ , secret := range secrets {
assertValidName ( t , secret . Name )
}
}
func assertValidName ( t * testing . T , name string ) {
t . Helper ( )
validateSecretName := validation . NameIsDNSSubdomain // matches k/k
require . NotEmpty ( t , name )
require . Empty ( t , validateSecretName ( name , false ) )
require . Empty ( t , validateSecretName ( name , true ) ) // I do not think we actually care about this case
}
func getName ( t * testing . T , action coretesting . Action ) string {
t . Helper ( )
if getter , ok := action . ( interface {
GetName ( ) string
} ) ; ok {
return getter . GetName ( )
}
if getter , ok := action . ( interface {
GetObject ( ) runtime . Object
} ) ; ok {
accessor , err := meta . Accessor ( getter . GetObject ( ) )
require . NoError ( t , err )
return accessor . GetName ( )
}
t . Fatalf ( "failed to get name for action: %#v" , action )
panic ( "unreachable" )
}
func errString ( err error ) string {
if err == nil {
return ""
}
return err . Error ( )
}
2021-10-22 21:32:26 +00:00
func TestFromSecret ( t * testing . T ) {
fakeNow := time . Date ( 2030 , time . January , 1 , 0 , 0 , 0 , 0 , time . UTC )
lifetime := time . Minute * 10
fakeNowPlusLifetimeAsString := metav1 . Time { Time : fakeNow . Add ( lifetime ) } . Format ( time . RFC3339 )
type testJSON struct {
Data string
}
tests := [ ] struct {
name string
resource string
secret * corev1 . Secret
wantData * testJSON
wantErr string
} {
{
name : "happy path" ,
resource : "candies" ,
secret : & corev1 . Secret {
ObjectMeta : metav1 . ObjectMeta {
Name : "pinniped-storage-candies-lvzgyywdc2dhjdbgf5jvzfyphosigvhnsh6qlse3blumogoqhqhq" ,
Namespace : "some-namespace" ,
ResourceVersion : "" ,
Labels : map [ string ] string {
"storage.pinniped.dev/type" : "candies" ,
} ,
Annotations : map [ string ] string {
"storage.pinniped.dev/garbage-collect-after" : fakeNowPlusLifetimeAsString ,
} ,
} ,
Data : map [ string ] [ ] byte {
"pinniped-storage-data" : [ ] byte ( ` { "Data":"snorlax"} ` ) ,
"pinniped-storage-version" : [ ] byte ( "1" ) ,
} ,
Type : "storage.pinniped.dev/candies" ,
} ,
wantData : & testJSON { Data : "snorlax" } ,
} ,
{
name : "can't unmarshal" ,
resource : "candies" ,
secret : & corev1 . Secret {
ObjectMeta : metav1 . ObjectMeta {
Name : "pinniped-storage-candies-lvzgyywdc2dhjdbgf5jvzfyphosigvhnsh6qlse3blumogoqhqhq" ,
Namespace : "some-namespace" ,
ResourceVersion : "" ,
Labels : map [ string ] string {
"storage.pinniped.dev/type" : "candies" ,
} ,
Annotations : map [ string ] string {
"storage.pinniped.dev/garbage-collect-after" : fakeNowPlusLifetimeAsString ,
} ,
} ,
Data : map [ string ] [ ] byte {
"pinniped-storage-data" : [ ] byte ( ` not-json ` ) ,
"pinniped-storage-version" : [ ] byte ( "1" ) ,
} ,
Type : "storage.pinniped.dev/candies" ,
} ,
wantData : & testJSON { Data : "snorlax" } ,
wantErr : "failed to decode candies: invalid character 'o' in literal null (expecting 'u')" ,
} ,
{
name : "wrong storage version" ,
resource : "candies" ,
secret : & corev1 . Secret {
ObjectMeta : metav1 . ObjectMeta {
Name : "pinniped-storage-candies-lvzgyywdc2dhjdbgf5jvzfyphosigvhnsh6qlse3blumogoqhqhq" ,
Namespace : "some-namespace" ,
ResourceVersion : "" ,
Labels : map [ string ] string {
"storage.pinniped.dev/type" : "candies" ,
} ,
Annotations : map [ string ] string {
"storage.pinniped.dev/garbage-collect-after" : fakeNowPlusLifetimeAsString ,
} ,
} ,
Data : map [ string ] [ ] byte {
"pinniped-storage-data" : [ ] byte ( ` { "Data":"snorlax"} ` ) ,
"pinniped-storage-version" : [ ] byte ( "wrong-version-here" ) ,
} ,
Type : "storage.pinniped.dev/candies" ,
} ,
wantData : & testJSON { Data : "snorlax" } ,
wantErr : "secret storage data has incorrect version" ,
} ,
{
name : "wrong type label" ,
resource : "candies" ,
secret : & corev1 . Secret {
ObjectMeta : metav1 . ObjectMeta {
Name : "pinniped-storage-candies-lvzgyywdc2dhjdbgf5jvzfyphosigvhnsh6qlse3blumogoqhqhq" ,
Namespace : "some-namespace" ,
ResourceVersion : "" ,
Labels : map [ string ] string {
"storage.pinniped.dev/type" : "candies" ,
} ,
Annotations : map [ string ] string {
"storage.pinniped.dev/garbage-collect-after" : fakeNowPlusLifetimeAsString ,
} ,
} ,
Data : map [ string ] [ ] byte {
"pinniped-storage-data" : [ ] byte ( ` { "Data":"snorlax"} ` ) ,
"pinniped-storage-version" : [ ] byte ( "1" ) ,
} ,
Type : "storage.pinniped.dev/not-candies" ,
} ,
wantData : & testJSON { Data : "snorlax" } ,
wantErr : "secret storage data has incorrect type: storage.pinniped.dev/not-candies must equal storage.pinniped.dev/candies" ,
} ,
{
name : "wrong secret type" ,
resource : "candies" ,
secret : & corev1 . Secret {
ObjectMeta : metav1 . ObjectMeta {
Name : "pinniped-storage-candies-lvzgyywdc2dhjdbgf5jvzfyphosigvhnsh6qlse3blumogoqhqhq" ,
Namespace : "some-namespace" ,
ResourceVersion : "" ,
Labels : map [ string ] string {
"storage.pinniped.dev/type" : "candies" ,
} ,
Annotations : map [ string ] string {
"storage.pinniped.dev/garbage-collect-after" : fakeNowPlusLifetimeAsString ,
} ,
} ,
Data : map [ string ] [ ] byte {
"pinniped-storage-data" : [ ] byte ( ` { "Data":"snorlax"} ` ) ,
"pinniped-storage-version" : [ ] byte ( "1" ) ,
} ,
Type : "storage.pinniped.dev/not-candies" ,
} ,
wantData : & testJSON { Data : "snorlax" } ,
wantErr : "secret storage data has incorrect type: storage.pinniped.dev/not-candies must equal storage.pinniped.dev/candies" ,
} ,
}
for _ , tt := range tests {
tt := tt
t . Run ( tt . name , func ( t * testing . T ) {
t . Parallel ( )
data := & testJSON { }
err := FromSecret ( "candies" , tt . secret , data )
if tt . wantErr == "" {
require . NoError ( t , err )
require . Equal ( t , data , tt . wantData )
} else {
require . EqualError ( t , err , tt . wantErr )
}
} )
}
}