package unpack import ( "os" "testing" "github.com/google/go-containerregistry/pkg/name" assertAPI "github.com/stretchr/testify/assert" "edge-infra.dev/pkg/f8n/warehouse/cluster" "edge-infra.dev/pkg/f8n/warehouse/lift" "edge-infra.dev/pkg/f8n/warehouse/oci" "edge-infra.dev/pkg/f8n/warehouse/oci/layer" "edge-infra.dev/pkg/f8n/warehouse/pallet" "edge-infra.dev/pkg/lib/uuid" "edge-infra.dev/test/fixtures" ) var ( path *fixtures.Path fluentbit oci.Artifact // package containing unrenderable dependency shoot oci.Artifact // v1.ImageIndex test fixture certMgr oci.Artifact // v1.Image test fixture // walk function that verifies all layers are processed layerCheck = func(t *testing.T) Fn { return func(_ pallet.Pallet, ll []layer.Layer) error { for _, l := range ll { checkLayerProcessing(t, l) } return nil } } ) func TestMain(m *testing.M) { // one time set up of shared test fixtures var err error path, err = fixtures.Layout() if err != nil { panic(err) } shoot, err = path.Get(name.MustParseReference("shoot:latest")) if err != nil { panic(err) } certMgr, err = path.Get(name.MustParseReference("cert-manager:latest")) if err != nil { panic(err) } fluentbit, err = path.Get(name.MustParseReference("fluentbit-test:latest")) if err != nil { panic(err) } os.Exit(m.Run()) } func TestUnpack(t *testing.T) { var ( assert = assertAPI.New(t) visited = map[string]bool{} ) // TODO: test that nodes excluded by ForProvider aren't visited assert.NoError(Walk(shoot, func(p pallet.Pallet, _ []layer.Layer) error { if visited[p.Name()] { t.Error("node already visited, function called twice", p.Name()) return nil } t.Log("visiting", p.Name()) deps, err := p.Dependencies() assert.NoError(err) // NOTE: this test logic isn't fantastic. it assumes that the test pallet, // shoot, doesn't have nested composite dependencies for _, d := range deps { t.Log("checking dep", d.Name()) // we will only have visited the dependency if it isn't a composite package // (aka, doesnt have its own images) isComposite, err := oci.IsComposite(d) assert.NoError(err) switch { case !isComposite: assert.Truef(visited[d.Name()], "dependency %s was not visited first for package %s", d.Name(), p.Name()) // but we should have visited its dependencies case isComposite: deps, err := d.Dependencies() assert.NoError(err) for _, d2 := range deps { isComposite, err := oci.IsComposite(d2) assert.NoError(err) if isComposite { assert.Truef(visited[d2.Name()], "dependency %s was not visited first for package %s", d2.Name(), d.Name()) } } } } visited[p.Name()] = true return nil }, ForProvider(cluster.Generic))) t.Run("ForProvider required for some input types", func(t *testing.T) { var ( assert = assertAPI.New(t) nopWalk = func(_ pallet.Pallet, _ []layer.Layer) error { return nil } ) assert.Error(Walk(shoot, nopWalk), "v1.ImageIndex should require ForProvider") p, err := pallet.New(shoot) assert.NoError(err) assert.Error(Walk(p, nopWalk), "Pallet should require ForProvider") cm, err := path.Get(name.MustParseReference("cert-manager:latest")) assert.NoError(err) assert.NoError(Walk(cm, nopWalk), "v1.Image should not require ForProvider") p, err = pallet.New(cm) assert.NoError(err) assert.NoError(Walk(p, nopWalk), "Pallet backed by v1.Image should not require ForProvider") }) t.Run("Layers Processed for all Input Types", func(t *testing.T) { var ( assert = assertAPI.New(t) walk = layerCheck(t) opts = []Option{ ForProvider(cluster.Generic), RenderWith(map[string]string{lift.ClusterUUIDRenderingParameter: uuid.New().UUID}), } ) assert.NoError(Walk(shoot, walk, opts...), "v1.ImageIndex layers weren't processsed") assert.NoError(Walk(certMgr, walk, opts...), "v1.Image layers weren't processed") p, err := pallet.New(shoot) assert.NoError(err) assert.NoError(Walk(p, walk, opts...), "Pallet from v1.ImageIndex layers weren't processed") p, err = pallet.New(shoot) assert.NoError(err) assert.NoError(Walk(p, walk, opts...), "Pallet from v1.Image layers weren't processed") }) t.Run("Handle Unrenderable Dependency", func(t *testing.T) { assertAPI.NoError(t, Walk(fluentbit, layerCheck(t), ForProvider(cluster.Generic), RenderWith(map[string]string{lift.ClusterUUIDRenderingParameter: uuid.New().UUID})), ) }) }