sigs.k8s.io/cluster-api-provider-azure@v1.14.3/internal/test/env/env.go (about)

     1  /*
     2  Copyright 2020 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package env
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"go/build"
    23  	"os"
    24  	"path"
    25  	"path/filepath"
    26  	"regexp"
    27  	goruntime "runtime"
    28  	"strings"
    29  
    30  	"github.com/go-logr/logr"
    31  	"github.com/onsi/ginkgo/v2"
    32  	"k8s.io/apimachinery/pkg/runtime"
    33  	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
    34  	clientgoscheme "k8s.io/client-go/kubernetes/scheme"
    35  	"k8s.io/client-go/rest"
    36  	"k8s.io/klog/v2"
    37  	"k8s.io/utils/ptr"
    38  	infrav1 "sigs.k8s.io/cluster-api-provider-azure/api/v1beta1"
    39  	infrav1exp "sigs.k8s.io/cluster-api-provider-azure/exp/api/v1beta1"
    40  	"sigs.k8s.io/cluster-api-provider-azure/internal/test/record"
    41  	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
    42  	expv1 "sigs.k8s.io/cluster-api/exp/api/v1beta1"
    43  	"sigs.k8s.io/controller-runtime/pkg/client"
    44  	"sigs.k8s.io/controller-runtime/pkg/envtest"
    45  	"sigs.k8s.io/controller-runtime/pkg/manager"
    46  	"sigs.k8s.io/controller-runtime/pkg/metrics/server"
    47  )
    48  
    49  var (
    50  	logger                 = record.NewLogger(record.WithThreshold(ptr.To(1)), record.WithWriter(ginkgo.GinkgoWriter))
    51  	scheme                 = runtime.NewScheme()
    52  	env                    *envtest.Environment
    53  	clusterAPIVersionRegex = regexp.MustCompile(`^(\W)sigs\.k8s\.io/cluster-api v(.+)`)
    54  )
    55  
    56  func init() {
    57  	// Calculate the scheme.
    58  	utilruntime.Must(clientgoscheme.AddToScheme(scheme))
    59  	utilruntime.Must(clusterv1.AddToScheme(scheme))
    60  	utilruntime.Must(expv1.AddToScheme(scheme))
    61  	utilruntime.Must(infrav1.AddToScheme(scheme))
    62  	utilruntime.Must(infrav1exp.AddToScheme(scheme))
    63  
    64  	// Get the root of the current file to use in CRD paths.
    65  	_, filename, _, _ := goruntime.Caller(0) //nolint:dogsled // Ignore "declaration has 3 blank identifiers" check.
    66  	root := path.Join(path.Dir(filename), "..", "..", "..")
    67  
    68  	crdPaths := []string{
    69  		filepath.Join(root, "config", "crd", "bases"),
    70  	}
    71  
    72  	if capiPath := getFilePathToCAPICRDs(root); capiPath != "" {
    73  		crdPaths = append(crdPaths, capiPath)
    74  	}
    75  
    76  	// Create the test environment.
    77  	env = &envtest.Environment{
    78  		ErrorIfCRDPathMissing: true,
    79  		CRDDirectoryPaths:     crdPaths,
    80  	}
    81  }
    82  
    83  type (
    84  	// TestEnvironment encapsulates a Kubernetes local test environment.
    85  	TestEnvironment struct {
    86  		manager.Manager
    87  		client.Client
    88  		Config      *rest.Config
    89  		Log         logr.LogSink
    90  		LogRecorder *record.Logger
    91  		doneMgr     chan struct{}
    92  	}
    93  )
    94  
    95  // NewTestEnvironment creates a new environment spinning up a local api-server.
    96  //
    97  // This function should be called only once for each package you're running tests within,
    98  // usually the environment is initialized in a suite_test.go file within a `BeforeSuite` ginkgo block.
    99  func NewTestEnvironment() *TestEnvironment {
   100  	if _, err := env.Start(); err != nil {
   101  		panic(err)
   102  	}
   103  
   104  	mgr, err := manager.New(env.Config, manager.Options{
   105  		Scheme: scheme,
   106  		Metrics: server.Options{
   107  			BindAddress: "0",
   108  		},
   109  	})
   110  	if err != nil {
   111  		klog.Fatalf("Failed to start testenv manager: %v", err)
   112  	}
   113  
   114  	return &TestEnvironment{
   115  		Manager:     mgr,
   116  		Client:      mgr.GetClient(),
   117  		Config:      mgr.GetConfig(),
   118  		LogRecorder: logger,
   119  		Log:         logger,
   120  		doneMgr:     make(chan struct{}),
   121  	}
   122  }
   123  
   124  // StartManager starts the test environment manager and blocks until the context is canceled.
   125  func (t *TestEnvironment) StartManager(ctx context.Context) error {
   126  	return t.Manager.Start(ctx)
   127  }
   128  
   129  // Stop stops the test environment.
   130  func (t *TestEnvironment) Stop() error {
   131  	return env.Stop()
   132  }
   133  
   134  func getFilePathToCAPICRDs(root string) string {
   135  	modBits, err := os.ReadFile(filepath.Join(root, "go.mod"))
   136  	if err != nil {
   137  		return ""
   138  	}
   139  
   140  	var clusterAPIVersion string
   141  	for _, line := range strings.Split(string(modBits), "\n") {
   142  		matches := clusterAPIVersionRegex.FindStringSubmatch(line)
   143  		if len(matches) == 3 {
   144  			clusterAPIVersion = matches[2]
   145  		}
   146  	}
   147  
   148  	if clusterAPIVersion == "" {
   149  		return ""
   150  	}
   151  
   152  	gopath := envOr("GOPATH", build.Default.GOPATH)
   153  	return filepath.Join(gopath, "pkg", "mod", "sigs.k8s.io", fmt.Sprintf("cluster-api@v%s", clusterAPIVersion), "config", "crd", "bases")
   154  }
   155  
   156  func envOr(envKey, defaultValue string) string {
   157  	if value, ok := os.LookupEnv(envKey); ok {
   158  		return value
   159  	}
   160  	return defaultValue
   161  }