knative.dev/pkg@v0.0.0-20260602142205-ac97e43f6622/webhook/helper_test.go (about)

     1  /*
     2  Copyright 2018 The Knative Authors
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package webhook
    18  
    19  import (
    20  	"context"
    21  	"crypto/tls"
    22  	"crypto/x509"
    23  	"net"
    24  	"net/http"
    25  	"testing"
    26  	"time"
    27  
    28  	"github.com/google/go-cmp/cmp"
    29  	corev1 "k8s.io/api/core/v1"
    30  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    31  	"k8s.io/apimachinery/pkg/util/wait"
    32  	"k8s.io/client-go/kubernetes"
    33  	"knative.dev/pkg/system"
    34  	certresources "knative.dev/pkg/webhook/certificates/resources"
    35  
    36  	. "knative.dev/pkg/logging/testing"
    37  )
    38  
    39  func TestEnsureLabelSelectorExpressions(t *testing.T) {
    40  	fooExpression := metav1.LabelSelectorRequirement{
    41  		Key:      "foo.bar/baz",
    42  		Operator: metav1.LabelSelectorOpDoesNotExist,
    43  	}
    44  	knativeExpression := metav1.LabelSelectorRequirement{
    45  		Key:      "knative.dev/foo",
    46  		Operator: metav1.LabelSelectorOpDoesNotExist,
    47  	}
    48  
    49  	tests := []struct {
    50  		name    string
    51  		current *metav1.LabelSelector
    52  		want    *metav1.LabelSelector
    53  		expect  *metav1.LabelSelector
    54  	}{{
    55  		name: "all nil",
    56  	}, {
    57  		name:    "current nil",
    58  		current: nil,
    59  		want: &metav1.LabelSelector{
    60  			MatchExpressions: []metav1.LabelSelectorRequirement{fooExpression},
    61  		},
    62  		expect: &metav1.LabelSelector{
    63  			MatchExpressions: []metav1.LabelSelectorRequirement{fooExpression},
    64  		},
    65  	}, {
    66  		name:    "current empty",
    67  		current: &metav1.LabelSelector{},
    68  		want: &metav1.LabelSelector{
    69  			MatchExpressions: []metav1.LabelSelectorRequirement{fooExpression},
    70  		},
    71  		expect: &metav1.LabelSelector{
    72  			MatchExpressions: []metav1.LabelSelectorRequirement{fooExpression},
    73  		},
    74  	}, {
    75  		name: "want nil",
    76  		current: &metav1.LabelSelector{
    77  			MatchExpressions: []metav1.LabelSelectorRequirement{fooExpression},
    78  		},
    79  		want: nil,
    80  		expect: &metav1.LabelSelector{
    81  			MatchExpressions: []metav1.LabelSelectorRequirement{fooExpression},
    82  		},
    83  	}, {
    84  		name: "want empty",
    85  		current: &metav1.LabelSelector{
    86  			MatchExpressions: []metav1.LabelSelectorRequirement{fooExpression},
    87  		},
    88  		want: &metav1.LabelSelector{},
    89  		expect: &metav1.LabelSelector{
    90  			MatchExpressions: []metav1.LabelSelectorRequirement{fooExpression},
    91  		},
    92  	}, {
    93  		name: "add new",
    94  		current: &metav1.LabelSelector{
    95  			MatchExpressions: []metav1.LabelSelectorRequirement{fooExpression},
    96  		},
    97  		want: &metav1.LabelSelector{
    98  			MatchExpressions: []metav1.LabelSelectorRequirement{knativeExpression},
    99  		},
   100  		expect: &metav1.LabelSelector{
   101  			MatchExpressions: []metav1.LabelSelectorRequirement{
   102  				knativeExpression, fooExpression,
   103  			},
   104  		},
   105  	}, {
   106  		name: "remove obsolete",
   107  		current: &metav1.LabelSelector{
   108  			MatchExpressions: []metav1.LabelSelectorRequirement{fooExpression, {
   109  				Key:      "knative.dev/bar",
   110  				Operator: metav1.LabelSelectorOpDoesNotExist,
   111  			}},
   112  		},
   113  		want: &metav1.LabelSelector{
   114  			MatchExpressions: []metav1.LabelSelectorRequirement{knativeExpression},
   115  		},
   116  		expect: &metav1.LabelSelector{
   117  			MatchExpressions: []metav1.LabelSelectorRequirement{
   118  				knativeExpression, fooExpression,
   119  			},
   120  		},
   121  	}}
   122  
   123  	for _, tc := range tests {
   124  		t.Run(tc.name, func(t *testing.T) {
   125  			got := EnsureLabelSelectorExpressions(tc.current, tc.want)
   126  			if !cmp.Equal(got, tc.expect) {
   127  				t.Errorf("LabelSelector mismatch: diff(-want,+got):\n%s", cmp.Diff(tc.expect, got))
   128  			}
   129  		})
   130  	}
   131  }
   132  
   133  func waitForNonTLSServerAvailable(t *testing.T, serverURL string, timeout time.Duration) error {
   134  	t.Helper()
   135  	interval := 100 * time.Millisecond
   136  
   137  	conditionFunc := func(ctx context.Context) (done bool, err error) {
   138  		var conn net.Conn
   139  		conn, _ = net.DialTimeout("tcp", serverURL, timeout)
   140  		if conn != nil {
   141  			conn.Close()
   142  			return true, nil
   143  		}
   144  		return false, nil
   145  	}
   146  
   147  	return wait.PollUntilContextTimeout(context.Background(), interval, timeout, true, conditionFunc)
   148  }
   149  
   150  func waitForServerAvailable(t *testing.T, serverURL string, timeout time.Duration) error {
   151  	t.Helper()
   152  
   153  	var (
   154  		// if this is too low you'll see TLS handshake EOF warnings
   155  		interval = 500 * time.Millisecond
   156  		tlsConf  = &tls.Config{InsecureSkipVerify: true}
   157  		dialer   = &net.Dialer{
   158  			Timeout:   interval, // Initial duration.
   159  			KeepAlive: 5 * time.Second,
   160  			DualStack: true,
   161  		}
   162  	)
   163  
   164  	conditionFunc := func(ctx context.Context) (done bool, err error) {
   165  		conn, _ := tls.DialWithDialer(dialer, "tcp", serverURL, tlsConf)
   166  		if conn != nil {
   167  			conn.Close()
   168  			return true, nil
   169  		}
   170  		return false, nil
   171  	}
   172  
   173  	return wait.PollUntilContextTimeout(context.Background(), interval, timeout, true, conditionFunc)
   174  }
   175  
   176  func createNamespace(t *testing.T, kubeClient kubernetes.Interface, name string) error {
   177  	t.Helper()
   178  	testns := &corev1.Namespace{
   179  		ObjectMeta: metav1.ObjectMeta{
   180  			Name: name,
   181  		},
   182  	}
   183  	_, err := kubeClient.CoreV1().Namespaces().Create(context.Background(), testns, metav1.CreateOptions{})
   184  	if err != nil {
   185  		return err
   186  	}
   187  	return nil
   188  }
   189  
   190  func createTestConfigMap(t *testing.T, kubeClient kubernetes.Interface) error {
   191  	t.Helper()
   192  	configMaps := &corev1.ConfigMap{
   193  		ObjectMeta: metav1.ObjectMeta{
   194  			Name: "extension-apiserver-authentication",
   195  		},
   196  		Data: map[string]string{"requestheader-client-ca-file": "test-client-file"},
   197  	}
   198  	_, err := kubeClient.CoreV1().ConfigMaps(metav1.NamespaceSystem).Create(context.Background(), configMaps, metav1.CreateOptions{})
   199  	if err != nil {
   200  		return err
   201  	}
   202  	return nil
   203  }
   204  
   205  func createSecureTLSClient(t *testing.T, kubeClient kubernetes.Interface, acOpts *Options) (*http.Client, error) {
   206  	t.Helper()
   207  	ctx := TestContextWithLogger(t)
   208  
   209  	secret, err := kubeClient.CoreV1().Secrets(system.Namespace()).Get(ctx, acOpts.SecretName, metav1.GetOptions{})
   210  	if err != nil {
   211  		return nil, err
   212  	}
   213  
   214  	sKey, sCert := getSecretDataKeyNamesOrDefault(acOpts.ServerPrivateKeyName, acOpts.ServerCertificateName)
   215  
   216  	serverKey := secret.Data[sKey]
   217  	serverCert := secret.Data[sCert]
   218  	caCert := secret.Data[certresources.CACert]
   219  
   220  	// Build cert pool with CA Cert
   221  	pool := x509.NewCertPool()
   222  	pool.AppendCertsFromPEM(caCert)
   223  
   224  	// Build key pair
   225  	cert, err := tls.X509KeyPair(serverCert, serverKey)
   226  	if err != nil {
   227  		return nil, err
   228  	}
   229  
   230  	tlsClientConfig := &tls.Config{
   231  		// Add knative namespace as CN
   232  		ServerName:   "webhook." + system.Namespace(),
   233  		RootCAs:      pool,
   234  		Certificates: []tls.Certificate{cert},
   235  	}
   236  	return &http.Client{
   237  		Transport: &http.Transport{
   238  			TLSClientConfig: tlsClientConfig,
   239  		},
   240  	}, nil
   241  }
   242  
   243  func createNonTLSClient() *http.Client {
   244  	return &http.Client{
   245  		Transport: &http.Transport{},
   246  	}
   247  }