github.com/stefanmcshane/helm@v0.0.0-20221213002717-88a4a2c6e77d/pkg/lint/rules/values_test.go (about)

     1  /*
     2  Copyright The Helm 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 rules
    18  
    19  import (
    20  	"io/ioutil"
    21  	"os"
    22  	"path/filepath"
    23  	"testing"
    24  
    25  	"github.com/stretchr/testify/assert"
    26  
    27  	"github.com/stefanmcshane/helm/internal/test/ensure"
    28  )
    29  
    30  var nonExistingValuesFilePath = filepath.Join("/fake/dir", "values.yaml")
    31  
    32  const testSchema = `
    33  {
    34    "$schema": "http://json-schema.org/draft-07/schema#",
    35    "title": "helm values test schema",
    36    "type": "object",
    37    "additionalProperties": false,
    38    "required": [
    39      "username",
    40      "password"
    41    ],
    42    "properties": {
    43      "username": {
    44        "description": "Your username",
    45        "type": "string"
    46      },
    47      "password": {
    48        "description": "Your password",
    49        "type": "string"
    50      }
    51    }
    52  }
    53  `
    54  
    55  func TestValidateValuesYamlNotDirectory(t *testing.T) {
    56  	_ = os.Mkdir(nonExistingValuesFilePath, os.ModePerm)
    57  	defer os.Remove(nonExistingValuesFilePath)
    58  
    59  	err := validateValuesFileExistence(nonExistingValuesFilePath)
    60  	if err == nil {
    61  		t.Errorf("validateValuesFileExistence to return a linter error, got no error")
    62  	}
    63  }
    64  
    65  func TestValidateValuesFileWellFormed(t *testing.T) {
    66  	badYaml := `
    67  	not:well[]{}formed
    68  	`
    69  	tmpdir := ensure.TempFile(t, "values.yaml", []byte(badYaml))
    70  	defer os.RemoveAll(tmpdir)
    71  	valfile := filepath.Join(tmpdir, "values.yaml")
    72  	if err := validateValuesFile(valfile, map[string]interface{}{}); err == nil {
    73  		t.Fatal("expected values file to fail parsing")
    74  	}
    75  }
    76  
    77  func TestValidateValuesFileSchema(t *testing.T) {
    78  	yaml := "username: admin\npassword: swordfish"
    79  	tmpdir := ensure.TempFile(t, "values.yaml", []byte(yaml))
    80  	defer os.RemoveAll(tmpdir)
    81  	createTestingSchema(t, tmpdir)
    82  
    83  	valfile := filepath.Join(tmpdir, "values.yaml")
    84  	if err := validateValuesFile(valfile, map[string]interface{}{}); err != nil {
    85  		t.Fatalf("Failed validation with %s", err)
    86  	}
    87  }
    88  
    89  func TestValidateValuesFileSchemaFailure(t *testing.T) {
    90  	// 1234 is an int, not a string. This should fail.
    91  	yaml := "username: 1234\npassword: swordfish"
    92  	tmpdir := ensure.TempFile(t, "values.yaml", []byte(yaml))
    93  	defer os.RemoveAll(tmpdir)
    94  	createTestingSchema(t, tmpdir)
    95  
    96  	valfile := filepath.Join(tmpdir, "values.yaml")
    97  
    98  	err := validateValuesFile(valfile, map[string]interface{}{})
    99  	if err == nil {
   100  		t.Fatal("expected values file to fail parsing")
   101  	}
   102  
   103  	assert.Contains(t, err.Error(), "Expected: string, given: integer", "integer should be caught by schema")
   104  }
   105  
   106  func TestValidateValuesFileSchemaOverrides(t *testing.T) {
   107  	yaml := "username: admin"
   108  	overrides := map[string]interface{}{
   109  		"password": "swordfish",
   110  	}
   111  	tmpdir := ensure.TempFile(t, "values.yaml", []byte(yaml))
   112  	defer os.RemoveAll(tmpdir)
   113  	createTestingSchema(t, tmpdir)
   114  
   115  	valfile := filepath.Join(tmpdir, "values.yaml")
   116  	if err := validateValuesFile(valfile, overrides); err != nil {
   117  		t.Fatalf("Failed validation with %s", err)
   118  	}
   119  }
   120  
   121  func TestValidateValuesFile(t *testing.T) {
   122  	tests := []struct {
   123  		name         string
   124  		yaml         string
   125  		overrides    map[string]interface{}
   126  		errorMessage string
   127  	}{
   128  		{
   129  			name:      "value added",
   130  			yaml:      "username: admin",
   131  			overrides: map[string]interface{}{"password": "swordfish"},
   132  		},
   133  		{
   134  			name:         "value not overridden",
   135  			yaml:         "username: admin\npassword:",
   136  			overrides:    map[string]interface{}{"username": "anotherUser"},
   137  			errorMessage: "Expected: string, given: null",
   138  		},
   139  		{
   140  			name:      "value overridden",
   141  			yaml:      "username: admin\npassword:",
   142  			overrides: map[string]interface{}{"username": "anotherUser", "password": "swordfish"},
   143  		},
   144  	}
   145  
   146  	for _, tt := range tests {
   147  		t.Run(tt.name, func(t *testing.T) {
   148  			tmpdir := ensure.TempFile(t, "values.yaml", []byte(tt.yaml))
   149  			defer os.RemoveAll(tmpdir)
   150  			createTestingSchema(t, tmpdir)
   151  
   152  			valfile := filepath.Join(tmpdir, "values.yaml")
   153  
   154  			err := validateValuesFile(valfile, tt.overrides)
   155  
   156  			switch {
   157  			case err != nil && tt.errorMessage == "":
   158  				t.Errorf("Failed validation with %s", err)
   159  			case err == nil && tt.errorMessage != "":
   160  				t.Error("expected values file to fail parsing")
   161  			case err != nil && tt.errorMessage != "":
   162  				assert.Contains(t, err.Error(), tt.errorMessage, "Failed with unexpected error")
   163  			}
   164  		})
   165  	}
   166  }
   167  
   168  func createTestingSchema(t *testing.T, dir string) string {
   169  	t.Helper()
   170  	schemafile := filepath.Join(dir, "values.schema.json")
   171  	if err := ioutil.WriteFile(schemafile, []byte(testSchema), 0700); err != nil {
   172  		t.Fatalf("Failed to write schema to tmpdir: %s", err)
   173  	}
   174  	return schemafile
   175  }