Merge pull request #112894 from pohly/e2e-framework-test-labels
e2e framework: test labels
This commit is contained in:
		
							
								
								
									
										45
									
								
								hack/verify-e2e-suites.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										45
									
								
								hack/verify-e2e-suites.sh
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,45 @@
 | 
			
		||||
#!/usr/bin/env bash
 | 
			
		||||
 | 
			
		||||
# Copyright 2021 The Kubernetes Authors.
 | 
			
		||||
#
 | 
			
		||||
# Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
# you may not use this file except in compliance with the License.
 | 
			
		||||
# You may obtain a copy of the License at
 | 
			
		||||
#
 | 
			
		||||
#     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
#
 | 
			
		||||
# Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
# distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
# See the License for the specific language governing permissions and
 | 
			
		||||
# limitations under the License.
 | 
			
		||||
 | 
			
		||||
# This script checks that all E2E test suites are sane, i.e. can be
 | 
			
		||||
# started without an error.
 | 
			
		||||
 | 
			
		||||
set -o errexit
 | 
			
		||||
set -o nounset
 | 
			
		||||
set -o pipefail
 | 
			
		||||
 | 
			
		||||
KUBE_ROOT=$(dirname "${BASH_SOURCE[0]}")/..
 | 
			
		||||
source "${KUBE_ROOT}/hack/lib/init.sh"
 | 
			
		||||
source "${KUBE_ROOT}/hack/lib/util.sh"
 | 
			
		||||
 | 
			
		||||
kube::golang::verify_go_version
 | 
			
		||||
 | 
			
		||||
cd "${KUBE_ROOT}"
 | 
			
		||||
 | 
			
		||||
kube::util::ensure-temp-dir
 | 
			
		||||
 | 
			
		||||
for suite in $(git grep -l framework.AfterReadingAllFlags | grep -v -e ^test/e2e/framework -e ^hack | xargs -n 1 dirname | sort -u); do
 | 
			
		||||
    # Build a binary and run it in the root directory to get paths that are
 | 
			
		||||
    # relative to that instead of the package directory.
 | 
			
		||||
    out=""
 | 
			
		||||
    if (cd "$suite" && go test -c -o "${KUBE_TEMP}/e2e.bin" .) && out=$("${KUBE_TEMP}/e2e.bin" --list-tests); then
 | 
			
		||||
        echo "E2E suite $suite passed."
 | 
			
		||||
    else
 | 
			
		||||
        echo >&2 "ERROR: E2E test suite invocation failed for $suite."
 | 
			
		||||
        # shellcheck disable=SC2001
 | 
			
		||||
        echo "$out" | sed -e 's/^/   /'
 | 
			
		||||
    fi
 | 
			
		||||
done
 | 
			
		||||
@@ -45,12 +45,10 @@ import (
 | 
			
		||||
// test/e2e/lifecycle/framework.go
 | 
			
		||||
package lifecycle
 | 
			
		||||
 | 
			
		||||
import "github.com/onsi/ginkgo"
 | 
			
		||||
import "k8s.io/kubernetes/test/e2e/framework"
 | 
			
		||||
 | 
			
		||||
// SIGDescribe annotates the test with the SIG label.
 | 
			
		||||
func SIGDescribe(text string, body func()) bool {
 | 
			
		||||
	return ginkgo.Describe("[sig-cluster-lifecycle] "+text, body)
 | 
			
		||||
}
 | 
			
		||||
var SIGDescribe = framework.SIGDescribe("cluster-lifecycle")
 | 
			
		||||
```
 | 
			
		||||
```golang
 | 
			
		||||
// test/e2e/lifecycle/bootstrap/bootstrap_signer.go
 | 
			
		||||
 
 | 
			
		||||
@@ -16,9 +16,7 @@ limitations under the License.
 | 
			
		||||
 | 
			
		||||
package apimachinery
 | 
			
		||||
 | 
			
		||||
import "github.com/onsi/ginkgo/v2"
 | 
			
		||||
import "k8s.io/kubernetes/test/e2e/framework"
 | 
			
		||||
 | 
			
		||||
// SIGDescribe annotates the test with the SIG label.
 | 
			
		||||
func SIGDescribe(text string, body func()) bool {
 | 
			
		||||
	return ginkgo.Describe("[sig-api-machinery] "+text, body)
 | 
			
		||||
}
 | 
			
		||||
var SIGDescribe = framework.SIGDescribe("api-machinery")
 | 
			
		||||
 
 | 
			
		||||
@@ -16,9 +16,7 @@ limitations under the License.
 | 
			
		||||
 | 
			
		||||
package apps
 | 
			
		||||
 | 
			
		||||
import "github.com/onsi/ginkgo/v2"
 | 
			
		||||
import "k8s.io/kubernetes/test/e2e/framework"
 | 
			
		||||
 | 
			
		||||
// SIGDescribe annotates the test with the SIG label.
 | 
			
		||||
func SIGDescribe(text string, body func()) bool {
 | 
			
		||||
	return ginkgo.Describe("[sig-apps] "+text, body)
 | 
			
		||||
}
 | 
			
		||||
var SIGDescribe = framework.SIGDescribe("apps")
 | 
			
		||||
 
 | 
			
		||||
@@ -16,9 +16,7 @@ limitations under the License.
 | 
			
		||||
 | 
			
		||||
package architecture
 | 
			
		||||
 | 
			
		||||
import "github.com/onsi/ginkgo/v2"
 | 
			
		||||
import "k8s.io/kubernetes/test/e2e/framework"
 | 
			
		||||
 | 
			
		||||
// SIGDescribe annotates the test with the SIG label.
 | 
			
		||||
func SIGDescribe(text string, body func()) bool {
 | 
			
		||||
	return ginkgo.Describe("[sig-architecture] "+text, body)
 | 
			
		||||
}
 | 
			
		||||
var SIGDescribe = framework.SIGDescribe("architecture")
 | 
			
		||||
 
 | 
			
		||||
@@ -16,9 +16,7 @@ limitations under the License.
 | 
			
		||||
 | 
			
		||||
package auth
 | 
			
		||||
 | 
			
		||||
import "github.com/onsi/ginkgo/v2"
 | 
			
		||||
import "k8s.io/kubernetes/test/e2e/framework"
 | 
			
		||||
 | 
			
		||||
// SIGDescribe annotates the test with the SIG label.
 | 
			
		||||
func SIGDescribe(text string, body func()) bool {
 | 
			
		||||
	return ginkgo.Describe("[sig-auth] "+text, body)
 | 
			
		||||
}
 | 
			
		||||
var SIGDescribe = framework.SIGDescribe("auth")
 | 
			
		||||
 
 | 
			
		||||
@@ -16,9 +16,7 @@ limitations under the License.
 | 
			
		||||
 | 
			
		||||
package autoscaling
 | 
			
		||||
 | 
			
		||||
import "github.com/onsi/ginkgo/v2"
 | 
			
		||||
import "k8s.io/kubernetes/test/e2e/framework"
 | 
			
		||||
 | 
			
		||||
// SIGDescribe annotates the test with the SIG label.
 | 
			
		||||
func SIGDescribe(text string, body func()) bool {
 | 
			
		||||
	return ginkgo.Describe("[sig-autoscaling] "+text, body)
 | 
			
		||||
}
 | 
			
		||||
var SIGDescribe = framework.SIGDescribe("autoscaling")
 | 
			
		||||
 
 | 
			
		||||
@@ -16,9 +16,7 @@ limitations under the License.
 | 
			
		||||
 | 
			
		||||
package cloud
 | 
			
		||||
 | 
			
		||||
import "github.com/onsi/ginkgo/v2"
 | 
			
		||||
import "k8s.io/kubernetes/test/e2e/framework"
 | 
			
		||||
 | 
			
		||||
// SIGDescribe annotates the test with the SIG label.
 | 
			
		||||
func SIGDescribe(text string, body func()) bool {
 | 
			
		||||
	return ginkgo.Describe("[sig-cloud-provider] "+text, body)
 | 
			
		||||
}
 | 
			
		||||
var SIGDescribe = framework.SIGDescribe("cloud-provider")
 | 
			
		||||
 
 | 
			
		||||
@@ -16,9 +16,7 @@ limitations under the License.
 | 
			
		||||
 | 
			
		||||
package apps
 | 
			
		||||
 | 
			
		||||
import "github.com/onsi/ginkgo/v2"
 | 
			
		||||
import "k8s.io/kubernetes/test/e2e/framework"
 | 
			
		||||
 | 
			
		||||
// SIGDescribe annotates the test with the SIG label.
 | 
			
		||||
func SIGDescribe(text string, body func()) bool {
 | 
			
		||||
	return ginkgo.Describe("[sig-apps] "+text, body)
 | 
			
		||||
}
 | 
			
		||||
var SIGDescribe = framework.SIGDescribe("apps")
 | 
			
		||||
 
 | 
			
		||||
@@ -16,9 +16,7 @@ limitations under the License.
 | 
			
		||||
 | 
			
		||||
package auth
 | 
			
		||||
 | 
			
		||||
import "github.com/onsi/ginkgo/v2"
 | 
			
		||||
import "k8s.io/kubernetes/test/e2e/framework"
 | 
			
		||||
 | 
			
		||||
// SIGDescribe annotates the test with the SIG label.
 | 
			
		||||
func SIGDescribe(text string, body func()) bool {
 | 
			
		||||
	return ginkgo.Describe("[sig-auth] "+text, body)
 | 
			
		||||
}
 | 
			
		||||
var SIGDescribe = framework.SIGDescribe("auth")
 | 
			
		||||
 
 | 
			
		||||
@@ -16,9 +16,7 @@ limitations under the License.
 | 
			
		||||
 | 
			
		||||
package gcp
 | 
			
		||||
 | 
			
		||||
import "github.com/onsi/ginkgo/v2"
 | 
			
		||||
import "k8s.io/kubernetes/test/e2e/framework"
 | 
			
		||||
 | 
			
		||||
// SIGDescribe annotates the test with the SIG label.
 | 
			
		||||
func SIGDescribe(text string, body func()) bool {
 | 
			
		||||
	return ginkgo.Describe("[sig-cloud-provider-gcp] "+text, body)
 | 
			
		||||
}
 | 
			
		||||
var SIGDescribe = framework.SIGDescribe("cloud-provider-gcp")
 | 
			
		||||
 
 | 
			
		||||
@@ -16,9 +16,7 @@ limitations under the License.
 | 
			
		||||
 | 
			
		||||
package network
 | 
			
		||||
 | 
			
		||||
import "github.com/onsi/ginkgo/v2"
 | 
			
		||||
import "k8s.io/kubernetes/test/e2e/framework"
 | 
			
		||||
 | 
			
		||||
// SIGDescribe annotates the test with the SIG label.
 | 
			
		||||
func SIGDescribe(text string, body func()) bool {
 | 
			
		||||
	return ginkgo.Describe("[sig-network] "+text, body)
 | 
			
		||||
}
 | 
			
		||||
var SIGDescribe = framework.SIGDescribe("network")
 | 
			
		||||
 
 | 
			
		||||
@@ -16,9 +16,7 @@ limitations under the License.
 | 
			
		||||
 | 
			
		||||
package node
 | 
			
		||||
 | 
			
		||||
import "github.com/onsi/ginkgo/v2"
 | 
			
		||||
import "k8s.io/kubernetes/test/e2e/framework"
 | 
			
		||||
 | 
			
		||||
// SIGDescribe annotates the test with the SIG label.
 | 
			
		||||
func SIGDescribe(text string, body func()) bool {
 | 
			
		||||
	return ginkgo.Describe("[sig-node] "+text, body)
 | 
			
		||||
}
 | 
			
		||||
var SIGDescribe = framework.SIGDescribe("node")
 | 
			
		||||
 
 | 
			
		||||
@@ -16,9 +16,7 @@ limitations under the License.
 | 
			
		||||
 | 
			
		||||
package network
 | 
			
		||||
 | 
			
		||||
import "github.com/onsi/ginkgo/v2"
 | 
			
		||||
import "k8s.io/kubernetes/test/e2e/framework"
 | 
			
		||||
 | 
			
		||||
// SIGDescribe annotates the test with the SIG label.
 | 
			
		||||
func SIGDescribe(text string, body func()) bool {
 | 
			
		||||
	return ginkgo.Describe("[sig-network] "+text, body)
 | 
			
		||||
}
 | 
			
		||||
var SIGDescribe = framework.SIGDescribe("network")
 | 
			
		||||
 
 | 
			
		||||
@@ -16,9 +16,6 @@ limitations under the License.
 | 
			
		||||
 | 
			
		||||
package node
 | 
			
		||||
 | 
			
		||||
import "github.com/onsi/ginkgo/v2"
 | 
			
		||||
import "k8s.io/kubernetes/test/e2e/framework"
 | 
			
		||||
 | 
			
		||||
// SIGDescribe annotates the test with the SIG label.
 | 
			
		||||
func SIGDescribe(text string, body func()) bool {
 | 
			
		||||
	return ginkgo.Describe("[sig-node] "+text, body)
 | 
			
		||||
}
 | 
			
		||||
var SIGDescribe = framework.SIGDescribe("node")
 | 
			
		||||
 
 | 
			
		||||
@@ -16,9 +16,7 @@ limitations under the License.
 | 
			
		||||
 | 
			
		||||
package storage
 | 
			
		||||
 | 
			
		||||
import "github.com/onsi/ginkgo/v2"
 | 
			
		||||
import "k8s.io/kubernetes/test/e2e/framework"
 | 
			
		||||
 | 
			
		||||
// SIGDescribe annotates the test with the SIG label.
 | 
			
		||||
func SIGDescribe(text string, body func()) bool {
 | 
			
		||||
	return ginkgo.Describe("[sig-storage] "+text, body)
 | 
			
		||||
}
 | 
			
		||||
var SIGDescribe = framework.SIGDescribe("storage")
 | 
			
		||||
 
 | 
			
		||||
@@ -43,6 +43,10 @@ import (
 | 
			
		||||
	e2etestingmanifests "k8s.io/kubernetes/test/e2e/testing-manifests"
 | 
			
		||||
	testfixtures "k8s.io/kubernetes/test/fixtures"
 | 
			
		||||
 | 
			
		||||
	// define and freeze constants
 | 
			
		||||
	_ "k8s.io/kubernetes/test/e2e/feature"
 | 
			
		||||
	_ "k8s.io/kubernetes/test/e2e/nodefeature"
 | 
			
		||||
 | 
			
		||||
	// test sources
 | 
			
		||||
	_ "k8s.io/kubernetes/test/e2e/apimachinery"
 | 
			
		||||
	_ "k8s.io/kubernetes/test/e2e/apps"
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										132
									
								
								test/e2e/feature/feature.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										132
									
								
								test/e2e/feature/feature.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,132 @@
 | 
			
		||||
/*
 | 
			
		||||
Copyright 2023 The Kubernetes Authors.
 | 
			
		||||
 | 
			
		||||
Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
you may not use this file except in compliance with the License.
 | 
			
		||||
You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
See the License for the specific language governing permissions and
 | 
			
		||||
limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
// Package feature contains pre-defined features used by test/e2e and/or
 | 
			
		||||
// test/e2e_node.
 | 
			
		||||
package feature
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"k8s.io/kubernetes/test/e2e/framework"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	APIServerIdentity                  = framework.WithFeature(framework.ValidFeatures.Add("APIServerIdentity"))
 | 
			
		||||
	AppArmor                           = framework.WithFeature(framework.ValidFeatures.Add("AppArmor"))
 | 
			
		||||
	BootstrapTokens                    = framework.WithFeature(framework.ValidFeatures.Add("BootstrapTokens"))
 | 
			
		||||
	BoundServiceAccountTokenVolume     = framework.WithFeature(framework.ValidFeatures.Add("BoundServiceAccountTokenVolume"))
 | 
			
		||||
	CloudProvider                      = framework.WithFeature(framework.ValidFeatures.Add("CloudProvider"))
 | 
			
		||||
	ClusterAutoscalerScalability1      = framework.WithFeature(framework.ValidFeatures.Add("ClusterAutoscalerScalability1"))
 | 
			
		||||
	ClusterAutoscalerScalability2      = framework.WithFeature(framework.ValidFeatures.Add("ClusterAutoscalerScalability2"))
 | 
			
		||||
	ClusterAutoscalerScalability3      = framework.WithFeature(framework.ValidFeatures.Add("ClusterAutoscalerScalability3"))
 | 
			
		||||
	ClusterAutoscalerScalability4      = framework.WithFeature(framework.ValidFeatures.Add("ClusterAutoscalerScalability4"))
 | 
			
		||||
	ClusterAutoscalerScalability5      = framework.WithFeature(framework.ValidFeatures.Add("ClusterAutoscalerScalability5"))
 | 
			
		||||
	ClusterAutoscalerScalability6      = framework.WithFeature(framework.ValidFeatures.Add("ClusterAutoscalerScalability6"))
 | 
			
		||||
	ClusterDowngrade                   = framework.WithFeature(framework.ValidFeatures.Add("ClusterDowngrade"))
 | 
			
		||||
	ClusterSizeAutoscalingGpu          = framework.WithFeature(framework.ValidFeatures.Add("ClusterSizeAutoscalingGpu"))
 | 
			
		||||
	ClusterSizeAutoscalingScaleDown    = framework.WithFeature(framework.ValidFeatures.Add("ClusterSizeAutoscalingScaleDown"))
 | 
			
		||||
	ClusterSizeAutoscalingScaleUp      = framework.WithFeature(framework.ValidFeatures.Add("ClusterSizeAutoscalingScaleUp"))
 | 
			
		||||
	ClusterUpgrade                     = framework.WithFeature(framework.ValidFeatures.Add("ClusterUpgrade"))
 | 
			
		||||
	ComprehensiveNamespaceDraining     = framework.WithFeature(framework.ValidFeatures.Add("ComprehensiveNamespaceDraining"))
 | 
			
		||||
	CPUManager                         = framework.WithFeature(framework.ValidFeatures.Add("CPUManager"))
 | 
			
		||||
	CustomMetricsAutoscaling           = framework.WithFeature(framework.ValidFeatures.Add("CustomMetricsAutoscaling"))
 | 
			
		||||
	DeviceManager                      = framework.WithFeature(framework.ValidFeatures.Add("DeviceManager"))
 | 
			
		||||
	DevicePluginProbe                  = framework.WithFeature(framework.ValidFeatures.Add("DevicePluginProbe"))
 | 
			
		||||
	Downgrade                          = framework.WithFeature(framework.ValidFeatures.Add("Downgrade"))
 | 
			
		||||
	DynamicResourceAllocation          = framework.WithFeature(framework.ValidFeatures.Add("DynamicResourceAllocation"))
 | 
			
		||||
	EphemeralStorage                   = framework.WithFeature(framework.ValidFeatures.Add("EphemeralStorage"))
 | 
			
		||||
	Example                            = framework.WithFeature(framework.ValidFeatures.Add("Example"))
 | 
			
		||||
	ExperimentalResourceUsageTracking  = framework.WithFeature(framework.ValidFeatures.Add("ExperimentalResourceUsageTracking"))
 | 
			
		||||
	Flexvolumes                        = framework.WithFeature(framework.ValidFeatures.Add("Flexvolumes"))
 | 
			
		||||
	GKENodePool                        = framework.WithFeature(framework.ValidFeatures.Add("GKENodePool"))
 | 
			
		||||
	GPUClusterDowngrade                = framework.WithFeature(framework.ValidFeatures.Add("GPUClusterDowngrade"))
 | 
			
		||||
	GPUClusterUpgrade                  = framework.WithFeature(framework.ValidFeatures.Add("GPUClusterUpgrade"))
 | 
			
		||||
	GPUDevicePlugin                    = framework.WithFeature(framework.ValidFeatures.Add("GPUDevicePlugin"))
 | 
			
		||||
	GPUMasterUpgrade                   = framework.WithFeature(framework.ValidFeatures.Add("GPUMasterUpgrade"))
 | 
			
		||||
	GPUUpgrade                         = framework.WithFeature(framework.ValidFeatures.Add("GPUUpgrade"))
 | 
			
		||||
	HAMaster                           = framework.WithFeature(framework.ValidFeatures.Add("HAMaster"))
 | 
			
		||||
	HPA                                = framework.WithFeature(framework.ValidFeatures.Add("HPA"))
 | 
			
		||||
	HugePages                          = framework.WithFeature(framework.ValidFeatures.Add("HugePages"))
 | 
			
		||||
	Ingress                            = framework.WithFeature(framework.ValidFeatures.Add("Ingress"))
 | 
			
		||||
	IngressScale                       = framework.WithFeature(framework.ValidFeatures.Add("IngressScale"))
 | 
			
		||||
	InPlacePodVerticalScaling          = framework.WithFeature(framework.ValidFeatures.Add("InPlacePodVerticalScaling"))
 | 
			
		||||
	IPv6DualStack                      = framework.WithFeature(framework.ValidFeatures.Add("IPv6DualStack"))
 | 
			
		||||
	Kind                               = framework.WithFeature(framework.ValidFeatures.Add("Kind"))
 | 
			
		||||
	KubeletCredentialProviders         = framework.WithFeature(framework.ValidFeatures.Add("KubeletCredentialProviders"))
 | 
			
		||||
	KubeletSecurity                    = framework.WithFeature(framework.ValidFeatures.Add("KubeletSecurity"))
 | 
			
		||||
	KubeProxyDaemonSetDowngrade        = framework.WithFeature(framework.ValidFeatures.Add("KubeProxyDaemonSetDowngrade"))
 | 
			
		||||
	KubeProxyDaemonSetUpgrade          = framework.WithFeature(framework.ValidFeatures.Add("KubeProxyDaemonSetUpgrade"))
 | 
			
		||||
	KubeProxyDaemonSetMigration        = framework.WithFeature(framework.ValidFeatures.Add("KubeProxyDaemonSetMigration"))
 | 
			
		||||
	LabelSelector                      = framework.WithFeature(framework.ValidFeatures.Add("LabelSelector"))
 | 
			
		||||
	LocalStorageCapacityIsolation      = framework.WithFeature(framework.ValidFeatures.Add("LocalStorageCapacityIsolation"))
 | 
			
		||||
	LocalStorageCapacityIsolationQuota = framework.WithFeature(framework.ValidFeatures.Add("LocalStorageCapacityIsolationQuota"))
 | 
			
		||||
	MasterUpgrade                      = framework.WithFeature(framework.ValidFeatures.Add("MasterUpgrade"))
 | 
			
		||||
	MemoryManager                      = framework.WithFeature(framework.ValidFeatures.Add("MemoryManager"))
 | 
			
		||||
	NEG                                = framework.WithFeature(framework.ValidFeatures.Add("NEG"))
 | 
			
		||||
	NetworkingDNS                      = framework.WithFeature(framework.ValidFeatures.Add("Networking-DNS"))
 | 
			
		||||
	NetworkingIPv4                     = framework.WithFeature(framework.ValidFeatures.Add("Networking-IPv4"))
 | 
			
		||||
	NetworkingIPv6                     = framework.WithFeature(framework.ValidFeatures.Add("Networking-IPv6"))
 | 
			
		||||
	NetworkingPerformance              = framework.WithFeature(framework.ValidFeatures.Add("Networking-Performance"))
 | 
			
		||||
	NetworkPolicy                      = framework.WithFeature(framework.ValidFeatures.Add("NetworkPolicy"))
 | 
			
		||||
	NodeAuthenticator                  = framework.WithFeature(framework.ValidFeatures.Add("NodeAuthenticator"))
 | 
			
		||||
	NodeAuthorizer                     = framework.WithFeature(framework.ValidFeatures.Add("NodeAuthorizer"))
 | 
			
		||||
	NodeOutOfServiceVolumeDetach       = framework.WithFeature(framework.ValidFeatures.Add("NodeOutOfServiceVolumeDetach"))
 | 
			
		||||
	NoSNAT                             = framework.WithFeature(framework.ValidFeatures.Add("NoSNAT"))
 | 
			
		||||
	PerformanceDNS                     = framework.WithFeature(framework.ValidFeatures.Add("PerformanceDNS"))
 | 
			
		||||
	PodGarbageCollector                = framework.WithFeature(framework.ValidFeatures.Add("PodGarbageCollector"))
 | 
			
		||||
	PodPriority                        = framework.WithFeature(framework.ValidFeatures.Add("PodPriority"))
 | 
			
		||||
	PodReadyToStartContainersCondition = framework.WithFeature(framework.ValidFeatures.Add("PodReadyToStartContainersCondition"))
 | 
			
		||||
	PodResources                       = framework.WithFeature(framework.ValidFeatures.Add("PodResources"))
 | 
			
		||||
	ProbeTerminationGracePeriod        = framework.WithFeature(framework.ValidFeatures.Add("ProbeTerminationGracePeriod"))
 | 
			
		||||
	Reboot                             = framework.WithFeature(framework.ValidFeatures.Add("Reboot"))
 | 
			
		||||
	ReclaimPolicy                      = framework.WithFeature(framework.ValidFeatures.Add("ReclaimPolicy"))
 | 
			
		||||
	RecoverVolumeExpansionFailure      = framework.WithFeature(framework.ValidFeatures.Add("RecoverVolumeExpansionFailure"))
 | 
			
		||||
	Recreate                           = framework.WithFeature(framework.ValidFeatures.Add("Recreate"))
 | 
			
		||||
	RegularResourceUsageTracking       = framework.WithFeature(framework.ValidFeatures.Add("RegularResourceUsageTracking"))
 | 
			
		||||
	ScopeSelectors                     = framework.WithFeature(framework.ValidFeatures.Add("ScopeSelectors"))
 | 
			
		||||
	SCTPConnectivity                   = framework.WithFeature(framework.ValidFeatures.Add("SCTPConnectivity"))
 | 
			
		||||
	SeccompDefault                     = framework.WithFeature(framework.ValidFeatures.Add("SeccompDefault"))
 | 
			
		||||
	SELinux                            = framework.WithFeature(framework.ValidFeatures.Add("SELinux"))
 | 
			
		||||
	SELinuxMountReadWriteOncePod       = framework.WithFeature(framework.ValidFeatures.Add("SELinuxMountReadWriteOncePod"))
 | 
			
		||||
	StackdriverAcceleratorMonitoring   = framework.WithFeature(framework.ValidFeatures.Add("StackdriverAcceleratorMonitoring"))
 | 
			
		||||
	StackdriverCustomMetrics           = framework.WithFeature(framework.ValidFeatures.Add("StackdriverCustomMetrics"))
 | 
			
		||||
	StackdriverExternalMetrics         = framework.WithFeature(framework.ValidFeatures.Add("StackdriverExternalMetrics"))
 | 
			
		||||
	StackdriverMetadataAgent           = framework.WithFeature(framework.ValidFeatures.Add("StackdriverMetadataAgent"))
 | 
			
		||||
	StackdriverMonitoring              = framework.WithFeature(framework.ValidFeatures.Add("StackdriverMonitoring"))
 | 
			
		||||
	StandaloneMode                     = framework.WithFeature(framework.ValidFeatures.Add("StandaloneMode"))
 | 
			
		||||
	StatefulSet                        = framework.WithFeature(framework.ValidFeatures.Add("StatefulSet"))
 | 
			
		||||
	StatefulSetStartOrdinal            = framework.WithFeature(framework.ValidFeatures.Add("StatefulSetStartOrdinal"))
 | 
			
		||||
	StatefulUpgrade                    = framework.WithFeature(framework.ValidFeatures.Add("StatefulUpgrade"))
 | 
			
		||||
	StorageProvider                    = framework.WithFeature(framework.ValidFeatures.Add("StorageProvider"))
 | 
			
		||||
	StorageVersionAPI                  = framework.WithFeature(framework.ValidFeatures.Add("StorageVersionAPI"))
 | 
			
		||||
	TopologyHints                      = framework.WithFeature(framework.ValidFeatures.Add("Topology Hints"))
 | 
			
		||||
	UDP                                = framework.WithFeature(framework.ValidFeatures.Add("UDP"))
 | 
			
		||||
	Upgrade                            = framework.WithFeature(framework.ValidFeatures.Add("Upgrade"))
 | 
			
		||||
	UserNamespacesStatelessPodsSupport = framework.WithFeature(framework.ValidFeatures.Add("UserNamespacesStatelessPodsSupport"))
 | 
			
		||||
	ValidatingAdmissionPolicy          = framework.WithFeature(framework.ValidFeatures.Add("ValidatingAdmissionPolicy"))
 | 
			
		||||
	Volumes                            = framework.WithFeature(framework.ValidFeatures.Add("Volumes"))
 | 
			
		||||
	VolumeSnapshotDataSource           = framework.WithFeature(framework.ValidFeatures.Add("VolumeSnapshotDataSource"))
 | 
			
		||||
	VolumeSourceXFS                    = framework.WithFeature(framework.ValidFeatures.Add("VolumeSourceXFS"))
 | 
			
		||||
	Vsphere                            = framework.WithFeature(framework.ValidFeatures.Add("vsphere"))
 | 
			
		||||
	WatchList                          = framework.WithFeature(framework.ValidFeatures.Add("WatchList"))
 | 
			
		||||
	Windows                            = framework.WithFeature(framework.ValidFeatures.Add("Windows"))
 | 
			
		||||
	WindowsHostProcessContainers       = framework.WithFeature(framework.ValidFeatures.Add("WindowsHostProcessContainers"))
 | 
			
		||||
	WindowsHyperVContainers            = framework.WithFeature(framework.ValidFeatures.Add("WindowsHyperVContainers"))
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
	// This prevents adding additional ad-hoc features in tests.
 | 
			
		||||
	framework.ValidFeatures.Freeze()
 | 
			
		||||
}
 | 
			
		||||
@@ -4,7 +4,7 @@ rules:
 | 
			
		||||
  # The following packages are okay to use:
 | 
			
		||||
  #
 | 
			
		||||
  # public API
 | 
			
		||||
  - selectorRegexp: ^k8s[.]io/(api|apimachinery|client-go|component-base|klog|pod-security-admission|utils)/|^[a-z]+(/|$)|github.com/onsi/(ginkgo|gomega)|^k8s[.]io/kubernetes/test/(e2e/framework/internal/|utils)
 | 
			
		||||
  - selectorRegexp: ^k8s[.]io/(api|apimachinery|client-go|component-base|klog|pod-security-admission|utils)
 | 
			
		||||
    allowedPrefixes: [ "" ]
 | 
			
		||||
 | 
			
		||||
  # stdlib
 | 
			
		||||
@@ -16,7 +16,7 @@ rules:
 | 
			
		||||
    allowedPrefixes: [ "" ]
 | 
			
		||||
 | 
			
		||||
  # Ginkgo + Gomega
 | 
			
		||||
  - selectorRegexp: github.com/onsi/(ginkgo|gomega)|^k8s[.]io/kubernetes/test/(e2e/framework/internal/|utils)
 | 
			
		||||
  - selectorRegexp: ^github.com/onsi/(ginkgo|gomega)
 | 
			
		||||
    allowedPrefixes: [ "" ]
 | 
			
		||||
 | 
			
		||||
  # kube-openapi
 | 
			
		||||
@@ -33,8 +33,10 @@ rules:
 | 
			
		||||
 | 
			
		||||
  # Third party deps
 | 
			
		||||
  - selectorRegexp: ^github.com/|^gopkg.in
 | 
			
		||||
    allowedPrefixes: [ 
 | 
			
		||||
    allowedPrefixes: [
 | 
			
		||||
      "gopkg.in/inf.v0",
 | 
			
		||||
      "gopkg.in/yaml.v2",
 | 
			
		||||
      "github.com/blang/semver/",
 | 
			
		||||
      "github.com/davecgh/go-spew/spew",
 | 
			
		||||
      "github.com/evanphx/json-patch",
 | 
			
		||||
      "github.com/go-logr/logr",
 | 
			
		||||
@@ -48,6 +50,10 @@ rules:
 | 
			
		||||
      "github.com/google/gofuzz",
 | 
			
		||||
      "github.com/google/uuid",
 | 
			
		||||
      "github.com/imdario/mergo",
 | 
			
		||||
      "github.com/prometheus/client_golang/",
 | 
			
		||||
      "github.com/prometheus/client_model/",
 | 
			
		||||
      "github.com/prometheus/common/",
 | 
			
		||||
      "github.com/prometheus/procfs",
 | 
			
		||||
      "github.com/spf13/cobra",
 | 
			
		||||
      "github.com/spf13/pflag",
 | 
			
		||||
      "github.com/stretchr/testify/assert",
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										108
									
								
								test/e2e/framework/bugs.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								test/e2e/framework/bugs.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,108 @@
 | 
			
		||||
/*
 | 
			
		||||
Copyright 2023 The Kubernetes Authors.
 | 
			
		||||
 | 
			
		||||
Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
you may not use this file except in compliance with the License.
 | 
			
		||||
You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
See the License for the specific language governing permissions and
 | 
			
		||||
limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
package framework
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"sort"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"sync"
 | 
			
		||||
 | 
			
		||||
	"github.com/onsi/ginkgo/v2/types"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	bugs     []Bug
 | 
			
		||||
	bugMutex sync.Mutex
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// RecordBug stores information about a bug in the E2E suite source code that
 | 
			
		||||
// cannot be reported through ginkgo.Fail because it was found outside of some
 | 
			
		||||
// test, for example during test registration.
 | 
			
		||||
//
 | 
			
		||||
// This can be used instead of raising a panic. Then all bugs can be reported
 | 
			
		||||
// together instead of failing after the first one.
 | 
			
		||||
func RecordBug(bug Bug) {
 | 
			
		||||
	bugMutex.Lock()
 | 
			
		||||
	defer bugMutex.Unlock()
 | 
			
		||||
 | 
			
		||||
	bugs = append(bugs, bug)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type Bug struct {
 | 
			
		||||
	FileName   string
 | 
			
		||||
	LineNumber int
 | 
			
		||||
	Message    string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewBug creates a new bug with a location that is obtained by skipping a certain number
 | 
			
		||||
// of stack frames. Passing zero will record the source code location of the direct caller
 | 
			
		||||
// of NewBug.
 | 
			
		||||
func NewBug(message string, skip int) Bug {
 | 
			
		||||
	location := types.NewCodeLocation(skip + 1)
 | 
			
		||||
	return Bug{FileName: location.FileName, LineNumber: location.LineNumber, Message: message}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// FormatBugs produces a report that includes all bugs recorded earlier via
 | 
			
		||||
// RecordBug. An error is returned with the report if there have been bugs.
 | 
			
		||||
func FormatBugs() error {
 | 
			
		||||
	bugMutex.Lock()
 | 
			
		||||
	defer bugMutex.Unlock()
 | 
			
		||||
 | 
			
		||||
	if len(bugs) == 0 {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	lines := make([]string, 0, len(bugs))
 | 
			
		||||
	wd, err := os.Getwd()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fmt.Errorf("get current directory: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	// Sort by file name, line number, message. For the sake of simplicity
 | 
			
		||||
	// this uses the full file name even though the output the may use a
 | 
			
		||||
	// relative path. Usually the result should be the same because full
 | 
			
		||||
	// paths will all have the same prefix.
 | 
			
		||||
	sort.Slice(bugs, func(i, j int) bool {
 | 
			
		||||
		switch strings.Compare(bugs[i].FileName, bugs[j].FileName) {
 | 
			
		||||
		case -1:
 | 
			
		||||
			return true
 | 
			
		||||
		case 1:
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
		if bugs[i].LineNumber < bugs[j].LineNumber {
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
		if bugs[i].LineNumber > bugs[j].LineNumber {
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
		return bugs[i].Message < bugs[j].Message
 | 
			
		||||
	})
 | 
			
		||||
	for _, bug := range bugs {
 | 
			
		||||
		// Use relative paths, if possible.
 | 
			
		||||
		path := bug.FileName
 | 
			
		||||
		if wd != "" {
 | 
			
		||||
			if relpath, err := filepath.Rel(wd, bug.FileName); err == nil {
 | 
			
		||||
				path = relpath
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		lines = append(lines, fmt.Sprintf("ERROR: %s:%d: %s\n", path, bug.LineNumber, strings.TrimSpace(bug.Message)))
 | 
			
		||||
	}
 | 
			
		||||
	return errors.New(strings.Join(lines, ""))
 | 
			
		||||
}
 | 
			
		||||
@@ -17,13 +17,72 @@ limitations under the License.
 | 
			
		||||
package framework
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"path"
 | 
			
		||||
	"reflect"
 | 
			
		||||
	"regexp"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"github.com/onsi/ginkgo/v2"
 | 
			
		||||
	"github.com/onsi/ginkgo/v2/types"
 | 
			
		||||
 | 
			
		||||
	apierrors "k8s.io/apimachinery/pkg/api/errors"
 | 
			
		||||
	"k8s.io/apimachinery/pkg/util/sets"
 | 
			
		||||
	utilfeature "k8s.io/apiserver/pkg/util/feature"
 | 
			
		||||
	"k8s.io/component-base/featuregate"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Feature is the name of a certain feature that the cluster under test must have.
 | 
			
		||||
// Such features are different from feature gates.
 | 
			
		||||
type Feature string
 | 
			
		||||
 | 
			
		||||
// Environment is the name for the environment in which a test can run, like
 | 
			
		||||
// "Linux" or "Windows".
 | 
			
		||||
type Environment string
 | 
			
		||||
 | 
			
		||||
// NodeFeature is the name of a feature that a node must support. To be
 | 
			
		||||
// removed, see
 | 
			
		||||
// https://github.com/kubernetes/enhancements/tree/master/keps/sig-testing/3041-node-conformance-and-features#nodefeature.
 | 
			
		||||
type NodeFeature string
 | 
			
		||||
 | 
			
		||||
type Valid[T comparable] struct {
 | 
			
		||||
	items  sets.Set[T]
 | 
			
		||||
	frozen bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Add registers a new valid item name. The expected usage is
 | 
			
		||||
//
 | 
			
		||||
//	var SomeFeature = framework.ValidFeatures.Add("Some")
 | 
			
		||||
//
 | 
			
		||||
// during the init phase of an E2E suite. Individual tests should not register
 | 
			
		||||
// their own, to avoid uncontrolled proliferation of new items. E2E suites can,
 | 
			
		||||
// but don't have to, enforce that by freezing the set of valid names.
 | 
			
		||||
func (v *Valid[T]) Add(item T) T {
 | 
			
		||||
	if v.frozen {
 | 
			
		||||
		RecordBug(NewBug(fmt.Sprintf(`registry %T is already frozen, "%v" must not be added anymore`, *v, item), 1))
 | 
			
		||||
	}
 | 
			
		||||
	if v.items == nil {
 | 
			
		||||
		v.items = sets.New[T]()
 | 
			
		||||
	}
 | 
			
		||||
	if v.items.Has(item) {
 | 
			
		||||
		RecordBug(NewBug(fmt.Sprintf(`registry %T already contains "%v", it must not be added again`, *v, item), 1))
 | 
			
		||||
	}
 | 
			
		||||
	v.items.Insert(item)
 | 
			
		||||
	return item
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (v *Valid[T]) Freeze() {
 | 
			
		||||
	v.frozen = true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// These variables contain the parameters that [WithFeature], [WithEnvironment]
 | 
			
		||||
// and [WithNodeFeatures] accept. The framework itself has no pre-defined
 | 
			
		||||
// constants. Test suites and tests may define their own and then add them here
 | 
			
		||||
// before calling these With functions.
 | 
			
		||||
var (
 | 
			
		||||
	ValidFeatures     Valid[Feature]
 | 
			
		||||
	ValidEnvironments Valid[Environment]
 | 
			
		||||
	ValidNodeFeatures Valid[NodeFeature]
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var errInterface = reflect.TypeOf((*error)(nil)).Elem()
 | 
			
		||||
@@ -65,8 +124,344 @@ func AnnotatedLocationWithOffset(annotation string, offset int) types.CodeLocati
 | 
			
		||||
	return codeLocation
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SIGDescribe returns a wrapper function for ginkgo.Describe which injects
 | 
			
		||||
// the SIG name as annotation. The parameter should be lowercase with
 | 
			
		||||
// no spaces and no sig- or SIG- prefix.
 | 
			
		||||
func SIGDescribe(sig string) func(string, ...interface{}) bool {
 | 
			
		||||
	if !sigRE.MatchString(sig) || strings.HasPrefix(sig, "sig-") {
 | 
			
		||||
		panic(fmt.Sprintf("SIG label must be lowercase, no spaces and no sig- prefix, got instead: %q", sig))
 | 
			
		||||
	}
 | 
			
		||||
	return func(text string, args ...interface{}) bool {
 | 
			
		||||
		args = append(args, ginkgo.Label("sig-"+sig))
 | 
			
		||||
		if text == "" {
 | 
			
		||||
			text = fmt.Sprintf("[sig-%s]", sig)
 | 
			
		||||
		} else {
 | 
			
		||||
			text = fmt.Sprintf("[sig-%s] %s", sig, text)
 | 
			
		||||
		}
 | 
			
		||||
		return registerInSuite(ginkgo.Describe, text, args)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var sigRE = regexp.MustCompile(`^[a-z]+(-[a-z]+)*$`)
 | 
			
		||||
 | 
			
		||||
// ConformanceIt is wrapper function for ginkgo It.  Adds "[Conformance]" tag and makes static analysis easier.
 | 
			
		||||
func ConformanceIt(text string, args ...interface{}) bool {
 | 
			
		||||
	args = append(args, ginkgo.Offset(1))
 | 
			
		||||
	return ginkgo.It(text+" [Conformance]", args...)
 | 
			
		||||
	args = append(args, ginkgo.Offset(1), WithConformance())
 | 
			
		||||
	return It(text, args...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// It is a wrapper around [ginkgo.It] which supports framework With* labels as
 | 
			
		||||
// optional arguments in addition to those already supported by ginkgo itself,
 | 
			
		||||
// like [ginkgo.Label] and [gingko.Offset].
 | 
			
		||||
//
 | 
			
		||||
// Text and arguments may be mixed. The final text is a concatenation
 | 
			
		||||
// of the text arguments and special tags from the With functions.
 | 
			
		||||
func It(text string, args ...interface{}) bool {
 | 
			
		||||
	return registerInSuite(ginkgo.It, text, args)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// It is a shorthand for the corresponding package function.
 | 
			
		||||
func (f *Framework) It(text string, args ...interface{}) bool {
 | 
			
		||||
	return registerInSuite(ginkgo.It, text, args)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Describe is a wrapper around [ginkgo.Describe] which supports framework
 | 
			
		||||
// With* labels as optional arguments in addition to those already supported by
 | 
			
		||||
// ginkgo itself, like [ginkgo.Label] and [gingko.Offset].
 | 
			
		||||
//
 | 
			
		||||
// Text and arguments may be mixed. The final text is a concatenation
 | 
			
		||||
// of the text arguments and special tags from the With functions.
 | 
			
		||||
func Describe(text string, args ...interface{}) bool {
 | 
			
		||||
	return registerInSuite(ginkgo.Describe, text, args)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Describe is a shorthand for the corresponding package function.
 | 
			
		||||
func (f *Framework) Describe(text string, args ...interface{}) bool {
 | 
			
		||||
	return registerInSuite(ginkgo.Describe, text, args)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Context is a wrapper around [ginkgo.Context] which supports framework With*
 | 
			
		||||
// labels as optional arguments in addition to those already supported by
 | 
			
		||||
// ginkgo itself, like [ginkgo.Label] and [gingko.Offset].
 | 
			
		||||
//
 | 
			
		||||
// Text and arguments may be mixed. The final text is a concatenation
 | 
			
		||||
// of the text arguments and special tags from the With functions.
 | 
			
		||||
func Context(text string, args ...interface{}) bool {
 | 
			
		||||
	return registerInSuite(ginkgo.Context, text, args)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Context is a shorthand for the corresponding package function.
 | 
			
		||||
func (f *Framework) Context(text string, args ...interface{}) bool {
 | 
			
		||||
	return registerInSuite(ginkgo.Context, text, args)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// registerInSuite is the common implementation of all wrapper functions. It
 | 
			
		||||
// expects to be called through one intermediate wrapper.
 | 
			
		||||
func registerInSuite(ginkgoCall func(text string, args ...interface{}) bool, text string, args []interface{}) bool {
 | 
			
		||||
	var ginkgoArgs []interface{}
 | 
			
		||||
	var offset ginkgo.Offset
 | 
			
		||||
	var texts []string
 | 
			
		||||
	if text != "" {
 | 
			
		||||
		texts = append(texts, text)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	addLabel := func(label string) {
 | 
			
		||||
		texts = append(texts, fmt.Sprintf("[%s]", label))
 | 
			
		||||
		ginkgoArgs = append(ginkgoArgs, ginkgo.Label(label))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	haveEmptyStrings := false
 | 
			
		||||
	for _, arg := range args {
 | 
			
		||||
		switch arg := arg.(type) {
 | 
			
		||||
		case label:
 | 
			
		||||
			fullLabel := strings.Join(arg.parts, ": ")
 | 
			
		||||
			addLabel(fullLabel)
 | 
			
		||||
			if arg.extra != "" {
 | 
			
		||||
				addLabel(arg.extra)
 | 
			
		||||
			}
 | 
			
		||||
			if fullLabel == "Serial" {
 | 
			
		||||
				ginkgoArgs = append(ginkgoArgs, ginkgo.Serial)
 | 
			
		||||
			}
 | 
			
		||||
		case ginkgo.Offset:
 | 
			
		||||
			offset = arg
 | 
			
		||||
		case string:
 | 
			
		||||
			if arg == "" {
 | 
			
		||||
				haveEmptyStrings = true
 | 
			
		||||
			}
 | 
			
		||||
			texts = append(texts, arg)
 | 
			
		||||
		default:
 | 
			
		||||
			ginkgoArgs = append(ginkgoArgs, arg)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	offset += 2 // This function and its direct caller.
 | 
			
		||||
 | 
			
		||||
	// Now that we have the final offset, we can record bugs.
 | 
			
		||||
	if haveEmptyStrings {
 | 
			
		||||
		RecordBug(NewBug("empty strings as separators are unnecessary and need to be removed", int(offset)))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Enforce that text snippets to not start or end with spaces because
 | 
			
		||||
	// those lead to double spaces when concatenating below.
 | 
			
		||||
	for _, text := range texts {
 | 
			
		||||
		if strings.HasPrefix(text, " ") || strings.HasSuffix(text, " ") {
 | 
			
		||||
			RecordBug(NewBug(fmt.Sprintf("trailing or leading spaces are unnecessary and need to be removed: %q", text), int(offset)))
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ginkgoArgs = append(ginkgoArgs, offset)
 | 
			
		||||
	text = strings.Join(texts, " ")
 | 
			
		||||
	return ginkgoCall(text, ginkgoArgs...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// WithEnvironment specifies that a certain test or group of tests only works
 | 
			
		||||
// with a feature available. The return value must be passed as additional
 | 
			
		||||
// argument to [framework.It], [framework.Describe], [framework.Context].
 | 
			
		||||
//
 | 
			
		||||
// The feature must be listed in ValidFeatures.
 | 
			
		||||
func WithFeature(name Feature) interface{} {
 | 
			
		||||
	return withFeature(name)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// WithFeature is a shorthand for the corresponding package function.
 | 
			
		||||
func (f *Framework) WithFeature(name Feature) interface{} {
 | 
			
		||||
	return withFeature(name)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func withFeature(name Feature) interface{} {
 | 
			
		||||
	if !ValidFeatures.items.Has(name) {
 | 
			
		||||
		RecordBug(NewBug(fmt.Sprintf("WithFeature: unknown feature %q", name), 2))
 | 
			
		||||
	}
 | 
			
		||||
	return newLabel("Feature", string(name))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// WithFeatureGate specifies that a certain test or group of tests depends on a
 | 
			
		||||
// feature gate being enabled. The return value must be passed as additional
 | 
			
		||||
// argument to [framework.It], [framework.Describe], [framework.Context].
 | 
			
		||||
//
 | 
			
		||||
// The feature gate must be listed in
 | 
			
		||||
// [k8s.io/apiserver/pkg/util/feature.DefaultMutableFeatureGate]. Once a
 | 
			
		||||
// feature gate gets removed from there, the WithFeatureGate calls using it
 | 
			
		||||
// also need to be removed.
 | 
			
		||||
func WithFeatureGate(featureGate featuregate.Feature) interface{} {
 | 
			
		||||
	return withFeatureGate(featureGate)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// WithFeatureGate is a shorthand for the corresponding package function.
 | 
			
		||||
func (f *Framework) WithFeatureGate(featureGate featuregate.Feature) interface{} {
 | 
			
		||||
	return withFeatureGate(featureGate)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func withFeatureGate(featureGate featuregate.Feature) interface{} {
 | 
			
		||||
	spec, ok := utilfeature.DefaultMutableFeatureGate.GetAll()[featureGate]
 | 
			
		||||
	if !ok {
 | 
			
		||||
		RecordBug(NewBug(fmt.Sprintf("WithFeatureGate: the feature gate %q is unknown", featureGate), 2))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// We use mixed case (i.e. Beta instead of BETA). GA feature gates have no level string.
 | 
			
		||||
	var level string
 | 
			
		||||
	if spec.PreRelease != "" {
 | 
			
		||||
		level = string(spec.PreRelease)
 | 
			
		||||
		level = strings.ToUpper(level[0:1]) + strings.ToLower(level[1:])
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	l := newLabel("FeatureGate", string(featureGate))
 | 
			
		||||
	l.extra = level
 | 
			
		||||
	return l
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// WithEnvironment specifies that a certain test or group of tests only works
 | 
			
		||||
// in a certain environment. The return value must be passed as additional
 | 
			
		||||
// argument to [framework.It], [framework.Describe], [framework.Context].
 | 
			
		||||
//
 | 
			
		||||
// The environment must be listed in ValidEnvironments.
 | 
			
		||||
func WithEnvironment(name Environment) interface{} {
 | 
			
		||||
	return withEnvironment(name)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// WithEnvironment is a shorthand for the corresponding package function.
 | 
			
		||||
func (f *Framework) WithEnvironment(name Environment) interface{} {
 | 
			
		||||
	return withEnvironment(name)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func withEnvironment(name Environment) interface{} {
 | 
			
		||||
	if !ValidEnvironments.items.Has(name) {
 | 
			
		||||
		RecordBug(NewBug(fmt.Sprintf("WithEnvironment: unknown environment %q", name), 2))
 | 
			
		||||
	}
 | 
			
		||||
	return newLabel("Environment", string(name))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// WithNodeFeature specifies that a certain test or group of tests only works
 | 
			
		||||
// if the node supports a certain feature. The return value must be passed as
 | 
			
		||||
// additional argument to [framework.It], [framework.Describe],
 | 
			
		||||
// [framework.Context].
 | 
			
		||||
//
 | 
			
		||||
// The environment must be listed in ValidNodeFeatures.
 | 
			
		||||
func WithNodeFeature(name NodeFeature) interface{} {
 | 
			
		||||
	return withNodeFeature(name)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// WithNodeFeature is a shorthand for the corresponding package function.
 | 
			
		||||
func (f *Framework) WithNodeFeature(name NodeFeature) interface{} {
 | 
			
		||||
	return withNodeFeature(name)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func withNodeFeature(name NodeFeature) interface{} {
 | 
			
		||||
	if !ValidNodeFeatures.items.Has(name) {
 | 
			
		||||
		RecordBug(NewBug(fmt.Sprintf("WithNodeFeature: unknown environment %q", name), 2))
 | 
			
		||||
	}
 | 
			
		||||
	return newLabel(string(name))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// WithConformace specifies that a certain test or group of tests must pass in
 | 
			
		||||
// all conformant Kubernetes clusters. The return value must be passed as
 | 
			
		||||
// additional argument to [framework.It], [framework.Describe],
 | 
			
		||||
// [framework.Context].
 | 
			
		||||
func WithConformance() interface{} {
 | 
			
		||||
	return withConformance()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// WithConformance is a shorthand for the corresponding package function.
 | 
			
		||||
func (f *Framework) WithConformance() interface{} {
 | 
			
		||||
	return withConformance()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func withConformance() interface{} {
 | 
			
		||||
	return newLabel("Conformance")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// WithNodeConformance specifies that a certain test or group of tests for node
 | 
			
		||||
// functionality that does not depend on runtime or Kubernetes distro specific
 | 
			
		||||
// behavior. The return value must be passed as additional argument to
 | 
			
		||||
// [framework.It], [framework.Describe], [framework.Context].
 | 
			
		||||
func WithNodeConformance() interface{} {
 | 
			
		||||
	return withNodeConformance()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// WithNodeConformance is a shorthand for the corresponding package function.
 | 
			
		||||
func (f *Framework) WithNodeConformance() interface{} {
 | 
			
		||||
	return withNodeConformance()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func withNodeConformance() interface{} {
 | 
			
		||||
	return newLabel("NodeConformance")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// WithDisruptive specifies that a certain test or group of tests temporarily
 | 
			
		||||
// affects the functionality of the Kubernetes cluster. The return value must
 | 
			
		||||
// be passed as additional argument to [framework.It], [framework.Describe],
 | 
			
		||||
// [framework.Context].
 | 
			
		||||
func WithDisruptive() interface{} {
 | 
			
		||||
	return withDisruptive()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// WithDisruptive is a shorthand for the corresponding package function.
 | 
			
		||||
func (f *Framework) WithDisruptive() interface{} {
 | 
			
		||||
	return withDisruptive()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func withDisruptive() interface{} {
 | 
			
		||||
	return newLabel("Disruptive")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// WithSerial specifies that a certain test or group of tests must not run in
 | 
			
		||||
// parallel with other tests. The return value must be passed as additional
 | 
			
		||||
// argument to [framework.It], [framework.Describe], [framework.Context].
 | 
			
		||||
//
 | 
			
		||||
// Starting with ginkgo v2, serial and parallel tests can be executed in the
 | 
			
		||||
// same invocation. Ginkgo itself will ensure that the serial tests run
 | 
			
		||||
// sequentially.
 | 
			
		||||
func WithSerial() interface{} {
 | 
			
		||||
	return withSerial()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// WithSerial is a shorthand for the corresponding package function.
 | 
			
		||||
func (f *Framework) WithSerial() interface{} {
 | 
			
		||||
	return withSerial()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func withSerial() interface{} {
 | 
			
		||||
	return newLabel("Serial")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// WithSlow specifies that a certain test or group of tests must not run in
 | 
			
		||||
// parallel with other tests. The return value must be passed as additional
 | 
			
		||||
// argument to [framework.It], [framework.Describe], [framework.Context].
 | 
			
		||||
func WithSlow() interface{} {
 | 
			
		||||
	return withSlow()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// WithSlow is a shorthand for the corresponding package function.
 | 
			
		||||
func (f *Framework) WithSlow() interface{} {
 | 
			
		||||
	return WithSlow()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func withSlow() interface{} {
 | 
			
		||||
	return newLabel("Slow")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// WithLabel is a wrapper around [ginkgo.Label]. Besides adding an arbitrary
 | 
			
		||||
// label to a test, it also injects the label in square brackets into the test
 | 
			
		||||
// name.
 | 
			
		||||
func WithLabel(label string) interface{} {
 | 
			
		||||
	return withLabel(label)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// WithLabel is a shorthand for the corresponding package function.
 | 
			
		||||
func (f *Framework) WithLabel(label string) interface{} {
 | 
			
		||||
	return withLabel(label)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func withLabel(label string) interface{} {
 | 
			
		||||
	return newLabel(label)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type label struct {
 | 
			
		||||
	// parts get concatenated with ": " to build the full label.
 | 
			
		||||
	parts []string
 | 
			
		||||
	// extra is an optional fully-formed extra label.
 | 
			
		||||
	extra string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newLabel(parts ...string) label {
 | 
			
		||||
	return label{parts: parts}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										168
									
								
								test/e2e/framework/internal/unittests/bugs/bugs.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										168
									
								
								test/e2e/framework/internal/unittests/bugs/bugs.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,168 @@
 | 
			
		||||
/*
 | 
			
		||||
Copyright 2023 The Kubernetes Authors.
 | 
			
		||||
 | 
			
		||||
Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
you may not use this file except in compliance with the License.
 | 
			
		||||
You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
See the License for the specific language governing permissions and
 | 
			
		||||
limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
package bugs
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"github.com/onsi/ginkgo/v2"
 | 
			
		||||
	"k8s.io/kubernetes/test/e2e/framework"
 | 
			
		||||
	"k8s.io/kubernetes/test/e2e/framework/internal/unittests/bugs/features"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// The line number of the following code is checked in BugOutput below.
 | 
			
		||||
// Be careful when moving it around or changing the import statements above.
 | 
			
		||||
// Here are some intentionally blank lines that can be removed to compensate
 | 
			
		||||
// for future additional import statements.
 | 
			
		||||
//
 | 
			
		||||
//
 | 
			
		||||
//
 | 
			
		||||
//
 | 
			
		||||
//
 | 
			
		||||
//
 | 
			
		||||
//
 | 
			
		||||
//
 | 
			
		||||
//
 | 
			
		||||
//
 | 
			
		||||
//
 | 
			
		||||
//
 | 
			
		||||
//
 | 
			
		||||
//
 | 
			
		||||
//
 | 
			
		||||
//
 | 
			
		||||
//
 | 
			
		||||
//
 | 
			
		||||
// This must be line #50.
 | 
			
		||||
 | 
			
		||||
func helper() {
 | 
			
		||||
	framework.RecordBug(framework.NewBug("new bug", 0))
 | 
			
		||||
	framework.RecordBug(framework.NewBug("parent", 1))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func RecordBugs() {
 | 
			
		||||
	helper()
 | 
			
		||||
	framework.RecordBug(framework.Bug{FileName: "buggy/buggy.go", LineNumber: 100, Message: "hello world"})
 | 
			
		||||
	framework.RecordBug(framework.Bug{FileName: "some/relative/path/buggy.go", LineNumber: 200, Message: "    with spaces    \n"})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	validFeature     = framework.ValidFeatures.Add("feature-foo")
 | 
			
		||||
	validEnvironment = framework.ValidEnvironments.Add("Linux")
 | 
			
		||||
	validNodeFeature = framework.ValidNodeFeatures.Add("node-feature-foo")
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func Describe() {
 | 
			
		||||
	// Normally a single line would be better, but this is an extreme example and
 | 
			
		||||
	// thus uses multiple.
 | 
			
		||||
	framework.SIGDescribe("testing")("abc",
 | 
			
		||||
		// Bugs in parameters will be attributed to the Describe call, not the line of the parameter.
 | 
			
		||||
		"",        // buggy: not needed
 | 
			
		||||
		" space1", // buggy: leading white space
 | 
			
		||||
		"space2 ", // buggy: trailing white space
 | 
			
		||||
		framework.WithFeature("no-such-feature"),
 | 
			
		||||
		framework.WithFeature(validFeature),
 | 
			
		||||
		framework.WithEnvironment("no-such-env"),
 | 
			
		||||
		framework.WithEnvironment(validEnvironment),
 | 
			
		||||
		framework.WithNodeFeature("no-such-node-env"),
 | 
			
		||||
		framework.WithNodeFeature(validNodeFeature),
 | 
			
		||||
		framework.WithFeatureGate("no-such-feature-gate"),
 | 
			
		||||
		framework.WithFeatureGate(features.Alpha),
 | 
			
		||||
		framework.WithFeatureGate(features.Beta),
 | 
			
		||||
		framework.WithFeatureGate(features.GA),
 | 
			
		||||
		framework.WithConformance(),
 | 
			
		||||
		framework.WithNodeConformance(),
 | 
			
		||||
		framework.WithSlow(),
 | 
			
		||||
		framework.WithSerial(),
 | 
			
		||||
		framework.WithDisruptive(),
 | 
			
		||||
		framework.WithLabel("custom-label"),
 | 
			
		||||
		"xyz", // okay, becomes part of the final text
 | 
			
		||||
		func() {
 | 
			
		||||
			f := framework.NewDefaultFramework("abc")
 | 
			
		||||
 | 
			
		||||
			framework.Context("y", framework.WithLabel("foo"), func() {
 | 
			
		||||
				framework.It("should", f.WithLabel("bar"), func() {
 | 
			
		||||
				})
 | 
			
		||||
			})
 | 
			
		||||
 | 
			
		||||
			f.Context("x", f.WithLabel("foo"), func() {
 | 
			
		||||
				f.It("should", f.WithLabel("bar"), func() {
 | 
			
		||||
				})
 | 
			
		||||
			})
 | 
			
		||||
		},
 | 
			
		||||
	)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	numBugs   = 3
 | 
			
		||||
	bugOutput = `ERROR: bugs.go:53: new bug
 | 
			
		||||
ERROR: bugs.go:58: parent
 | 
			
		||||
ERROR: bugs.go:72: empty strings as separators are unnecessary and need to be removed
 | 
			
		||||
ERROR: bugs.go:72: trailing or leading spaces are unnecessary and need to be removed: " space1"
 | 
			
		||||
ERROR: bugs.go:72: trailing or leading spaces are unnecessary and need to be removed: "space2 "
 | 
			
		||||
ERROR: bugs.go:77: WithFeature: unknown feature "no-such-feature"
 | 
			
		||||
ERROR: bugs.go:79: WithEnvironment: unknown environment "no-such-env"
 | 
			
		||||
ERROR: bugs.go:81: WithNodeFeature: unknown environment "no-such-node-env"
 | 
			
		||||
ERROR: bugs.go:83: WithFeatureGate: the feature gate "no-such-feature-gate" is unknown
 | 
			
		||||
ERROR: buggy/buggy.go:100: hello world
 | 
			
		||||
ERROR: some/relative/path/buggy.go:200: with spaces
 | 
			
		||||
`
 | 
			
		||||
	// Used by unittests/list-tests. It's sorted by test name, not source code location.
 | 
			
		||||
	ListTestsOutput = `The following spec names can be used with 'ginkgo run --focus/skip':
 | 
			
		||||
    ../bugs/bugs.go:103: [sig-testing] abc   space1 space2  [Feature: no-such-feature] [Feature: feature-foo] [Environment: no-such-env] [Environment: Linux] [no-such-node-env] [node-feature-foo] [FeatureGate: no-such-feature-gate] [FeatureGate: TestAlphaFeature] [Alpha] [FeatureGate: TestBetaFeature] [Beta] [FeatureGate: TestGAFeature] [Conformance] [NodeConformance] [Slow] [Serial] [Disruptive] [custom-label] xyz x [foo] should [bar]
 | 
			
		||||
    ../bugs/bugs.go:98: [sig-testing] abc   space1 space2  [Feature: no-such-feature] [Feature: feature-foo] [Environment: no-such-env] [Environment: Linux] [no-such-node-env] [node-feature-foo] [FeatureGate: no-such-feature-gate] [FeatureGate: TestAlphaFeature] [Alpha] [FeatureGate: TestBetaFeature] [Beta] [FeatureGate: TestGAFeature] [Conformance] [NodeConformance] [Slow] [Serial] [Disruptive] [custom-label] xyz y [foo] should [bar]
 | 
			
		||||
 | 
			
		||||
`
 | 
			
		||||
 | 
			
		||||
	// Used by unittests/list-labels.
 | 
			
		||||
	ListLabelsOutput = `The following labels can be used with 'gingko run --label-filter':
 | 
			
		||||
    Alpha
 | 
			
		||||
    Beta
 | 
			
		||||
    Conformance
 | 
			
		||||
    Disruptive
 | 
			
		||||
    Environment: Linux
 | 
			
		||||
    Environment: no-such-env
 | 
			
		||||
    Feature: feature-foo
 | 
			
		||||
    Feature: no-such-feature
 | 
			
		||||
    FeatureGate: TestAlphaFeature
 | 
			
		||||
    FeatureGate: TestBetaFeature
 | 
			
		||||
    FeatureGate: TestGAFeature
 | 
			
		||||
    FeatureGate: no-such-feature-gate
 | 
			
		||||
    NodeConformance
 | 
			
		||||
    Serial
 | 
			
		||||
    Slow
 | 
			
		||||
    bar
 | 
			
		||||
    custom-label
 | 
			
		||||
    foo
 | 
			
		||||
    no-such-node-env
 | 
			
		||||
    node-feature-foo
 | 
			
		||||
    sig-testing
 | 
			
		||||
 | 
			
		||||
`
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func GetGinkgoOutput(t *testing.T) string {
 | 
			
		||||
	var buffer bytes.Buffer
 | 
			
		||||
	ginkgo.GinkgoWriter.TeeTo(&buffer)
 | 
			
		||||
	t.Cleanup(ginkgo.GinkgoWriter.ClearTeeWriters)
 | 
			
		||||
 | 
			
		||||
	suiteConfig, reporterConfig := framework.CreateGinkgoConfig()
 | 
			
		||||
	fakeT := &testing.T{}
 | 
			
		||||
	ginkgo.RunSpecs(fakeT, "Buggy Suite", suiteConfig, reporterConfig)
 | 
			
		||||
 | 
			
		||||
	return buffer.String()
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										41
									
								
								test/e2e/framework/internal/unittests/bugs/bugs_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								test/e2e/framework/internal/unittests/bugs/bugs_test.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,41 @@
 | 
			
		||||
/*
 | 
			
		||||
Copyright 2023 The Kubernetes Authors.
 | 
			
		||||
 | 
			
		||||
Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
you may not use this file except in compliance with the License.
 | 
			
		||||
You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
See the License for the specific language governing permissions and
 | 
			
		||||
limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
package bugs
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"github.com/stretchr/testify/assert"
 | 
			
		||||
	"github.com/stretchr/testify/require"
 | 
			
		||||
 | 
			
		||||
	"k8s.io/kubernetes/test/e2e/framework"
 | 
			
		||||
	"k8s.io/kubernetes/test/e2e/framework/internal/unittests"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestBugs(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, framework.FormatBugs())
 | 
			
		||||
	RecordBugs()
 | 
			
		||||
	Describe()
 | 
			
		||||
 | 
			
		||||
	err := framework.FormatBugs()
 | 
			
		||||
	require.Error(t, err)
 | 
			
		||||
	require.Equal(t, bugOutput, err.Error())
 | 
			
		||||
 | 
			
		||||
	output, code := unittests.GetFrameworkOutput(t, nil)
 | 
			
		||||
	assert.Equal(t, 1, code)
 | 
			
		||||
	assert.Equal(t, "ERROR: E2E suite initialization was faulty, these errors must be fixed:\n"+bugOutput, output)
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,39 @@
 | 
			
		||||
/*
 | 
			
		||||
Copyright 2023 The Kubernetes Authors.
 | 
			
		||||
 | 
			
		||||
Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
you may not use this file except in compliance with the License.
 | 
			
		||||
You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
See the License for the specific language governing permissions and
 | 
			
		||||
limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
package features
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"k8s.io/apimachinery/pkg/util/runtime"
 | 
			
		||||
	utilfeature "k8s.io/apiserver/pkg/util/feature"
 | 
			
		||||
	"k8s.io/component-base/featuregate"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	Alpha featuregate.Feature = "TestAlphaFeature"
 | 
			
		||||
	Beta  featuregate.Feature = "TestBetaFeature"
 | 
			
		||||
	GA    featuregate.Feature = "TestGAFeature"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
	runtime.Must(utilfeature.DefaultMutableFeatureGate.Add(testFeatureGates))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var testFeatureGates = map[featuregate.Feature]featuregate.FeatureSpec{
 | 
			
		||||
	Alpha: {PreRelease: featuregate.Alpha},
 | 
			
		||||
	Beta:  {PreRelease: featuregate.Beta},
 | 
			
		||||
	GA:    {PreRelease: featuregate.GA},
 | 
			
		||||
}
 | 
			
		||||
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
 | 
			
		||||
limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
package framework_test
 | 
			
		||||
package unittests_test
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"reflect"
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										61
									
								
								test/e2e/framework/internal/unittests/helpers.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								test/e2e/framework/internal/unittests/helpers.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,61 @@
 | 
			
		||||
/*
 | 
			
		||||
Copyright 2023 The Kubernetes Authors.
 | 
			
		||||
 | 
			
		||||
Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
you may not use this file except in compliance with the License.
 | 
			
		||||
You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
See the License for the specific language governing permissions and
 | 
			
		||||
limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
package unittests
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"flag"
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"github.com/stretchr/testify/require"
 | 
			
		||||
	"k8s.io/kubernetes/test/e2e/framework"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// GetFrameworkOutput captures writes to framework.Output during a test suite setup
 | 
			
		||||
// and returns it together with any explicit Exit call code, -1 if none.
 | 
			
		||||
// May only be called once per test binary.
 | 
			
		||||
func GetFrameworkOutput(t *testing.T, flags map[string]string) (output string, finalExitCode int) {
 | 
			
		||||
	// This simulates how test/e2e uses the framework and how users
 | 
			
		||||
	// invoke test/e2e.
 | 
			
		||||
	framework.RegisterCommonFlags(flag.CommandLine)
 | 
			
		||||
	framework.RegisterClusterFlags(flag.CommandLine)
 | 
			
		||||
	for flagname, value := range flags {
 | 
			
		||||
		require.NoError(t, flag.Set(flagname, value), "set %s", flagname)
 | 
			
		||||
	}
 | 
			
		||||
	var buffer bytes.Buffer
 | 
			
		||||
	framework.Output = &buffer
 | 
			
		||||
	framework.Exit = func(code int) {
 | 
			
		||||
		panic(exitCode(code))
 | 
			
		||||
	}
 | 
			
		||||
	finalExitCode = -1
 | 
			
		||||
	defer func() {
 | 
			
		||||
		if r := recover(); r != nil {
 | 
			
		||||
			if code, ok := r.(exitCode); ok {
 | 
			
		||||
				finalExitCode = int(code)
 | 
			
		||||
			} else {
 | 
			
		||||
				panic(r)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		output = buffer.String()
 | 
			
		||||
	}()
 | 
			
		||||
	framework.AfterReadingAllFlags(&framework.TestContext)
 | 
			
		||||
 | 
			
		||||
	// Results set by defer.
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type exitCode int
 | 
			
		||||
@@ -0,0 +1,35 @@
 | 
			
		||||
/*
 | 
			
		||||
Copyright 2023 The Kubernetes Authors.
 | 
			
		||||
 | 
			
		||||
Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
you may not use this file except in compliance with the License.
 | 
			
		||||
You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
See the License for the specific language governing permissions and
 | 
			
		||||
limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
package listlabels
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"github.com/stretchr/testify/assert"
 | 
			
		||||
 | 
			
		||||
	"k8s.io/kubernetes/test/e2e/framework"
 | 
			
		||||
	"k8s.io/kubernetes/test/e2e/framework/internal/unittests"
 | 
			
		||||
	"k8s.io/kubernetes/test/e2e/framework/internal/unittests/bugs"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestListTests(t *testing.T) {
 | 
			
		||||
	bugs.Describe()
 | 
			
		||||
	framework.CheckForBugs = false
 | 
			
		||||
	output, code := unittests.GetFrameworkOutput(t, map[string]string{"list-labels": "true"})
 | 
			
		||||
	assert.Equal(t, 0, code)
 | 
			
		||||
	assert.Equal(t, bugs.ListLabelsOutput, output)
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,35 @@
 | 
			
		||||
/*
 | 
			
		||||
Copyright 2023 The Kubernetes Authors.
 | 
			
		||||
 | 
			
		||||
Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
you may not use this file except in compliance with the License.
 | 
			
		||||
You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
See the License for the specific language governing permissions and
 | 
			
		||||
limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
package listtests
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"github.com/stretchr/testify/assert"
 | 
			
		||||
 | 
			
		||||
	"k8s.io/kubernetes/test/e2e/framework"
 | 
			
		||||
	"k8s.io/kubernetes/test/e2e/framework/internal/unittests"
 | 
			
		||||
	"k8s.io/kubernetes/test/e2e/framework/internal/unittests/bugs"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestListTests(t *testing.T) {
 | 
			
		||||
	bugs.Describe()
 | 
			
		||||
	framework.CheckForBugs = false
 | 
			
		||||
	output, code := unittests.GetFrameworkOutput(t, map[string]string{"list-tests": "true"})
 | 
			
		||||
	assert.Equal(t, 0, code)
 | 
			
		||||
	assert.Equal(t, bugs.ListTestsOutput, output)
 | 
			
		||||
}
 | 
			
		||||
@@ -23,9 +23,11 @@ import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"flag"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
	"math"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"sort"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
@@ -36,6 +38,7 @@ import (
 | 
			
		||||
	"github.com/onsi/gomega"
 | 
			
		||||
	gomegaformat "github.com/onsi/gomega/format"
 | 
			
		||||
 | 
			
		||||
	"k8s.io/apimachinery/pkg/util/sets"
 | 
			
		||||
	restclient "k8s.io/client-go/rest"
 | 
			
		||||
	"k8s.io/client-go/tools/clientcmd"
 | 
			
		||||
	cliflag "k8s.io/component-base/cli/flag"
 | 
			
		||||
@@ -53,6 +56,20 @@ const (
 | 
			
		||||
	DefaultNumNodes = -1
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	// Output is used for output when not running tests, for example in -list-tests.
 | 
			
		||||
	// Test output should go to ginkgo.GinkgoWriter.
 | 
			
		||||
	Output io.Writer = os.Stdout
 | 
			
		||||
 | 
			
		||||
	// Exit is called when the framework detects fatal errors or when
 | 
			
		||||
	// it is done with the execution of e.g. -list-tests.
 | 
			
		||||
	Exit = os.Exit
 | 
			
		||||
 | 
			
		||||
	// CheckForBugs determines whether the framework bails out when
 | 
			
		||||
	// test initialization found any bugs.
 | 
			
		||||
	CheckForBugs = true
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// TestContextType contains test settings and global state. Due to
 | 
			
		||||
// historic reasons, it is a mixture of items managed by the test
 | 
			
		||||
// framework itself, cloud providers and individual tests.
 | 
			
		||||
@@ -94,6 +111,8 @@ type TestContextType struct {
 | 
			
		||||
	// ListImages will list off all images that are used then quit
 | 
			
		||||
	ListImages bool
 | 
			
		||||
 | 
			
		||||
	listTests, listLabels bool
 | 
			
		||||
 | 
			
		||||
	// ListConformanceTests will list off all conformance tests that are available then quit
 | 
			
		||||
	ListConformanceTests bool
 | 
			
		||||
 | 
			
		||||
@@ -356,6 +375,8 @@ func RegisterCommonFlags(flags *flag.FlagSet) {
 | 
			
		||||
	flags.StringVar(&TestContext.NonblockingTaints, "non-blocking-taints", `node-role.kubernetes.io/control-plane`, "Nodes with taints in this comma-delimited list will not block the test framework from starting tests.")
 | 
			
		||||
 | 
			
		||||
	flags.BoolVar(&TestContext.ListImages, "list-images", false, "If true, will show list of images used for running tests.")
 | 
			
		||||
	flags.BoolVar(&TestContext.listLabels, "list-labels", false, "If true, will show the list of labels that can be used to select tests via -ginkgo.label-filter.")
 | 
			
		||||
	flags.BoolVar(&TestContext.listTests, "list-tests", false, "If true, will show the full names of all tests (aka specs) that can be used to select test via -ginkgo.focus/skip.")
 | 
			
		||||
	flags.StringVar(&TestContext.KubectlPath, "kubectl-path", "kubectl", "The kubectl binary to use. For development, you might use 'cluster/kubectl.sh' here.")
 | 
			
		||||
 | 
			
		||||
	flags.StringVar(&TestContext.ProgressReportURL, "progress-report-url", "", "The URL to POST progress updates to as the suite runs to assist in aiding integrations. If empty, no messages sent.")
 | 
			
		||||
@@ -482,7 +503,7 @@ func AfterReadingAllFlags(t *TestContextType) {
 | 
			
		||||
		for _, v := range image.GetImageConfigs() {
 | 
			
		||||
			fmt.Println(v.GetE2EImage())
 | 
			
		||||
		}
 | 
			
		||||
		os.Exit(0)
 | 
			
		||||
		Exit(0)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Reconfigure gomega defaults. The poll interval should be suitable
 | 
			
		||||
@@ -494,6 +515,19 @@ func AfterReadingAllFlags(t *TestContextType) {
 | 
			
		||||
	gomega.SetDefaultEventuallyTimeout(t.timeouts.PodStart)
 | 
			
		||||
	gomega.SetDefaultConsistentlyDuration(t.timeouts.PodStartShort)
 | 
			
		||||
 | 
			
		||||
	// ginkgo.PreviewSpecs will expand all nodes and thus may find new bugs.
 | 
			
		||||
	report := ginkgo.PreviewSpecs("Kubernetes e2e test statistics")
 | 
			
		||||
	if err := FormatBugs(); CheckForBugs && err != nil {
 | 
			
		||||
		// Refuse to do anything if the E2E suite is buggy.
 | 
			
		||||
		fmt.Fprint(Output, "ERROR: E2E suite initialization was faulty, these errors must be fixed:")
 | 
			
		||||
		fmt.Fprint(Output, "\n"+err.Error())
 | 
			
		||||
		Exit(1)
 | 
			
		||||
	}
 | 
			
		||||
	if t.listLabels || t.listTests {
 | 
			
		||||
		listTestInformation(report)
 | 
			
		||||
		Exit(0)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Only set a default host if one won't be supplied via kubeconfig
 | 
			
		||||
	if len(t.Host) == 0 && len(t.KubeConfig) == 0 {
 | 
			
		||||
		// Check if we can use the in-cluster config
 | 
			
		||||
@@ -553,7 +587,7 @@ func AfterReadingAllFlags(t *TestContextType) {
 | 
			
		||||
		} else {
 | 
			
		||||
			klog.Errorf("Failed to setup provider config for %q: %v", TestContext.Provider, err)
 | 
			
		||||
		}
 | 
			
		||||
		os.Exit(1)
 | 
			
		||||
		Exit(1)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if TestContext.ReportDir != "" {
 | 
			
		||||
@@ -563,13 +597,13 @@ func AfterReadingAllFlags(t *TestContextType) {
 | 
			
		||||
		// in parallel, so we will get "exists" error in most of them.
 | 
			
		||||
		if err := os.MkdirAll(TestContext.ReportDir, 0777); err != nil && !os.IsExist(err) {
 | 
			
		||||
			klog.Errorf("Create report dir: %v", err)
 | 
			
		||||
			os.Exit(1)
 | 
			
		||||
			Exit(1)
 | 
			
		||||
		}
 | 
			
		||||
		ginkgoDir := path.Join(TestContext.ReportDir, "ginkgo")
 | 
			
		||||
		if TestContext.ReportCompleteGinkgo || TestContext.ReportCompleteJUnit {
 | 
			
		||||
			if err := os.MkdirAll(ginkgoDir, 0777); err != nil && !os.IsExist(err) {
 | 
			
		||||
				klog.Errorf("Create <report-dir>/ginkgo: %v", err)
 | 
			
		||||
				os.Exit(1)
 | 
			
		||||
				Exit(1)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@@ -600,3 +634,47 @@ func AfterReadingAllFlags(t *TestContextType) {
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func listTestInformation(report ginkgo.Report) {
 | 
			
		||||
	indent := strings.Repeat(" ", 4)
 | 
			
		||||
 | 
			
		||||
	if TestContext.listLabels {
 | 
			
		||||
		labels := sets.New[string]()
 | 
			
		||||
		for _, spec := range report.SpecReports {
 | 
			
		||||
			if spec.LeafNodeType == types.NodeTypeIt {
 | 
			
		||||
				labels.Insert(spec.Labels()...)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		fmt.Fprintf(Output, "The following labels can be used with 'gingko run --label-filter':\n%s%s\n\n", indent, strings.Join(sets.List(labels), "\n"+indent))
 | 
			
		||||
	}
 | 
			
		||||
	if TestContext.listTests {
 | 
			
		||||
		leafs := make([][]string, 0, len(report.SpecReports))
 | 
			
		||||
		wd, _ := os.Getwd()
 | 
			
		||||
		for _, spec := range report.SpecReports {
 | 
			
		||||
			if spec.LeafNodeType == types.NodeTypeIt {
 | 
			
		||||
				leafs = append(leafs, []string{fmt.Sprintf("%s:%d: ", relativePath(wd, spec.LeafNodeLocation.FileName), spec.LeafNodeLocation.LineNumber), spec.FullText()})
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		// Sort by test name, not the source code location, because the test
 | 
			
		||||
		// name is more stable across code refactoring.
 | 
			
		||||
		sort.Slice(leafs, func(i, j int) bool {
 | 
			
		||||
			return leafs[i][1] < leafs[j][1]
 | 
			
		||||
		})
 | 
			
		||||
		fmt.Fprint(Output, "The following spec names can be used with 'ginkgo run --focus/skip':\n")
 | 
			
		||||
		for _, leaf := range leafs {
 | 
			
		||||
			fmt.Fprintf(Output, "%s%s%s\n", indent, leaf[0], leaf[1])
 | 
			
		||||
		}
 | 
			
		||||
		fmt.Fprint(Output, "\n")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func relativePath(wd, path string) string {
 | 
			
		||||
	if wd == "" {
 | 
			
		||||
		return path
 | 
			
		||||
	}
 | 
			
		||||
	relpath, err := filepath.Rel(wd, path)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return path
 | 
			
		||||
	}
 | 
			
		||||
	return relpath
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -16,9 +16,7 @@ limitations under the License.
 | 
			
		||||
 | 
			
		||||
package common
 | 
			
		||||
 | 
			
		||||
import "github.com/onsi/ginkgo/v2"
 | 
			
		||||
import "k8s.io/kubernetes/test/e2e/framework"
 | 
			
		||||
 | 
			
		||||
// SIGDescribe annotates the test with the SIG label.
 | 
			
		||||
func SIGDescribe(text string, body func()) bool {
 | 
			
		||||
	return ginkgo.Describe("[sig-instrumentation] "+text, body)
 | 
			
		||||
}
 | 
			
		||||
var SIGDescribe = framework.SIGDescribe("instrumentation")
 | 
			
		||||
 
 | 
			
		||||
@@ -16,9 +16,7 @@ limitations under the License.
 | 
			
		||||
 | 
			
		||||
package kubectl
 | 
			
		||||
 | 
			
		||||
import "github.com/onsi/ginkgo/v2"
 | 
			
		||||
import "k8s.io/kubernetes/test/e2e/framework"
 | 
			
		||||
 | 
			
		||||
// SIGDescribe annotates the test with the SIG label.
 | 
			
		||||
func SIGDescribe(text string, body func()) bool {
 | 
			
		||||
	return ginkgo.Describe("[sig-cli] "+text, body)
 | 
			
		||||
}
 | 
			
		||||
var SIGDescribe = framework.SIGDescribe("cli")
 | 
			
		||||
 
 | 
			
		||||
@@ -16,9 +16,7 @@ limitations under the License.
 | 
			
		||||
 | 
			
		||||
package lifecycle
 | 
			
		||||
 | 
			
		||||
import "github.com/onsi/ginkgo/v2"
 | 
			
		||||
import "k8s.io/kubernetes/test/e2e/framework"
 | 
			
		||||
 | 
			
		||||
// SIGDescribe annotates the test with the SIG label.
 | 
			
		||||
func SIGDescribe(text string, body func()) bool {
 | 
			
		||||
	return ginkgo.Describe("[sig-cluster-lifecycle] "+text, body)
 | 
			
		||||
}
 | 
			
		||||
var SIGDescribe = framework.SIGDescribe("cluster-lifecycle")
 | 
			
		||||
 
 | 
			
		||||
@@ -16,9 +16,7 @@ limitations under the License.
 | 
			
		||||
 | 
			
		||||
package common
 | 
			
		||||
 | 
			
		||||
import "github.com/onsi/ginkgo/v2"
 | 
			
		||||
import "k8s.io/kubernetes/test/e2e/framework"
 | 
			
		||||
 | 
			
		||||
// SIGDescribe annotates the test with the SIG label.
 | 
			
		||||
func SIGDescribe(text string, body func()) bool {
 | 
			
		||||
	return ginkgo.Describe("[sig-network] "+text, body)
 | 
			
		||||
}
 | 
			
		||||
var SIGDescribe = framework.SIGDescribe("network")
 | 
			
		||||
 
 | 
			
		||||
@@ -16,9 +16,7 @@ limitations under the License.
 | 
			
		||||
 | 
			
		||||
package node
 | 
			
		||||
 | 
			
		||||
import "github.com/onsi/ginkgo/v2"
 | 
			
		||||
import "k8s.io/kubernetes/test/e2e/framework"
 | 
			
		||||
 | 
			
		||||
// SIGDescribe annotates the test with the SIG label.
 | 
			
		||||
func SIGDescribe(text string, body func()) bool {
 | 
			
		||||
	return ginkgo.Describe("[sig-node] "+text, body)
 | 
			
		||||
}
 | 
			
		||||
var SIGDescribe = framework.SIGDescribe("node")
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										55
									
								
								test/e2e/nodefeature/nodefeature.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								test/e2e/nodefeature/nodefeature.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,55 @@
 | 
			
		||||
/*
 | 
			
		||||
Copyright 2023 The Kubernetes Authors.
 | 
			
		||||
 | 
			
		||||
Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
you may not use this file except in compliance with the License.
 | 
			
		||||
You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
See the License for the specific language governing permissions and
 | 
			
		||||
limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
// Package feature contains pre-defined node features used by test/e2e and/or
 | 
			
		||||
// test/e2e_node.
 | 
			
		||||
package nodefeature
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"k8s.io/kubernetes/test/e2e/framework"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	AppArmor                               = framework.WithNodeFeature(framework.ValidNodeFeatures.Add("AppArmor"))
 | 
			
		||||
	CheckpointContainer                    = framework.WithNodeFeature(framework.ValidNodeFeatures.Add("CheckpointContainer"))
 | 
			
		||||
	CriticalPod                            = framework.WithNodeFeature(framework.ValidNodeFeatures.Add("CriticalPod"))
 | 
			
		||||
	DeviceManager                          = framework.WithNodeFeature(framework.ValidNodeFeatures.Add("DeviceManager"))
 | 
			
		||||
	DevicePluginProbe                      = framework.WithNodeFeature(framework.ValidNodeFeatures.Add("DevicePluginProbe"))
 | 
			
		||||
	DownwardAPIHugePages                   = framework.WithNodeFeature(framework.ValidNodeFeatures.Add("DownwardAPIHugePages"))
 | 
			
		||||
	DynamicResourceAllocation              = framework.WithNodeFeature(framework.ValidNodeFeatures.Add("DynamicResourceAllocation"))
 | 
			
		||||
	Eviction                               = framework.WithNodeFeature(framework.ValidNodeFeatures.Add("Eviction"))
 | 
			
		||||
	FSGroup                                = framework.WithNodeFeature(framework.ValidNodeFeatures.Add("FSGroup"))
 | 
			
		||||
	GarbageCollect                         = framework.WithNodeFeature(framework.ValidNodeFeatures.Add("GarbageCollect"))
 | 
			
		||||
	GracefulNodeShutdown                   = framework.WithNodeFeature(framework.ValidNodeFeatures.Add("GracefulNodeShutdown"))
 | 
			
		||||
	GracefulNodeShutdownBasedOnPodPriority = framework.WithNodeFeature(framework.ValidNodeFeatures.Add("GracefulNodeShutdownBasedOnPodPriority"))
 | 
			
		||||
	HostAccess                             = framework.WithNodeFeature(framework.ValidNodeFeatures.Add("HostAccess"))
 | 
			
		||||
	ImageID                                = framework.WithNodeFeature(framework.ValidNodeFeatures.Add(" ImageID"))
 | 
			
		||||
	LSCIQuotaMonitoring                    = framework.WithNodeFeature(framework.ValidNodeFeatures.Add("LSCIQuotaMonitoring"))
 | 
			
		||||
	NodeAllocatable                        = framework.WithNodeFeature(framework.ValidNodeFeatures.Add("NodeAllocatable"))
 | 
			
		||||
	NodeProblemDetector                    = framework.WithNodeFeature(framework.ValidNodeFeatures.Add("NodeProblemDetector"))
 | 
			
		||||
	OOMScoreAdj                            = framework.WithNodeFeature(framework.ValidNodeFeatures.Add("OOMScoreAdj"))
 | 
			
		||||
	PodDisruptionConditions                = framework.WithNodeFeature(framework.ValidNodeFeatures.Add("PodDisruptionConditions"))
 | 
			
		||||
	PodResources                           = framework.WithNodeFeature(framework.ValidNodeFeatures.Add("PodResources"))
 | 
			
		||||
	ResourceMetrics                        = framework.WithNodeFeature(framework.ValidNodeFeatures.Add("ResourceMetrics"))
 | 
			
		||||
	RuntimeHandler                         = framework.WithNodeFeature(framework.ValidNodeFeatures.Add("RuntimeHandler"))
 | 
			
		||||
	SystemNodeCriticalPod                  = framework.WithNodeFeature(framework.ValidNodeFeatures.Add("SystemNodeCriticalPod"))
 | 
			
		||||
	TopologyManager                        = framework.WithNodeFeature(framework.ValidNodeFeatures.Add("TopologyManager"))
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
	// This prevents adding additional ad-hoc features in tests.
 | 
			
		||||
	framework.ValidNodeFeatures.Freeze()
 | 
			
		||||
}
 | 
			
		||||
@@ -21,8 +21,6 @@ import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/onsi/ginkgo/v2"
 | 
			
		||||
 | 
			
		||||
	v1 "k8s.io/api/core/v1"
 | 
			
		||||
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
			
		||||
	"k8s.io/apimachinery/pkg/util/sets"
 | 
			
		||||
@@ -33,12 +31,10 @@ import (
 | 
			
		||||
var (
 | 
			
		||||
	timeout  = 10 * time.Minute
 | 
			
		||||
	waitTime = 2 * time.Second
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// SIGDescribe annotates the test with the SIG label.
 | 
			
		||||
func SIGDescribe(text string, body func()) bool {
 | 
			
		||||
	return ginkgo.Describe("[sig-scheduling] "+text, body)
 | 
			
		||||
}
 | 
			
		||||
	// SIGDescribe annotates the test with the SIG label.
 | 
			
		||||
	SIGDescribe = framework.SIGDescribe("scheduling")
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// WaitForStableCluster waits until all existing pods are scheduled and returns their amount.
 | 
			
		||||
func WaitForStableCluster(c clientset.Interface, workerNodes sets.Set[string]) int {
 | 
			
		||||
 
 | 
			
		||||
@@ -53,8 +53,6 @@ var testDrivers = []func() storageframework.TestDriver{
 | 
			
		||||
 | 
			
		||||
// This executes testSuites for in-tree volumes.
 | 
			
		||||
var _ = utils.SIGDescribe("In-tree Volumes", func() {
 | 
			
		||||
	framework.Logf("Enabling in-tree volume drivers")
 | 
			
		||||
 | 
			
		||||
	gceEnabled := false
 | 
			
		||||
	for _, driver := range framework.TestContext.EnabledVolumeDrivers {
 | 
			
		||||
		switch driver {
 | 
			
		||||
 
 | 
			
		||||
@@ -16,9 +16,7 @@ limitations under the License.
 | 
			
		||||
 | 
			
		||||
package utils
 | 
			
		||||
 | 
			
		||||
import "github.com/onsi/ginkgo/v2"
 | 
			
		||||
import "k8s.io/kubernetes/test/e2e/framework"
 | 
			
		||||
 | 
			
		||||
// SIGDescribe annotates the test with the SIG label.
 | 
			
		||||
func SIGDescribe(text string, body func()) bool {
 | 
			
		||||
	return ginkgo.Describe("[sig-storage] "+text, body)
 | 
			
		||||
}
 | 
			
		||||
var SIGDescribe = framework.SIGDescribe("storage")
 | 
			
		||||
 
 | 
			
		||||
@@ -35,7 +35,7 @@ import (
 | 
			
		||||
	"github.com/onsi/gomega"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var _ = SIGDescribe("[Feature:Windows] Cpu Resources [Serial]", func() {
 | 
			
		||||
var _ = sigDescribe("[Feature:Windows] Cpu Resources [Serial]", skipUnlessWindows(func() {
 | 
			
		||||
	f := framework.NewDefaultFramework("cpu-resources-test-windows")
 | 
			
		||||
	f.NamespacePodSecurityLevel = admissionapi.LevelPrivileged
 | 
			
		||||
 | 
			
		||||
@@ -100,7 +100,7 @@ var _ = SIGDescribe("[Feature:Windows] Cpu Resources [Serial]", func() {
 | 
			
		||||
			}
 | 
			
		||||
		})
 | 
			
		||||
	})
 | 
			
		||||
})
 | 
			
		||||
}))
 | 
			
		||||
 | 
			
		||||
// newCPUBurnPods creates a list of pods (specification) with a workload that will consume all available CPU resources up to container limit
 | 
			
		||||
func newCPUBurnPods(numPods int, image imageutils.Config, cpuLimit string, memoryLimit string) []*v1.Pod {
 | 
			
		||||
 
 | 
			
		||||
@@ -40,7 +40,7 @@ import (
 | 
			
		||||
	"github.com/onsi/gomega"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var _ = SIGDescribe("[Feature:Windows] Density [Serial] [Slow]", func() {
 | 
			
		||||
var _ = sigDescribe("[Feature:Windows] Density [Serial] [Slow]", skipUnlessWindows(func() {
 | 
			
		||||
	f := framework.NewDefaultFramework("density-test-windows")
 | 
			
		||||
	f.NamespacePodSecurityLevel = admissionapi.LevelPrivileged
 | 
			
		||||
 | 
			
		||||
@@ -72,7 +72,7 @@ var _ = SIGDescribe("[Feature:Windows] Density [Serial] [Slow]", func() {
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
})
 | 
			
		||||
}))
 | 
			
		||||
 | 
			
		||||
type densityTest struct {
 | 
			
		||||
	// number of pods
 | 
			
		||||
 
 | 
			
		||||
@@ -39,7 +39,7 @@ const (
 | 
			
		||||
	testSlowMultiplier = 60
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var _ = SIGDescribe("[Feature:GPUDevicePlugin] Device Plugin", func() {
 | 
			
		||||
var _ = sigDescribe("[Feature:GPUDevicePlugin] Device Plugin", skipUnlessWindows(func() {
 | 
			
		||||
	f := framework.NewDefaultFramework("device-plugin")
 | 
			
		||||
	f.NamespacePodSecurityLevel = admissionapi.LevelPrivileged
 | 
			
		||||
 | 
			
		||||
@@ -132,4 +132,4 @@ var _ = SIGDescribe("[Feature:GPUDevicePlugin] Device Plugin", func() {
 | 
			
		||||
		_, envVarDirectxGpuNameErr := e2eoutput.LookForStringInPodExec(defaultNs, windowsPod.Name, envVarCommand, envVarDirectxGpuName, time.Minute)
 | 
			
		||||
		framework.ExpectNoError(envVarDirectxGpuNameErr, "failed: didn't find expected environment variable.")
 | 
			
		||||
	})
 | 
			
		||||
})
 | 
			
		||||
}))
 | 
			
		||||
 
 | 
			
		||||
@@ -31,7 +31,7 @@ import (
 | 
			
		||||
	"github.com/onsi/gomega"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var _ = SIGDescribe("[Feature:Windows] DNS", func() {
 | 
			
		||||
var _ = sigDescribe("[Feature:Windows] DNS", skipUnlessWindows(func() {
 | 
			
		||||
 | 
			
		||||
	ginkgo.BeforeEach(func() {
 | 
			
		||||
		e2eskipper.SkipUnlessNodeOSDistroIs("windows")
 | 
			
		||||
@@ -136,4 +136,4 @@ var _ = SIGDescribe("[Feature:Windows] DNS", func() {
 | 
			
		||||
 | 
			
		||||
		// TODO: Add more test cases for other DNSPolicies.
 | 
			
		||||
	})
 | 
			
		||||
})
 | 
			
		||||
}))
 | 
			
		||||
 
 | 
			
		||||
@@ -17,19 +17,29 @@ limitations under the License.
 | 
			
		||||
package windows
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"k8s.io/kubernetes/test/e2e/framework"
 | 
			
		||||
	e2eskipper "k8s.io/kubernetes/test/e2e/framework/skipper"
 | 
			
		||||
 | 
			
		||||
	"github.com/onsi/ginkgo/v2"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// SIGDescribe annotates the test with the SIG label.
 | 
			
		||||
func SIGDescribe(text string, body func()) bool {
 | 
			
		||||
	return ginkgo.Describe("[sig-windows] "+text, func() {
 | 
			
		||||
// sigDescribe annotates the test with the SIG label.
 | 
			
		||||
// Use this together with skipUnlessWindows to define
 | 
			
		||||
// tests that only run if the node OS is Windows:
 | 
			
		||||
//
 | 
			
		||||
//	sigDescribe("foo", skipUnlessWindows(func() { ... }))
 | 
			
		||||
var sigDescribe = framework.SIGDescribe("windows")
 | 
			
		||||
 | 
			
		||||
// skipUnlessWindows wraps some other Ginkgo callback such that
 | 
			
		||||
// a BeforeEach runs before tests defined by that callback which
 | 
			
		||||
// skips those tests unless the node OS is Windows.
 | 
			
		||||
func skipUnlessWindows(cb func()) func() {
 | 
			
		||||
	return func() {
 | 
			
		||||
		ginkgo.BeforeEach(func() {
 | 
			
		||||
			// all tests in this package are Windows specific
 | 
			
		||||
			e2eskipper.SkipUnlessNodeOSDistroIs("windows")
 | 
			
		||||
		})
 | 
			
		||||
 | 
			
		||||
		body()
 | 
			
		||||
	})
 | 
			
		||||
		cb()
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -90,7 +90,7 @@ const (
 | 
			
		||||
	gmsaSharedFolder = "write_test"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var _ = SIGDescribe("[Feature:Windows] GMSA Full [Serial] [Slow]", func() {
 | 
			
		||||
var _ = sigDescribe("[Feature:Windows] GMSA Full [Serial] [Slow]", skipUnlessWindows(func() {
 | 
			
		||||
	f := framework.NewDefaultFramework("gmsa-full-test-windows")
 | 
			
		||||
	f.NamespacePodSecurityLevel = admissionapi.LevelPrivileged
 | 
			
		||||
 | 
			
		||||
@@ -220,7 +220,7 @@ var _ = SIGDescribe("[Feature:Windows] GMSA Full [Serial] [Slow]", func() {
 | 
			
		||||
 | 
			
		||||
		})
 | 
			
		||||
	})
 | 
			
		||||
})
 | 
			
		||||
}))
 | 
			
		||||
 | 
			
		||||
func isValidOutput(output string) bool {
 | 
			
		||||
	return strings.Contains(output, expectedQueryOutput) &&
 | 
			
		||||
 
 | 
			
		||||
@@ -39,7 +39,7 @@ import (
 | 
			
		||||
	"github.com/onsi/gomega"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var _ = SIGDescribe("[Feature:Windows] GMSA Kubelet [Slow]", func() {
 | 
			
		||||
var _ = sigDescribe("[Feature:Windows] GMSA Kubelet [Slow]", skipUnlessWindows(func() {
 | 
			
		||||
	f := framework.NewDefaultFramework("gmsa-kubelet-test-windows")
 | 
			
		||||
	f.NamespacePodSecurityLevel = admissionapi.LevelPrivileged
 | 
			
		||||
 | 
			
		||||
@@ -133,7 +133,7 @@ var _ = SIGDescribe("[Feature:Windows] GMSA Kubelet [Slow]", func() {
 | 
			
		||||
			})
 | 
			
		||||
		})
 | 
			
		||||
	})
 | 
			
		||||
})
 | 
			
		||||
}))
 | 
			
		||||
 | 
			
		||||
func generateDummyCredSpecs(domain string) *string {
 | 
			
		||||
	shortName := strings.ToUpper(strings.Split(domain, ".")[0])
 | 
			
		||||
 
 | 
			
		||||
@@ -85,7 +85,7 @@ var (
 | 
			
		||||
	User_NTAuthoritySystem       = "NT AUTHORITY\\SYSTEM"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var _ = SIGDescribe("[Feature:WindowsHostProcessContainers] [MinimumKubeletVersion:1.22] HostProcess containers", func() {
 | 
			
		||||
var _ = sigDescribe("[Feature:WindowsHostProcessContainers] [MinimumKubeletVersion:1.22] HostProcess containers", skipUnlessWindows(func() {
 | 
			
		||||
	ginkgo.BeforeEach(func() {
 | 
			
		||||
		e2eskipper.SkipUnlessNodeOSDistroIs("windows")
 | 
			
		||||
	})
 | 
			
		||||
@@ -799,7 +799,7 @@ var _ = SIGDescribe("[Feature:WindowsHostProcessContainers] [MinimumKubeletVersi
 | 
			
		||||
		gomega.Expect(strings.ToLower(logs)).ShouldNot(gomega.ContainSubstring("nt authority"), "Container runs 'whoami' and logs should not contain 'nt authority'")
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
})
 | 
			
		||||
}))
 | 
			
		||||
 | 
			
		||||
func makeTestPodWithVolumeMounts(name string) *v1.Pod {
 | 
			
		||||
	hostPathDirectoryOrCreate := v1.HostPathDirectoryOrCreate
 | 
			
		||||
 
 | 
			
		||||
@@ -44,7 +44,7 @@ var (
 | 
			
		||||
	linuxBusyBoxImage   = imageutils.GetE2EImage(imageutils.Nginx)
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var _ = SIGDescribe("Hybrid cluster network", func() {
 | 
			
		||||
var _ = sigDescribe("Hybrid cluster network", skipUnlessWindows(func() {
 | 
			
		||||
	f := framework.NewDefaultFramework("hybrid-network")
 | 
			
		||||
	f.NamespacePodSecurityLevel = admissionapi.LevelPrivileged
 | 
			
		||||
 | 
			
		||||
@@ -99,7 +99,7 @@ var _ = SIGDescribe("Hybrid cluster network", func() {
 | 
			
		||||
		})
 | 
			
		||||
 | 
			
		||||
	})
 | 
			
		||||
})
 | 
			
		||||
}))
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	warmUpDuration = "30s"
 | 
			
		||||
 
 | 
			
		||||
@@ -35,7 +35,7 @@ var (
 | 
			
		||||
	WindowsHyperVContainerRuntimeClass = "runhcs-wcow-hypervisor"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var _ = SIGDescribe("[Feature:WindowsHyperVContainers] HyperV containers", func() {
 | 
			
		||||
var _ = sigDescribe("[Feature:WindowsHyperVContainers] HyperV containers", skipUnlessWindows(func() {
 | 
			
		||||
	ginkgo.BeforeEach(func() {
 | 
			
		||||
		e2eskipper.SkipUnlessNodeOSDistroIs("windows")
 | 
			
		||||
	})
 | 
			
		||||
@@ -143,4 +143,4 @@ var _ = SIGDescribe("[Feature:WindowsHyperVContainers] HyperV containers", func(
 | 
			
		||||
 | 
			
		||||
		gomega.Expect(p.Status.Phase).To(gomega.Equal(v1.PodSucceeded), "pod should have succeeded")
 | 
			
		||||
	})
 | 
			
		||||
})
 | 
			
		||||
}))
 | 
			
		||||
 
 | 
			
		||||
@@ -37,7 +37,7 @@ import (
 | 
			
		||||
	"github.com/onsi/gomega"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var _ = SIGDescribe("[Feature:Windows] Kubelet-Stats [Serial]", func() {
 | 
			
		||||
var _ = sigDescribe("[Feature:Windows] Kubelet-Stats [Serial]", skipUnlessWindows(func() {
 | 
			
		||||
	f := framework.NewDefaultFramework("kubelet-stats-test-windows-serial")
 | 
			
		||||
	f.NamespacePodSecurityLevel = admissionapi.LevelPrivileged
 | 
			
		||||
 | 
			
		||||
@@ -113,8 +113,9 @@ var _ = SIGDescribe("[Feature:Windows] Kubelet-Stats [Serial]", func() {
 | 
			
		||||
			})
 | 
			
		||||
		})
 | 
			
		||||
	})
 | 
			
		||||
})
 | 
			
		||||
var _ = SIGDescribe("[Feature:Windows] Kubelet-Stats", func() {
 | 
			
		||||
}))
 | 
			
		||||
 | 
			
		||||
var _ = sigDescribe("[Feature:Windows] Kubelet-Stats", skipUnlessWindows(func() {
 | 
			
		||||
	f := framework.NewDefaultFramework("kubelet-stats-test-windows")
 | 
			
		||||
	f.NamespacePodSecurityLevel = admissionapi.LevelPrivileged
 | 
			
		||||
 | 
			
		||||
@@ -204,7 +205,7 @@ var _ = SIGDescribe("[Feature:Windows] Kubelet-Stats", func() {
 | 
			
		||||
			})
 | 
			
		||||
		})
 | 
			
		||||
	})
 | 
			
		||||
})
 | 
			
		||||
}))
 | 
			
		||||
 | 
			
		||||
// findWindowsNode finds a Windows node that is Ready and Schedulable
 | 
			
		||||
func findWindowsNode(ctx context.Context, f *framework.Framework) (v1.Node, error) {
 | 
			
		||||
 
 | 
			
		||||
@@ -39,7 +39,7 @@ import (
 | 
			
		||||
	"github.com/onsi/gomega"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var _ = SIGDescribe("[Feature:Windows] Memory Limits [Serial] [Slow]", func() {
 | 
			
		||||
var _ = sigDescribe("[Feature:Windows] Memory Limits [Serial] [Slow]", skipUnlessWindows(func() {
 | 
			
		||||
 | 
			
		||||
	f := framework.NewDefaultFramework("memory-limit-test-windows")
 | 
			
		||||
	f.NamespacePodSecurityLevel = admissionapi.LevelPrivileged
 | 
			
		||||
@@ -60,8 +60,7 @@ var _ = SIGDescribe("[Feature:Windows] Memory Limits [Serial] [Slow]", func() {
 | 
			
		||||
			overrideAllocatableMemoryTest(ctx, f, framework.TestContext.CloudConfig.NumNodes)
 | 
			
		||||
		})
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
})
 | 
			
		||||
}))
 | 
			
		||||
 | 
			
		||||
type nodeMemory struct {
 | 
			
		||||
	// capacity
 | 
			
		||||
 
 | 
			
		||||
@@ -34,7 +34,7 @@ import (
 | 
			
		||||
	admissionapi "k8s.io/pod-security-admission/api"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var _ = SIGDescribe("[Feature:Windows] [Excluded:WindowsDocker] [MinimumKubeletVersion:1.22] RebootHost containers [Serial] [Disruptive] [Slow]", func() {
 | 
			
		||||
var _ = sigDescribe("[Feature:Windows] [Excluded:WindowsDocker] [MinimumKubeletVersion:1.22] RebootHost containers [Serial] [Disruptive] [Slow]", skipUnlessWindows(func() {
 | 
			
		||||
	ginkgo.BeforeEach(func() {
 | 
			
		||||
		e2eskipper.SkipUnlessNodeOSDistroIs("windows")
 | 
			
		||||
	})
 | 
			
		||||
@@ -254,4 +254,4 @@ var _ = SIGDescribe("[Feature:Windows] [Excluded:WindowsDocker] [MinimumKubeletV
 | 
			
		||||
		framework.ExpectNoError(err, "Error retrieving pod")
 | 
			
		||||
		gomega.Expect(p.Status.Phase).To(gomega.Equal(v1.PodSucceeded))
 | 
			
		||||
	})
 | 
			
		||||
})
 | 
			
		||||
}))
 | 
			
		||||
 
 | 
			
		||||
@@ -40,7 +40,7 @@ import (
 | 
			
		||||
 | 
			
		||||
const runAsUserNameContainerName = "run-as-username-container"
 | 
			
		||||
 | 
			
		||||
var _ = SIGDescribe("[Feature:Windows] SecurityContext", func() {
 | 
			
		||||
var _ = sigDescribe("[Feature:Windows] SecurityContext", skipUnlessWindows(func() {
 | 
			
		||||
	f := framework.NewDefaultFramework("windows-run-as-username")
 | 
			
		||||
	f.NamespacePodSecurityLevel = admissionapi.LevelPrivileged
 | 
			
		||||
 | 
			
		||||
@@ -190,7 +190,7 @@ var _ = SIGDescribe("[Feature:Windows] SecurityContext", func() {
 | 
			
		||||
		expectedEventError := "container's runAsUserName (CONTAINERADMINISTRATOR) which will be regarded as root identity and will break non-root policy"
 | 
			
		||||
		gomega.Expect(event.Message).Should(gomega.ContainSubstring(expectedEventError), "Event error should indicate non-root policy caused container to not start")
 | 
			
		||||
	})
 | 
			
		||||
})
 | 
			
		||||
}))
 | 
			
		||||
 | 
			
		||||
func runAsUserNamePod(username *string) *v1.Pod {
 | 
			
		||||
	podName := "run-as-username-" + string(uuid.NewUUID())
 | 
			
		||||
 
 | 
			
		||||
@@ -36,7 +36,7 @@ import (
 | 
			
		||||
	"github.com/onsi/gomega"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var _ = SIGDescribe("Services", func() {
 | 
			
		||||
var _ = sigDescribe("Services", skipUnlessWindows(func() {
 | 
			
		||||
	f := framework.NewDefaultFramework("services")
 | 
			
		||||
	f.NamespacePodSecurityLevel = admissionapi.LevelPrivileged
 | 
			
		||||
 | 
			
		||||
@@ -85,5 +85,4 @@ var _ = SIGDescribe("Services", func() {
 | 
			
		||||
		assertConsistentConnectivity(ctx, f, testPod.ObjectMeta.Name, windowsOS, windowsCheck(fmt.Sprintf("http://%s", net.JoinHostPort(nodeIP, strconv.Itoa(nodePort)))))
 | 
			
		||||
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
})
 | 
			
		||||
}))
 | 
			
		||||
 
 | 
			
		||||
@@ -44,7 +44,7 @@ var (
 | 
			
		||||
	image = imageutils.GetE2EImage(imageutils.Pause)
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var _ = SIGDescribe("[Feature:Windows] Windows volume mounts", func() {
 | 
			
		||||
var _ = sigDescribe("[Feature:Windows] Windows volume mounts", skipUnlessWindows(func() {
 | 
			
		||||
	f := framework.NewDefaultFramework("windows-volumes")
 | 
			
		||||
	f.NamespacePodSecurityLevel = admissionapi.LevelPrivileged
 | 
			
		||||
	var (
 | 
			
		||||
@@ -86,8 +86,7 @@ var _ = SIGDescribe("[Feature:Windows] Windows volume mounts", func() {
 | 
			
		||||
		})
 | 
			
		||||
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
})
 | 
			
		||||
}))
 | 
			
		||||
 | 
			
		||||
func doReadOnlyTest(ctx context.Context, f *framework.Framework, source v1.VolumeSource, volumePath string) {
 | 
			
		||||
	var (
 | 
			
		||||
 
 | 
			
		||||
@@ -4,9 +4,11 @@ rules:
 | 
			
		||||
    allowedPrefixes:
 | 
			
		||||
      - k8s.io/kubernetes/test/e2e/common
 | 
			
		||||
      - k8s.io/kubernetes/test/e2e/dra/test-driver/app
 | 
			
		||||
      - k8s.io/kubernetes/test/e2e/feature
 | 
			
		||||
      - k8s.io/kubernetes/test/e2e/framework
 | 
			
		||||
      - k8s.io/kubernetes/test/e2e/storage/utils
 | 
			
		||||
      - k8s.io/kubernetes/test/e2e/network/common
 | 
			
		||||
      - k8s.io/kubernetes/test/e2e/nodefeature
 | 
			
		||||
      - k8s.io/kubernetes/test/e2e/perftype
 | 
			
		||||
      - k8s.io/kubernetes/test/e2e/testing-manifests
 | 
			
		||||
      - k8s.io/kubernetes/test/e2e_node
 | 
			
		||||
 
 | 
			
		||||
@@ -53,6 +53,10 @@ import (
 | 
			
		||||
	e2enodetestingmanifests "k8s.io/kubernetes/test/e2e_node/testing-manifests"
 | 
			
		||||
	system "k8s.io/system-validators/validators"
 | 
			
		||||
 | 
			
		||||
	// define and freeze constants
 | 
			
		||||
	_ "k8s.io/kubernetes/test/e2e/feature"
 | 
			
		||||
	_ "k8s.io/kubernetes/test/e2e/nodefeature"
 | 
			
		||||
 | 
			
		||||
	// reconfigure framework
 | 
			
		||||
	_ "k8s.io/kubernetes/test/e2e/framework/debug/init"
 | 
			
		||||
	_ "k8s.io/kubernetes/test/e2e/framework/metrics/init"
 | 
			
		||||
 
 | 
			
		||||
@@ -16,9 +16,7 @@ limitations under the License.
 | 
			
		||||
 | 
			
		||||
package e2enode
 | 
			
		||||
 | 
			
		||||
import "github.com/onsi/ginkgo/v2"
 | 
			
		||||
import "k8s.io/kubernetes/test/e2e/framework"
 | 
			
		||||
 | 
			
		||||
// SIGDescribe annotates the test with the SIG label.
 | 
			
		||||
func SIGDescribe(text string, body func()) bool {
 | 
			
		||||
	return ginkgo.Describe("[sig-node] "+text, body)
 | 
			
		||||
}
 | 
			
		||||
var SIGDescribe = framework.SIGDescribe("node")
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user