mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-05-17 18:25:26 +00:00
262 lines
6.9 KiB
Go
262 lines
6.9 KiB
Go
// Copyright 2019 The Kubernetes Authors.
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package kusttest_test
|
|
|
|
import (
|
|
"fmt"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
|
|
"sigs.k8s.io/kustomize/v3/api/internal/loadertest"
|
|
"sigs.k8s.io/kustomize/v3/api/k8sdeps/kunstruct"
|
|
"sigs.k8s.io/kustomize/v3/api/k8sdeps/transformer"
|
|
fLdr "sigs.k8s.io/kustomize/v3/api/loader"
|
|
"sigs.k8s.io/kustomize/v3/api/pgmconfig"
|
|
"sigs.k8s.io/kustomize/v3/api/plugins/builtinconfig/consts"
|
|
"sigs.k8s.io/kustomize/v3/api/plugins/config"
|
|
pLdr "sigs.k8s.io/kustomize/v3/api/plugins/loader"
|
|
"sigs.k8s.io/kustomize/v3/api/resmap"
|
|
"sigs.k8s.io/kustomize/v3/api/resource"
|
|
"sigs.k8s.io/kustomize/v3/api/target"
|
|
"sigs.k8s.io/kustomize/v3/api/testutils/valtest"
|
|
"sigs.k8s.io/kustomize/v3/api/types"
|
|
)
|
|
|
|
// KustTestHarness is an environment for running a kustomize build,
|
|
// aka a run of MakeCustomizedResMap. It holds a file loader
|
|
// presumably primed with an in-memory file system, a plugin
|
|
// loader, factories to make what it needs, etc.
|
|
type KustTestHarness struct {
|
|
t *testing.T
|
|
rf *resmap.Factory
|
|
ldr loadertest.FakeLoader
|
|
pl *pLdr.Loader
|
|
}
|
|
|
|
func NewKustTestHarness(t *testing.T, path string) *KustTestHarness {
|
|
return NewKustTestHarnessFull(
|
|
t, path, fLdr.RestrictionRootOnly, config.DefaultPluginConfig())
|
|
}
|
|
|
|
func NewKustTestHarnessAllowPlugins(t *testing.T, path string) *KustTestHarness {
|
|
return NewKustTestHarnessFull(
|
|
t, path, fLdr.RestrictionRootOnly, config.ActivePluginConfig())
|
|
}
|
|
|
|
func NewKustTestHarnessNoLoadRestrictor(t *testing.T, path string) *KustTestHarness {
|
|
return NewKustTestHarnessFull(
|
|
t, path, fLdr.RestrictionNone, config.DefaultPluginConfig())
|
|
}
|
|
|
|
func NewKustTestHarnessFull(
|
|
t *testing.T, path string,
|
|
lr fLdr.LoadRestrictorFunc, pc *types.PluginConfig) *KustTestHarness {
|
|
rf := resmap.NewFactory(resource.NewFactory(
|
|
kunstruct.NewKunstructuredFactoryImpl()), transformer.NewFactoryImpl())
|
|
return &KustTestHarness{
|
|
t: t,
|
|
rf: rf,
|
|
ldr: loadertest.NewFakeLoaderWithRestrictor(lr, path),
|
|
pl: pLdr.NewLoader(pc, rf)}
|
|
}
|
|
|
|
func (th *KustTestHarness) MakeKustTarget() *target.KustTarget {
|
|
kt, err := target.NewKustTarget(
|
|
th.ldr, valtest_test.MakeFakeValidator(), th.rf,
|
|
transformer.NewFactoryImpl(), th.pl)
|
|
if err != nil {
|
|
th.t.Fatalf("Unexpected construction error %v", err)
|
|
}
|
|
return kt
|
|
}
|
|
|
|
func (th *KustTestHarness) WriteF(dir string, content string) {
|
|
err := th.ldr.AddFile(dir, []byte(content))
|
|
if err != nil {
|
|
th.t.Fatalf("failed write to %s; %v", dir, err)
|
|
}
|
|
}
|
|
|
|
func (th *KustTestHarness) WriteK(dir string, content string) {
|
|
th.WriteF(
|
|
filepath.Join(
|
|
dir,
|
|
pgmconfig.DefaultKustomizationFileName()), `
|
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
|
kind: Kustomization
|
|
`+content)
|
|
}
|
|
|
|
func (th *KustTestHarness) RF() *resource.Factory {
|
|
return th.rf.RF()
|
|
}
|
|
|
|
func (th *KustTestHarness) FromMap(m map[string]interface{}) *resource.Resource {
|
|
return th.rf.RF().FromMap(m)
|
|
}
|
|
|
|
func (th *KustTestHarness) FromMapAndOption(m map[string]interface{}, args *types.GeneratorArgs, option *types.GeneratorOptions) *resource.Resource {
|
|
return th.rf.RF().FromMapAndOption(m, args, option)
|
|
}
|
|
|
|
func (th *KustTestHarness) WriteDefaultConfigs(fName string) {
|
|
m := consts.GetDefaultFieldSpecsAsMap()
|
|
var content []byte
|
|
for _, tCfg := range m {
|
|
content = append(content, []byte(tCfg)...)
|
|
}
|
|
err := th.ldr.AddFile(fName, content)
|
|
if err != nil {
|
|
th.t.Fatalf("unable to add file %s", fName)
|
|
}
|
|
}
|
|
|
|
func (th *KustTestHarness) LoadAndRunGenerator(
|
|
config string) resmap.ResMap {
|
|
res, err := th.rf.RF().FromBytes([]byte(config))
|
|
if err != nil {
|
|
th.t.Fatalf("Err: %v", err)
|
|
}
|
|
g, err := th.pl.LoadGenerator(
|
|
th.ldr, valtest_test.MakeFakeValidator(), res)
|
|
if err != nil {
|
|
th.t.Fatalf("Err: %v", err)
|
|
}
|
|
rm, err := g.Generate()
|
|
if err != nil {
|
|
th.t.Fatalf("Err: %v", err)
|
|
}
|
|
return rm
|
|
}
|
|
|
|
func (th *KustTestHarness) LoadAndRunTransformer(
|
|
config, input string) resmap.ResMap {
|
|
resMap, err := th.RunTransformer(config, input)
|
|
if err != nil {
|
|
th.t.Fatalf("Err: %v", err)
|
|
}
|
|
return resMap
|
|
}
|
|
|
|
func (th *KustTestHarness) ErrorFromLoadAndRunTransformer(
|
|
config, input string) error {
|
|
_, err := th.RunTransformer(config, input)
|
|
return err
|
|
}
|
|
|
|
func (th *KustTestHarness) RunTransformer(
|
|
config, input string) (resmap.ResMap, error) {
|
|
resMap, err := th.rf.NewResMapFromBytes([]byte(input))
|
|
if err != nil {
|
|
th.t.Fatalf("Err: %v", err)
|
|
}
|
|
return th.RunTransformerFromResMap(config, resMap)
|
|
}
|
|
|
|
func (th *KustTestHarness) RunTransformerFromResMap(
|
|
config string, resMap resmap.ResMap) (resmap.ResMap, error) {
|
|
transConfig, err := th.rf.RF().FromBytes([]byte(config))
|
|
if err != nil {
|
|
th.t.Fatalf("Err: %v", err)
|
|
}
|
|
g, err := th.pl.LoadTransformer(
|
|
th.ldr, valtest_test.MakeFakeValidator(), transConfig)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
err = g.Transform(resMap)
|
|
return resMap, err
|
|
}
|
|
|
|
func tabToSpace(input string) string {
|
|
var result []string
|
|
for _, i := range input {
|
|
if i == 9 {
|
|
result = append(result, " ")
|
|
} else {
|
|
result = append(result, string(i))
|
|
}
|
|
}
|
|
return strings.Join(result, "")
|
|
}
|
|
|
|
func convertToArray(x string) ([]string, int) {
|
|
a := strings.Split(strings.TrimSuffix(x, "\n"), "\n")
|
|
maxLen := 0
|
|
for i, v := range a {
|
|
z := tabToSpace(v)
|
|
if len(z) > maxLen {
|
|
maxLen = len(z)
|
|
}
|
|
a[i] = z
|
|
}
|
|
return a, maxLen
|
|
}
|
|
|
|
func hint(a, b string) string {
|
|
if a == b {
|
|
return " "
|
|
}
|
|
return "X"
|
|
}
|
|
|
|
func (th *KustTestHarness) AssertActualEqualsExpected(
|
|
m resmap.ResMap, expected string) {
|
|
th.AssertActualEqualsExpectedWithTweak(m, nil, expected)
|
|
}
|
|
|
|
func (th *KustTestHarness) AssertActualEqualsExpectedWithTweak(
|
|
m resmap.ResMap, tweaker func([]byte) []byte, expected string) {
|
|
if m == nil {
|
|
th.t.Fatalf("Map should not be nil.")
|
|
}
|
|
// Ignore leading linefeed in expected value
|
|
// to ease readability of tests.
|
|
if len(expected) > 0 && expected[0] == 10 {
|
|
expected = expected[1:]
|
|
}
|
|
actual, err := m.AsYaml()
|
|
if err != nil {
|
|
th.t.Fatalf("Unexpected err: %v", err)
|
|
}
|
|
if tweaker != nil {
|
|
actual = tweaker(actual)
|
|
}
|
|
if string(actual) != expected {
|
|
th.reportDiffAndFail(actual, expected)
|
|
}
|
|
}
|
|
|
|
// Pretty printing of file differences.
|
|
func (th *KustTestHarness) reportDiffAndFail(actual []byte, expected string) {
|
|
sE, maxLen := convertToArray(expected)
|
|
sA, _ := convertToArray(string(actual))
|
|
fmt.Println("===== ACTUAL BEGIN ========================================")
|
|
fmt.Print(string(actual))
|
|
fmt.Println("===== ACTUAL END ==========================================")
|
|
format := fmt.Sprintf("%%s %%-%ds %%s\n", maxLen+4)
|
|
limit := 0
|
|
if len(sE) < len(sA) {
|
|
limit = len(sE)
|
|
} else {
|
|
limit = len(sA)
|
|
}
|
|
fmt.Printf(format, " ", "EXPECTED", "ACTUAL")
|
|
fmt.Printf(format, " ", "--------", "------")
|
|
for i := 0; i < limit; i++ {
|
|
fmt.Printf(format, hint(sE[i], sA[i]), sE[i], sA[i])
|
|
}
|
|
if len(sE) < len(sA) {
|
|
for i := len(sE); i < len(sA); i++ {
|
|
fmt.Printf(format, "X", "", sA[i])
|
|
}
|
|
} else {
|
|
for i := len(sA); i < len(sE); i++ {
|
|
fmt.Printf(format, "X", sE[i], "")
|
|
}
|
|
}
|
|
th.t.Fatalf("Expected not equal to actual")
|
|
}
|