get.porter.sh/porter@v1.3.0/tests/integration/schema_test.go (about)

     1  //go:build integration
     2  
     3  package integration
     4  
     5  import (
     6  	"os"
     7  	"path/filepath"
     8  	"strings"
     9  	"testing"
    10  
    11  	"get.porter.sh/porter/pkg/config"
    12  	"get.porter.sh/porter/pkg/manifest"
    13  	testhelper "get.porter.sh/porter/pkg/test"
    14  	"get.porter.sh/porter/pkg/yaml"
    15  	"get.porter.sh/porter/tests"
    16  	"get.porter.sh/porter/tests/tester"
    17  	"github.com/stretchr/testify/assert"
    18  	"github.com/stretchr/testify/require"
    19  	"github.com/xeipuuv/gojsonschema"
    20  )
    21  
    22  // Validates how porter integrates the mixin schema into porter's base schema to generate the final content for
    23  // the porter schema command
    24  func TestSchema(t *testing.T) {
    25  	test, err := tester.NewTest(t)
    26  	defer test.Close()
    27  	require.NoError(t, err, "test setup failed")
    28  
    29  	// Only use a well-known set of mixin in our home directory so that the schema is consistent
    30  	mixinsDir := filepath.Join(test.PorterHomeDir, "mixins")
    31  	mixins, err := os.ReadDir(mixinsDir)
    32  	for _, mixinDir := range mixins {
    33  		mixinName := mixinDir.Name()
    34  		if mixinName != "exec" && mixinName != "testmixin" {
    35  			require.NoError(t, os.RemoveAll(filepath.Join(mixinsDir, mixinName)))
    36  		}
    37  	}
    38  
    39  	// Validate that the schema matches what we expected
    40  	gotSchema, _ := test.RequirePorter("schema")
    41  	testhelper.CompareGoldenFile(t, "testdata/schema/schema.json", gotSchema)
    42  
    43  	testManifests := []struct {
    44  		name    string
    45  		path    string
    46  		wantErr string
    47  	}{
    48  		{name: "valid", path: filepath.Join(test.RepoRoot, "tests/testdata/mybuns/porter.yaml")},
    49  		{name: "invalid mixin declarations", path: "testdata/schema/invalid_mixin_config.yaml",
    50  			wantErr: `mixins.1: mixins.1 must be one of the following: "exec", "testmixin"
    51  mixins.2: Must validate one and only one schema (oneOf)
    52  mixins.2.testmixin: Additional property missingproperty is not allowed`},
    53  	}
    54  
    55  	// Validate each manifest against the schema
    56  	for _, tm := range testManifests {
    57  		t.Run(tm.name, func(t *testing.T) {
    58  			// Load the manifest as a go dump
    59  			testManifestPath := tm.path
    60  			mani, err := manifest.ReadManifest(test.TestContext.Context, testManifestPath, config.NewTestConfig(t).Config)
    61  
    62  			maniYaml, err := yaml.Marshal(mani)
    63  			require.NoError(t, err, "error marshaling manifest to yaml")
    64  
    65  			m := make(map[string]interface{})
    66  			err = yaml.Unmarshal(maniYaml, &m)
    67  			require.NoError(t, err, "failed to unmarshal %s", testManifestPath)
    68  
    69  			// Load the manifest schema returned from `porter schema`
    70  			manifestLoader := gojsonschema.NewGoLoader(m)
    71  			schemaLoader := gojsonschema.NewStringLoader(gotSchema)
    72  
    73  			// Validate the manifest against the schema
    74  			fails, err := gojsonschema.Validate(schemaLoader, manifestLoader)
    75  			require.NoError(t, err)
    76  
    77  			if tm.wantErr == "" {
    78  				assert.Empty(t, fails.Errors(), "expected %s to validate against the porter schema", testManifestPath)
    79  				// Print any validation errors returned
    80  				for _, err := range fails.Errors() {
    81  					t.Logf("%s", err)
    82  				}
    83  			} else {
    84  				var allFails strings.Builder
    85  				for _, err := range fails.Errors() {
    86  					allFails.WriteString(err.String())
    87  					allFails.WriteString("\n")
    88  				}
    89  				tests.RequireOutputContains(t, allFails.String(), tm.wantErr)
    90  			}
    91  		})
    92  	}
    93  }