github.com/Racer159/jackal@v0.32.7-0.20240401174413-0bd2339e4f2e/src/test/e2e/51_oci_compose_test.go (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  // SPDX-FileCopyrightText: 2021-Present The Jackal Authors
     3  
     4  // Package test provides e2e tests for Jackal.
     5  package test
     6  
     7  import (
     8  	"fmt"
     9  	"os"
    10  	"path/filepath"
    11  	"strconv"
    12  	"strings"
    13  	"testing"
    14  
    15  	"github.com/Racer159/jackal/src/pkg/layout"
    16  	"github.com/Racer159/jackal/src/pkg/transform"
    17  	"github.com/Racer159/jackal/src/pkg/utils"
    18  	"github.com/Racer159/jackal/src/types"
    19  	"github.com/defenseunicorns/pkg/helpers"
    20  	"github.com/stretchr/testify/require"
    21  	"github.com/stretchr/testify/suite"
    22  	corev1 "k8s.io/api/core/v1"
    23  	"oras.land/oras-go/v2/registry"
    24  )
    25  
    26  type SkeletonSuite struct {
    27  	suite.Suite
    28  	*require.Assertions
    29  	Reference registry.Reference
    30  }
    31  
    32  var (
    33  	importEverything     = filepath.Join("src", "test", "packages", "51-import-everything")
    34  	importEverythingPath string
    35  	importception        = filepath.Join("src", "test", "packages", "51-import-everything", "inception")
    36  	importceptionPath    string
    37  )
    38  
    39  func (suite *SkeletonSuite) SetupSuite() {
    40  	suite.Assertions = require.New(suite.T())
    41  
    42  	e2e.SetupDockerRegistry(suite.T(), 555)
    43  	suite.Reference.Registry = "localhost:555"
    44  
    45  	// Setup the package paths after e2e has been initialized
    46  	importEverythingPath = filepath.Join("build", fmt.Sprintf("jackal-package-import-everything-%s-0.0.1.tar.zst", e2e.Arch))
    47  	importceptionPath = filepath.Join("build", fmt.Sprintf("jackal-package-importception-%s-0.0.1.tar.zst", e2e.Arch))
    48  }
    49  
    50  func (suite *SkeletonSuite) TearDownSuite() {
    51  	e2e.TeardownRegistry(suite.T(), 555)
    52  
    53  	err := os.RemoveAll(filepath.Join("src", "test", "packages", "51-import-everything", "charts", "local"))
    54  	suite.NoError(err)
    55  	err = os.RemoveAll(importEverythingPath)
    56  	suite.NoError(err)
    57  	err = os.RemoveAll(importceptionPath)
    58  	suite.NoError(err)
    59  }
    60  
    61  func (suite *SkeletonSuite) Test_0_Publish_Skeletons() {
    62  	suite.T().Log("E2E: Skeleton Package Publish oci://")
    63  	ref := suite.Reference.String()
    64  
    65  	helmCharts := filepath.Join("examples", "helm-charts")
    66  	_, stdErr, err := e2e.Jackal("package", "publish", helmCharts, "oci://"+ref, "--insecure")
    67  	suite.NoError(err)
    68  	suite.Contains(stdErr, "Published "+ref)
    69  
    70  	bigBang := filepath.Join("src", "test", "packages", "51-import-everything", "big-bang-min")
    71  	_, stdErr, err = e2e.Jackal("package", "publish", bigBang, "oci://"+ref, "--insecure")
    72  	suite.NoError(err)
    73  	suite.Contains(stdErr, "Published "+ref)
    74  
    75  	composable := filepath.Join("src", "test", "packages", "09-composable-packages")
    76  	_, stdErr, err = e2e.Jackal("package", "publish", composable, "oci://"+ref, "--insecure")
    77  	suite.NoError(err)
    78  	suite.Contains(stdErr, "Published "+ref)
    79  
    80  	_, stdErr, err = e2e.Jackal("package", "publish", importEverything, "oci://"+ref, "--insecure")
    81  	suite.NoError(err)
    82  	suite.Contains(stdErr, "Published "+ref)
    83  
    84  	_, _, err = e2e.Jackal("package", "inspect", "oci://"+ref+"/import-everything:0.0.1", "--insecure", "-a", "skeleton")
    85  	suite.NoError(err)
    86  
    87  	_, _, err = e2e.Jackal("package", "pull", "oci://"+ref+"/import-everything:0.0.1", "-o", "build", "--insecure", "-a", "skeleton")
    88  	suite.NoError(err)
    89  
    90  	_, _, err = e2e.Jackal("package", "pull", "oci://"+ref+"/helm-charts:0.0.1", "-o", "build", "--insecure", "-a", "skeleton")
    91  	suite.NoError(err)
    92  
    93  	_, _, err = e2e.Jackal("package", "pull", "oci://"+ref+"/big-bang-min:2.10.0", "-o", "build", "--insecure", "-a", "skeleton")
    94  	suite.NoError(err)
    95  
    96  	_, _, err = e2e.Jackal("package", "pull", "oci://"+ref+"/test-compose-package:0.0.1", "-o", "build", "--insecure", "-a", "skeleton")
    97  	suite.NoError(err)
    98  }
    99  
   100  func (suite *SkeletonSuite) Test_1_Compose_Everything_Inception() {
   101  	suite.T().Log("E2E: Skeleton Package Compose oci://")
   102  
   103  	_, _, err := e2e.Jackal("package", "create", importEverything, "-o", "build", "--insecure", "--confirm")
   104  	suite.NoError(err)
   105  
   106  	_, _, err = e2e.Jackal("package", "create", importception, "-o", "build", "--insecure", "--confirm")
   107  	suite.NoError(err)
   108  
   109  	_, stdErr, err := e2e.Jackal("package", "inspect", importEverythingPath)
   110  	suite.NoError(err)
   111  
   112  	targets := []string{
   113  		"import-component-local == import-component-local",
   114  		"import-component-oci == import-component-oci",
   115  		"import-big-bang == import-big-bang",
   116  		"file-imports == file-imports",
   117  		"local-chart-import == local-chart-import",
   118  	}
   119  
   120  	for _, target := range targets {
   121  		suite.Contains(stdErr, target)
   122  	}
   123  }
   124  
   125  func (suite *SkeletonSuite) Test_2_FilePaths() {
   126  	suite.T().Log("E2E: Skeleton + Package File Paths")
   127  
   128  	pkgTars := []string{
   129  		filepath.Join("build", fmt.Sprintf("jackal-package-import-everything-%s-0.0.1.tar.zst", e2e.Arch)),
   130  		filepath.Join("build", "jackal-package-import-everything-skeleton-0.0.1.tar.zst"),
   131  		filepath.Join("build", fmt.Sprintf("jackal-package-importception-%s-0.0.1.tar.zst", e2e.Arch)),
   132  		filepath.Join("build", "jackal-package-helm-charts-skeleton-0.0.1.tar.zst"),
   133  		filepath.Join("build", "jackal-package-big-bang-min-skeleton-2.10.0.tar.zst"),
   134  		filepath.Join("build", "jackal-package-test-compose-package-skeleton-0.0.1.tar.zst"),
   135  	}
   136  
   137  	for _, pkgTar := range pkgTars {
   138  		var pkg types.JackalPackage
   139  
   140  		unpacked := strings.TrimSuffix(pkgTar, ".tar.zst")
   141  		defer os.RemoveAll(unpacked)
   142  		defer os.RemoveAll(pkgTar)
   143  		_, _, err := e2e.Jackal("tools", "archiver", "decompress", pkgTar, unpacked, "--unarchive-all")
   144  		suite.NoError(err)
   145  		suite.DirExists(unpacked)
   146  
   147  		// Verify skeleton contains kustomize-generated manifests.
   148  		if strings.HasSuffix(pkgTar, "jackal-package-test-compose-package-skeleton-0.0.1.tar.zst") {
   149  			kustomizeGeneratedManifests := []string{
   150  				"kustomization-connect-service-0.yaml",
   151  				"kustomization-connect-service-1.yaml",
   152  				"kustomization-connect-service-two-0.yaml",
   153  			}
   154  			manifestDir := filepath.Join(unpacked, "components", "test-compose-package", "manifests")
   155  			for _, manifest := range kustomizeGeneratedManifests {
   156  				manifestPath := filepath.Join(manifestDir, manifest)
   157  				suite.FileExists(manifestPath, "expected to find kustomize-generated manifest: %q", manifestPath)
   158  				var configMap corev1.ConfigMap
   159  				err := utils.ReadYaml(manifestPath, &configMap)
   160  				suite.NoError(err)
   161  				suite.Equal("ConfigMap", configMap.Kind, "expected manifest %q to be of kind ConfigMap", manifestPath)
   162  			}
   163  		}
   164  
   165  		err = utils.ReadYaml(filepath.Join(unpacked, layout.JackalYAML), &pkg)
   166  		suite.NoError(err)
   167  		suite.NotNil(pkg)
   168  
   169  		components := pkg.Components
   170  		suite.NotNil(components)
   171  
   172  		isSkeleton := false
   173  		if strings.Contains(pkgTar, "-skeleton-") {
   174  			isSkeleton = true
   175  		}
   176  		suite.verifyComponentPaths(unpacked, components, isSkeleton)
   177  	}
   178  }
   179  
   180  func (suite *SkeletonSuite) DirOrFileExists(path string) {
   181  	invalid := helpers.InvalidPath(path)
   182  	suite.Falsef(invalid, "path specified does not exist: %s", path)
   183  }
   184  
   185  func (suite *SkeletonSuite) verifyComponentPaths(unpackedPath string, components []types.JackalComponent, isSkeleton bool) {
   186  
   187  	if isSkeleton {
   188  		suite.NoDirExists(filepath.Join(unpackedPath, "images"))
   189  		suite.NoDirExists(filepath.Join(unpackedPath, "sboms"))
   190  	}
   191  
   192  	for _, component := range components {
   193  		if len(component.Charts) == 0 && len(component.Files) == 0 && len(component.Manifests) == 0 && len(component.DataInjections) == 0 && len(component.Repos) == 0 {
   194  			// component has no files to check
   195  			continue
   196  		}
   197  
   198  		base := filepath.Join(unpackedPath, "components", component.Name)
   199  		componentPaths := layout.ComponentPaths{
   200  			Base:           base,
   201  			Temp:           filepath.Join(base, layout.TempDir),
   202  			Files:          filepath.Join(base, layout.FilesDir),
   203  			Charts:         filepath.Join(base, layout.ChartsDir),
   204  			Repos:          filepath.Join(base, layout.ReposDir),
   205  			Manifests:      filepath.Join(base, layout.ManifestsDir),
   206  			DataInjections: filepath.Join(base, layout.DataInjectionsDir),
   207  			Values:         filepath.Join(base, layout.ValuesDir),
   208  		}
   209  
   210  		if isSkeleton && component.DeprecatedCosignKeyPath != "" {
   211  			suite.FileExists(filepath.Join(base, component.DeprecatedCosignKeyPath))
   212  		}
   213  
   214  		if isSkeleton && component.Extensions.BigBang != nil {
   215  			for _, valuesFile := range component.Extensions.BigBang.ValuesFiles {
   216  				suite.FileExists(filepath.Join(base, valuesFile))
   217  			}
   218  		}
   219  
   220  		for chartIdx, chart := range component.Charts {
   221  			if isSkeleton && chart.URL != "" {
   222  				continue
   223  			} else if isSkeleton {
   224  				dir := fmt.Sprintf("%s-%d", chart.Name, chartIdx)
   225  				suite.DirExists(filepath.Join(componentPaths.Charts, dir))
   226  				continue
   227  			}
   228  			tgz := fmt.Sprintf("%s-%s.tgz", chart.Name, chart.Version)
   229  			suite.FileExists(filepath.Join(componentPaths.Charts, tgz))
   230  		}
   231  
   232  		for filesIdx, file := range component.Files {
   233  			if isSkeleton && helpers.IsURL(file.Source) {
   234  				continue
   235  			} else if isSkeleton {
   236  				suite.FileExists(filepath.Join(base, file.Source))
   237  				continue
   238  			}
   239  			path := filepath.Join(componentPaths.Files, strconv.Itoa(filesIdx), filepath.Base(file.Target))
   240  			suite.DirOrFileExists(path)
   241  		}
   242  
   243  		for dataIdx, data := range component.DataInjections {
   244  			if isSkeleton && helpers.IsURL(data.Source) {
   245  				continue
   246  			} else if isSkeleton {
   247  				suite.DirOrFileExists(filepath.Join(base, data.Source))
   248  				continue
   249  			}
   250  			path := filepath.Join(componentPaths.DataInjections, strconv.Itoa(dataIdx), filepath.Base(data.Target.Path))
   251  			suite.DirOrFileExists(path)
   252  		}
   253  
   254  		for _, manifest := range component.Manifests {
   255  			if isSkeleton {
   256  				suite.Nil(manifest.Kustomizations)
   257  			}
   258  			for filesIdx, path := range manifest.Files {
   259  				if isSkeleton && helpers.IsURL(path) {
   260  					continue
   261  				} else if isSkeleton {
   262  					suite.FileExists(filepath.Join(base, path))
   263  					continue
   264  				}
   265  				suite.FileExists(filepath.Join(componentPaths.Manifests, fmt.Sprintf("%s-%d.yaml", manifest.Name, filesIdx)))
   266  			}
   267  			for kustomizeIdx := range manifest.Kustomizations {
   268  				path := filepath.Join(componentPaths.Manifests, fmt.Sprintf("kustomization-%s-%d.yaml", manifest.Name, kustomizeIdx))
   269  				suite.FileExists(path)
   270  			}
   271  		}
   272  
   273  		if !isSkeleton {
   274  			for _, repo := range component.Repos {
   275  				dir, err := transform.GitURLtoFolderName(repo)
   276  				suite.NoError(err)
   277  				suite.DirExists(filepath.Join(componentPaths.Repos, dir))
   278  			}
   279  		}
   280  	}
   281  
   282  }
   283  
   284  func TestSkeletonSuite(t *testing.T) {
   285  	e2e.SetupWithCluster(t)
   286  
   287  	suite.Run(t, new(SkeletonSuite))
   288  }