Consolidate test harness to one package.

This commit is contained in:
Jeffrey Regan
2019-12-02 09:28:50 -08:00
parent ce935448c1
commit 382c330f5b
64 changed files with 676 additions and 710 deletions

View File

@@ -0,0 +1,126 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package kusttest_test
import (
"path/filepath"
"strings"
"testing"
"sigs.k8s.io/kustomize/api/filesys"
"sigs.k8s.io/kustomize/api/konfig"
"sigs.k8s.io/kustomize/api/konfig/builtinpluginconsts"
"sigs.k8s.io/kustomize/api/krusty"
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/types"
)
// Harness manages a kustomize environment for tests.
type Harness struct {
t *testing.T
fSys filesys.FileSystem
}
func MakeHarness(t *testing.T) Harness {
return MakeHarnessWithFs(t, filesys.MakeFsInMemory())
}
func MakeHarnessWithFs(
t *testing.T, fSys filesys.FileSystem) Harness {
return Harness{
t: t,
fSys: fSys,
}
}
func (th Harness) GetT() *testing.T {
return th.t
}
func (th Harness) GetFSys() filesys.FileSystem {
return th.fSys
}
func (th Harness) WriteK(path string, content string) {
th.fSys.WriteFile(
filepath.Join(
path,
konfig.DefaultKustomizationFileName()), []byte(`
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
`+content))
}
func (th Harness) WriteF(path string, content string) {
th.fSys.WriteFile(path, []byte(content))
}
func (th Harness) MakeDefaultOptions() krusty.Options {
return th.MakeOptionsPluginsDisabled()
}
// This has no impact on Builtin plugins, as they are always enabled.
func (th Harness) MakeOptionsPluginsDisabled() krusty.Options {
return krusty.Options{
LoadRestrictions: types.LoadRestrictionsRootOnly,
PluginConfig: konfig.DisabledPluginConfig(),
}
}
// Enables use of non-builtin plugins.
func (th Harness) MakeOptionsPluginsEnabled() krusty.Options {
c, err := konfig.EnabledPluginConfig()
if err != nil {
if strings.Contains(err.Error(), "unable to find plugin root") {
th.t.Log(
"Tests that want to run with plugins enabled must be " +
"bookended by calls to NewPluginTestEnv.Set(), Reset().")
}
th.t.Fatal(err)
}
return krusty.Options{
LoadRestrictions: types.LoadRestrictionsRootOnly,
PluginConfig: c,
}
}
// Run, failing on error.
func (th Harness) Run(path string, o krusty.Options) resmap.ResMap {
m, err := krusty.MakeKustomizer(th.fSys, &o).Run(path)
if err != nil {
th.t.Fatal(err)
}
return m
}
// Run, failing if there is no error.
func (th Harness) RunWithErr(path string, o krusty.Options) error {
_, err := krusty.MakeKustomizer(th.fSys, &o).Run(path)
if err == nil {
th.t.Fatalf("expected error")
}
return err
}
func (th Harness) WriteLegacyConfigs(fName string) {
m := builtinpluginconsts.GetDefaultFieldSpecsAsMap()
var content []byte
for _, tCfg := range m {
content = append(content, []byte(tCfg)...)
}
err := th.fSys.WriteFile(fName, content)
if err != nil {
th.t.Fatalf("unable to add file %s", fName)
}
}
func (th Harness) AssertActualEqualsExpected(
m resmap.ResMap, expected string) {
th.AssertActualEqualsExpectedWithTweak(m, nil, expected)
}
func (th Harness) AssertActualEqualsExpectedWithTweak(
m resmap.ResMap, tweaker func([]byte) []byte, expected string) {
assertActualEqualsExpectedWithTweak(th, m, tweaker, expected)
}

View File

@@ -0,0 +1,104 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package kusttest_test
import (
"testing"
"sigs.k8s.io/kustomize/api/filesys"
"sigs.k8s.io/kustomize/api/internal/k8sdeps/transformer"
"sigs.k8s.io/kustomize/api/internal/loadertest"
pLdr "sigs.k8s.io/kustomize/api/internal/plugins/loader"
"sigs.k8s.io/kustomize/api/k8sdeps/kunstruct"
"sigs.k8s.io/kustomize/api/konfig"
fLdr "sigs.k8s.io/kustomize/api/loader"
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/resource"
valtest_test "sigs.k8s.io/kustomize/api/testutils/valtest"
)
// HarnessEnhanced manages a full plugin environment for tests.
// TODO: get rid of this. Combine Harness and PluginTestEnv.
type HarnessEnhanced struct {
Harness
rf *resmap.Factory
ldr loadertest.FakeLoader
pl *pLdr.Loader
}
func MakeHarnessEnhanced(
t *testing.T, path string) *HarnessEnhanced {
pc, err := konfig.EnabledPluginConfig()
if err != nil {
t.Fatal(err)
}
fSys := filesys.MakeFsInMemory()
rf := resmap.NewFactory(
resource.NewFactory(kunstruct.NewKunstructuredFactoryImpl()),
transformer.NewFactoryImpl())
return &HarnessEnhanced{
Harness: Harness{t: t, fSys: fSys},
rf: rf,
ldr: loadertest.NewFakeLoaderWithRestrictor(
fLdr.RestrictionRootOnly, fSys, path),
pl: pLdr.NewLoader(pc, rf)}
}
func (th *HarnessEnhanced) 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 *HarnessEnhanced) 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 *HarnessEnhanced) ErrorFromLoadAndRunTransformer(
config, input string) error {
_, err := th.RunTransformer(config, input)
return err
}
func (th *HarnessEnhanced) 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 *HarnessEnhanced) 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
}

View File

@@ -0,0 +1,104 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package kusttest_test
import (
"fmt"
"strings"
"testing"
"sigs.k8s.io/kustomize/api/resmap"
)
type hasGetT interface {
GetT() *testing.T
}
func assertActualEqualsExpectedWithTweak(
ht hasGetT,
m resmap.ResMap,
tweaker func([]byte) []byte, expected string) {
if m == nil {
ht.GetT().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 {
ht.GetT().Fatalf("Unexpected err: %v", err)
}
if tweaker != nil {
actual = tweaker(actual)
}
if string(actual) != expected {
reportDiffAndFail(ht.GetT(), actual, expected)
}
}
// Pretty printing of file differences.
func reportDiffAndFail(
t *testing.T, 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], "")
}
}
t.Fatalf("Expected not equal to actual")
}
func hint(a, b string) string {
if a == b {
return " "
}
return "X"
}
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 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, "")
}

View File

@@ -1,267 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package kusttest_test
import (
"fmt"
"path/filepath"
"strings"
"testing"
"sigs.k8s.io/kustomize/api/internal/k8sdeps/transformer"
"sigs.k8s.io/kustomize/api/internal/loadertest"
pLdr "sigs.k8s.io/kustomize/api/internal/plugins/loader"
"sigs.k8s.io/kustomize/api/internal/target"
"sigs.k8s.io/kustomize/api/k8sdeps/kunstruct"
"sigs.k8s.io/kustomize/api/konfig"
"sigs.k8s.io/kustomize/api/konfig/builtinpluginconsts"
fLdr "sigs.k8s.io/kustomize/api/loader"
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/resource"
valtest_test "sigs.k8s.io/kustomize/api/testutils/valtest"
"sigs.k8s.io/kustomize/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, konfig.DisabledPluginConfig())
}
func NewKustTestHarnessAllowPlugins(t *testing.T, path string) *KustTestHarness {
c, err := konfig.EnabledPluginConfig()
if err != nil {
t.Fatal(err)
}
return NewKustTestHarnessFull(t, path, fLdr.RestrictionRootOnly, c)
}
func NewKustTestHarnessNoLoadRestrictor(t *testing.T, path string) *KustTestHarness {
return NewKustTestHarnessFull(
t, path, fLdr.RestrictionNone, konfig.DisabledPluginConfig())
}
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 := target.NewKustTarget(
th.ldr, valtest_test.MakeFakeValidator(), th.rf,
transformer.NewFactoryImpl(), th.pl)
err := kt.Load()
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,
konfig.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 := builtinpluginconsts.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")
}