You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
helm/pkg/chartutil/save_test.go

247 lines
6.1 KiB

/*
Copyright The Helm Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package chartutil
import (
"archive/tar"
"bytes"
"compress/gzip"
"io"
"io/ioutil"
"os"
"path"
"path/filepath"
"regexp"
"strings"
"testing"
"time"
"helm.sh/helm/v3/internal/test/ensure"
"helm.sh/helm/v3/pkg/chart"
"helm.sh/helm/v3/pkg/chart/loader"
)
func TestSave(t *testing.T) {
tmp := ensure.TempDir(t)
defer os.RemoveAll(tmp)
for _, dest := range []string{tmp, path.Join(tmp, "newdir")} {
t.Run("outDir="+dest, func(t *testing.T) {
c := &chart.Chart{
Metadata: &chart.Metadata{
APIVersion: chart.APIVersionV1,
Name: "ahab",
Version: "1.2.3",
},
Lock: &chart.Lock{
Digest: "testdigest",
},
Files: []*chart.File{
{Name: "scheherazade/shahryar.txt", Data: []byte("1,001 Nights")},
},
Schema: []byte("{\n \"title\": \"Values\"\n}"),
}
chartWithInvalidJSON := withSchema(*c, []byte("{"))
where, err := Save(c, dest)
if err != nil {
t.Fatalf("Failed to save: %s", err)
}
if !strings.HasPrefix(where, dest) {
t.Fatalf("Expected %q to start with %q", where, dest)
}
if !strings.HasSuffix(where, ".tgz") {
t.Fatalf("Expected %q to end with .tgz", where)
}
c2, err := loader.LoadFile(where)
if err != nil {
t.Fatal(err)
}
if c2.Name() != c.Name() {
t.Fatalf("Expected chart archive to have %q, got %q", c.Name(), c2.Name())
}
if len(c2.Files) != 1 || c2.Files[0].Name != "scheherazade/shahryar.txt" {
t.Fatal("Files data did not match")
}
if c2.Lock != nil {
t.Fatal("Expected v1 chart archive not to contain Chart.lock file")
}
if !bytes.Equal(c.Schema, c2.Schema) {
indentation := 4
formattedExpected := Indent(indentation, string(c.Schema))
formattedActual := Indent(indentation, string(c2.Schema))
t.Fatalf("Schema data did not match.\nExpected:\n%s\nActual:\n%s", formattedExpected, formattedActual)
}
if _, err := Save(&chartWithInvalidJSON, dest); err == nil {
t.Fatalf("Invalid JSON was not caught while saving chart")
}
c.Metadata.APIVersion = chart.APIVersionV2
where, err = Save(c, dest)
if err != nil {
t.Fatalf("Failed to save: %s", err)
}
c2, err = loader.LoadFile(where)
if err != nil {
t.Fatal(err)
}
if c2.Lock == nil {
chore: Spelling (#9410) * spelling: annotate Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: asserts Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: behavior Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: binary Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: contain Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: copied Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: dependency Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: depending Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: deprecated Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: doesn't Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: donot Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: github Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: inputting Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: iteration Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: jabberwocky Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: kubernetes Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: length Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: mismatch Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: multiple Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: nonexistent Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: outputs Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: panicking Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: plugins Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: parsing Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: porthos Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: regular Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: resource Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: repositories Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: something Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: strict Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: string Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: unknown Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>
4 years ago
t.Fatal("Expected v2 chart archive to contain a Chart.lock file")
}
if c2.Lock.Digest != c.Lock.Digest {
t.Fatal("Chart.lock data did not match")
}
})
}
}
// Creates a copy with a different schema; does not modify anything.
func withSchema(chart chart.Chart, schema []byte) chart.Chart {
chart.Schema = schema
return chart
}
func Indent(n int, text string) string {
startOfLine := regexp.MustCompile(`(?m)^`)
indentation := strings.Repeat(" ", n)
return startOfLine.ReplaceAllLiteralString(text, indentation)
}
func TestSavePreservesTimestamps(t *testing.T) {
// Test executes so quickly that if we don't subtract a second, the
// check will fail because `initialCreateTime` will be identical to the
// written timestamp for the files.
initialCreateTime := time.Now().Add(-1 * time.Second)
tmp, err := ioutil.TempDir("", "helm-")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmp)
c := &chart.Chart{
Metadata: &chart.Metadata{
APIVersion: chart.APIVersionV1,
Name: "ahab",
Version: "1.2.3",
},
Values: map[string]interface{}{
"imageName": "testimage",
"imageId": 42,
},
Files: []*chart.File{
{Name: "scheherazade/shahryar.txt", Data: []byte("1,001 Nights")},
},
Schema: []byte("{\n \"title\": \"Values\"\n}"),
}
where, err := Save(c, tmp)
if err != nil {
t.Fatalf("Failed to save: %s", err)
}
allHeaders, err := retrieveAllHeadersFromTar(where)
if err != nil {
t.Fatalf("Failed to parse tar: %v", err)
}
for _, header := range allHeaders {
if header.ModTime.Before(initialCreateTime) {
t.Fatalf("File timestamp not preserved: %v", header.ModTime)
}
}
}
// We could refactor `load.go` to use this `retrieveAllHeadersFromTar` function
// as well, so we are not duplicating components of the code which iterate
// through the tar.
func retrieveAllHeadersFromTar(path string) ([]*tar.Header, error) {
raw, err := os.Open(path)
if err != nil {
return nil, err
}
defer raw.Close()
unzipped, err := gzip.NewReader(raw)
if err != nil {
return nil, err
}
defer unzipped.Close()
tr := tar.NewReader(unzipped)
headers := []*tar.Header{}
for {
hd, err := tr.Next()
if err == io.EOF {
break
}
if err != nil {
return nil, err
}
headers = append(headers, hd)
}
return headers, nil
}
func TestSaveDir(t *testing.T) {
tmp, err := ioutil.TempDir("", "helm-")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmp)
c := &chart.Chart{
Metadata: &chart.Metadata{
APIVersion: chart.APIVersionV1,
Name: "ahab",
Version: "1.2.3",
},
Files: []*chart.File{
{Name: "scheherazade/shahryar.txt", Data: []byte("1,001 Nights")},
},
Templates: []*chart.File{
{Name: filepath.Join(TemplatesDir, "nested", "dir", "thing.yaml"), Data: []byte("abc: {{ .Values.abc }}")},
},
}
if err := SaveDir(c, tmp); err != nil {
t.Fatalf("Failed to save: %s", err)
}
c2, err := loader.LoadDir(tmp + "/ahab")
if err != nil {
t.Fatal(err)
}
if c2.Name() != c.Name() {
t.Fatalf("Expected chart archive to have %q, got %q", c.Name(), c2.Name())
}
if len(c2.Templates) != 1 || c2.Templates[0].Name != filepath.Join(TemplatesDir, "nested", "dir", "thing.yaml") {
t.Fatal("Templates data did not match")
}
if len(c2.Files) != 1 || c2.Files[0].Name != "scheherazade/shahryar.txt" {
t.Fatal("Files data did not match")
}
}