...

Source file src/edge-infra.dev/pkg/f8n/warehouse/k8s/controllers/lumperctl/integration/controller_test.go

Documentation: edge-infra.dev/pkg/f8n/warehouse/k8s/controllers/lumperctl/integration

     1  package integration
     2  
     3  import (
     4  	"context"
     5  	_ "embed"
     6  	"fmt"
     7  	"os"
     8  	"testing"
     9  	"time"
    10  
    11  	"gotest.tools/v3/assert/cmp"
    12  	ctrl "sigs.k8s.io/controller-runtime"
    13  	"sigs.k8s.io/controller-runtime/pkg/client"
    14  	"sigs.k8s.io/kustomize/api/filters/namespace"
    15  
    16  	"edge-infra.dev/pkg/f8n/warehouse/capability"
    17  	"edge-infra.dev/pkg/f8n/warehouse/cluster"
    18  	whv1 "edge-infra.dev/pkg/f8n/warehouse/k8s/apis/v1alpha2"
    19  	"edge-infra.dev/pkg/f8n/warehouse/k8s/controllers/lumperctl"
    20  	"edge-infra.dev/pkg/f8n/warehouse/k8s/controllers/lumperctl/internal"
    21  	"edge-infra.dev/pkg/f8n/warehouse/oci"
    22  	"edge-infra.dev/pkg/f8n/warehouse/oci/cache"
    23  	"edge-infra.dev/pkg/f8n/warehouse/oci/layer"
    24  	"edge-infra.dev/pkg/f8n/warehouse/pallet"
    25  	"edge-infra.dev/pkg/k8s/object"
    26  	"edge-infra.dev/pkg/k8s/runtime/conditions"
    27  	"edge-infra.dev/pkg/k8s/runtime/inventory"
    28  	"edge-infra.dev/pkg/k8s/unstructured"
    29  	"edge-infra.dev/pkg/lib/fog"
    30  	"edge-infra.dev/test/f2"
    31  	"edge-infra.dev/test/f2/x/ktest"
    32  	"edge-infra.dev/test/f2/x/warehouse"
    33  )
    34  
    35  // TODO(wg-testing): update TestXXX funcs to call t.Parallel() once f2 supports
    36  
    37  var f f2.Framework
    38  
    39  // testPallet represents a pallet test fixture that is parsed + pushed to the
    40  // test registry
    41  type testPallet struct {
    42  	inv    *inventory.ResourceInventory
    43  	digest string
    44  	name   string
    45  	tag    string
    46  	pallet pallet.Pallet
    47  }
    48  
    49  // Test fixtures
    50  var (
    51  	//go:embed testdata/minimal-pallet-v1
    52  	minimalv1 []byte
    53  	//go:embed testdata/minimal-pallet-v2
    54  	minimalv2 []byte
    55  	//go:embed testdata/fake-infra.yaml
    56  	fakeInfra []byte
    57  	//go:embed testdata/fake-mesh-config.yaml
    58  	fakeMeshConfig []byte
    59  	//go:embed testdata/linkerdctl/linkerd.yaml
    60  	linkerdCapablityProvider []byte
    61  	//go:embed testdata/meshconfig
    62  	meshConfig []byte
    63  	//go:embed testdata/sappers/removes-fields-initial.yaml
    64  	sapInitial []byte
    65  	//go:embed testdata/sappers/removes-fields-after.yaml
    66  	sapFinal []byte
    67  
    68  	l5dCap capability.Capability = "linkerd"
    69  )
    70  
    71  const fixtureSemVer = "0.2.5-test.1711660462+commit.d34db33f"
    72  
    73  func TestMain(m *testing.M) {
    74  	// TODO(aw18576): logr interface impl for t.Log() and let framework set up?
    75  	// Set global loggers for controller-runtime and other pkgs so that our
    76  	// reconcilers log during test
    77  	lumperctl.SetPackageLoggers(fog.New())
    78  
    79  	healthzChecker := internal.New(ctrl.Log.WithName("lumper-liveness"))
    80  	f = f2.New(context.Background(),
    81  		f2.WithExtensions(
    82  			ktest.New(
    83  				ktest.WithCtrlManager(lumperctl.CreateMgr(healthzChecker)),
    84  				ktest.WithMetricsAddress(8080),
    85  			),
    86  			&warehouse.Registry{},
    87  		),
    88  	).
    89  		Setup(func(ctx f2.Context) (f2.Context, error) {
    90  			k, err := ktest.FromContext(ctx)
    91  			if err != nil {
    92  				return ctx, err
    93  			}
    94  
    95  			// Override timeouts if we aren't using a live cluster
    96  			if !*k.Env.UseExistingCluster {
    97  				k.Timeout = 5 * time.Second
    98  				k.Tick = 10 * time.Millisecond
    99  			}
   100  
   101  			warehouseCache, err := cache.New(
   102  				cache.WithMemoryCacheSize(250),
   103  			)
   104  			if err != nil {
   105  				return ctx, err
   106  			}
   107  
   108  			// NOTE: Will be nil if ktest.WithCtrlManager was not called, put manager
   109  			// behind k.Manager() and return error or something? Really shouldn't
   110  			// happen but people can be dense
   111  			if err := lumperctl.RegisterControllers(
   112  				k.Manager,
   113  				&lumperctl.Config{
   114  					Provider:  cluster.Generic, // TODO: should test all variations of providers
   115  					SvcAct:    "lumperctl",
   116  					Namespace: k.Namespace,
   117  					UpCfg: lumperctl.UnpackedPalletCfg{
   118  						Concurrent:         32,
   119  						DepRequeueInterval: k.Tick,
   120  					},
   121  					ShipCfg: lumperctl.ShipmentCfg{
   122  						Concurrent: 8,
   123  					},
   124  					Cache: warehouseCache,
   125  				},
   126  				healthzChecker,
   127  			); err != nil {
   128  				return ctx, err
   129  			}
   130  			fmt.Println("after register controllers")
   131  
   132  			fmt.Println("was able to register the controllers")
   133  			return ctx, nil
   134  		})
   135  
   136  	os.Exit(f.Run(m))
   137  }
   138  
   139  func unpackedPallet(
   140  	ctx f2.Context,
   141  	t *testing.T,
   142  	name string,
   143  	p pallet.Pallet,
   144  	opts ...whv1.Option,
   145  ) *whv1.UnpackedPallet {
   146  	t.Helper()
   147  	reg := warehouse.FromContextT(ctx, t)
   148  
   149  	digest, err := p.Digest()
   150  	if err != nil {
   151  		t.Fatalf("failed to compute digest of test pallet %s: %v", p.Name(), err)
   152  	}
   153  
   154  	repo := fmt.Sprintf("%s/%s", reg.URL, p.Name())
   155  	return whv1.NewUnpackedPallet(name,
   156  		append([]whv1.Option{
   157  			whv1.WithArtifact(whv1.NewArtifact(p.Name(), digest.String(), repo)),
   158  			whv1.ForProvider(cluster.Generic),
   159  			whv1.WithRuntime(),
   160  			whv1.WithTimeout(ktest.FromContextT(ctx, t).Tick * 3),
   161  			whv1.WithRetryInterval(ktest.FromContextT(ctx, t).Tick),
   162  		}, opts...)...,
   163  	)
   164  }
   165  
   166  func shipment(
   167  	ctx f2.Context,
   168  	t *testing.T,
   169  	name string,
   170  	pallets []whv1.BaseArtifact,
   171  	opts ...whv1.Option,
   172  ) *whv1.Shipment {
   173  	t.Helper()
   174  
   175  	return whv1.NewShipment(name,
   176  		append([]whv1.Option{
   177  			whv1.FromRepo(warehouse.FromContextT(ctx, t).URL),
   178  			whv1.WithArtifacts(pallets...),
   179  			whv1.ForProvider(cluster.Generic),
   180  			whv1.WithRuntime(),
   181  			whv1.WithRetryInterval(ktest.FromContextT(ctx, t).Tick),
   182  		}, opts...)...,
   183  	)
   184  }
   185  
   186  func createAndPushPallet(
   187  	ctx f2.Context,
   188  	t *testing.T,
   189  	name,
   190  	tag string,
   191  	layers ...layer.Layer,
   192  ) testPallet {
   193  	t.Helper()
   194  
   195  	p := testPallet{name: name, tag: tag}
   196  
   197  	var objs []*unstructured.Unstructured
   198  	for i, l := range layers {
   199  		// Transform objects so they are scheduled to test Namespace and avoid
   200  		// collision with other concurrent tests using same source objects
   201  		l, err := layer.Filter(
   202  			l,
   203  			namespace.Filter{Namespace: ktest.FromContextT(ctx, t).Namespace},
   204  		)
   205  		if err != nil {
   206  			t.Fatal("failed to render test pallet manifests", err)
   207  		}
   208  
   209  		r, err := l.Uncompressed()
   210  		if err != nil {
   211  			t.Fatal(name, err)
   212  		}
   213  		lobjs, err := object.ReadObjects(r)
   214  		if err != nil {
   215  			t.Fatal("failed to read test pallet objects", name, err)
   216  		}
   217  		objs = append(objs, lobjs...)
   218  		// Replace updated layer
   219  		layers[i] = l
   220  	}
   221  	p.inv = inventory.New(inventory.FromUnstructured(objs...))
   222  
   223  	a, err := pallet.Image(pallet.Options{
   224  		Metadata:         pkgMeta(name),
   225  		ClusterProviders: cluster.BuiltInProviders(),
   226  	}, layers...)
   227  	if err != nil {
   228  		t.Fatal("failed to create test pallet", name, err)
   229  	}
   230  	p.pallet = a
   231  
   232  	d, err := a.Digest()
   233  	if err != nil {
   234  		t.Fatal(name, err)
   235  	}
   236  	p.digest = d.String()
   237  
   238  	// Push so package is available for controller to pull
   239  	pushPkg(ctx, t, a, name, tag)
   240  
   241  	return p
   242  }
   243  
   244  func createAndPushPalletWithDeps(
   245  	ctx f2.Context,
   246  	t *testing.T,
   247  	name,
   248  	tag string,
   249  	deps ...oci.Artifact,
   250  ) testPallet {
   251  	t.Helper()
   252  
   253  	p := testPallet{name: name, tag: tag}
   254  
   255  	a, err := pallet.ImageIndex(pallet.Options{
   256  		Metadata:         pkgMeta(name),
   257  		ClusterProviders: cluster.BuiltInProviders(),
   258  	}, deps...)
   259  	if err != nil {
   260  		t.Fatal("failed to create test pallet", name, err)
   261  	}
   262  	p.pallet = a
   263  
   264  	d, err := a.Digest()
   265  	if err != nil {
   266  		t.Fatal(name, err)
   267  	}
   268  	p.digest = d.String()
   269  
   270  	// Push so package is available for controller to pull
   271  	pushPkg(ctx, t, a, name, tag)
   272  
   273  	return p
   274  }
   275  
   276  func createLayer(
   277  	t *testing.T,
   278  	lt layer.Type, //nolint // will use other layer.Type in future tests
   279  	yaml []byte,
   280  	opts ...layer.Option,
   281  ) layer.Layer {
   282  	t.Helper()
   283  
   284  	l, err := layer.New(lt, yaml, opts...)
   285  	if err != nil {
   286  		t.Fatal("failed to create test pallet layer", err)
   287  	}
   288  
   289  	return l
   290  }
   291  
   292  func pushPkg(ctx f2.Context, t *testing.T, a oci.Artifact, name, tag string) {
   293  	t.Helper()
   294  
   295  	if err := warehouse.FromContextT(ctx, t).Push(a, name, tag); err != nil {
   296  		t.Fatal("failed to push test pallet", err)
   297  	}
   298  }
   299  
   300  func pkgMeta(name string) pallet.Metadata {
   301  	return pallet.Metadata{
   302  		Name: name,
   303  		Team: "@ncrvoyix-swt-retail/edge-foundation",
   304  		BuildInfo: pallet.BuildInfo{
   305  			Created:  "yesterday",
   306  			Source:   "https://gothub.com/ncrvoyix-swt-retail/edge-infra",
   307  			Revision: "d34db33f",
   308  			Version:  "0.2.5-test.1711660462+commit.d34db33f",
   309  		},
   310  	}
   311  }
   312  
   313  func fakeL5dLayer(t *testing.T) layer.Layer {
   314  	return createLayer(t, layer.Runtime, fakeMeshConfig,
   315  		layer.ForCapability(l5dCap))
   316  }
   317  
   318  func fakeInfraLayer(t *testing.T) layer.Layer {
   319  	return createLayer(t, layer.Infra, fakeInfra)
   320  }
   321  
   322  func id(ctx f2.Context, name string) string {
   323  	return fmt.Sprintf("%s-%s", name, ctx.RunID)
   324  }
   325  
   326  func unpackedPalletReady(o client.Object) cmp.Result {
   327  	u := o.(*whv1.UnpackedPallet)
   328  	if conditions.IsReady(u) &&
   329  		u.Status.ObservedGeneration == u.Generation &&
   330  		u.IsUpToDate() {
   331  		return cmp.ResultSuccess
   332  	}
   333  	return cmp.ResultFailure(fmt.Sprintf("%s not ready", object.FmtObject(u)))
   334  }
   335  
   336  func shipmentReady(o client.Object) cmp.Result {
   337  	s := o.(*whv1.Shipment)
   338  	if conditions.IsReady(s) && s.IsUpToDate() {
   339  		return cmp.ResultSuccess
   340  	}
   341  	return cmp.ResultFailure(fmt.Sprintf("%s not ready", object.FmtObject(s)))
   342  }
   343  
   344  func shipmentStalled(o client.Object) cmp.Result {
   345  	s := o.(*whv1.Shipment)
   346  	if conditions.IsStalled(s) && s.IsUpToDate() {
   347  		return cmp.ResultSuccess
   348  	}
   349  	return cmp.ResultFailure(fmt.Sprintf("%s not stalled", object.FmtObject(s)))
   350  }
   351  

View as plain text