Start making examples more visible.

This commit is contained in:
jregan
2019-11-28 07:23:37 -08:00
parent fc92f4acd0
commit 89e7b76d48
4 changed files with 202 additions and 48 deletions

View File

@@ -0,0 +1,437 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package krusty_test
import (
"strings"
"testing"
. "sigs.k8s.io/kustomize/api/krusty"
"sigs.k8s.io/kustomize/api/types"
)
func TestOrderPreserved(t *testing.T) {
th := makeTestHarness(t)
th.WriteK("/app/base", `
namePrefix: b-
resources:
- namespace.yaml
- role.yaml
- service.yaml
- deployment.yaml
`)
th.WriteF("/app/base/service.yaml", `
apiVersion: v1
kind: Service
metadata:
name: myService
`)
th.WriteF("/app/base/namespace.yaml", `
apiVersion: v1
kind: Namespace
metadata:
name: myNs
`)
th.WriteF("/app/base/role.yaml", `
apiVersion: v1
kind: Role
metadata:
name: myRole
`)
th.WriteF("/app/base/deployment.yaml", `
apiVersion: v1
kind: Deployment
metadata:
name: myDep
`)
th.WriteK("/app/prod", `
namePrefix: p-
resources:
- ../base
- service.yaml
- namespace.yaml
`)
th.WriteF("/app/prod/service.yaml", `
apiVersion: v1
kind: Service
metadata:
name: myService2
`)
th.WriteF("/app/prod/namespace.yaml", `
apiVersion: v1
kind: Namespace
metadata:
name: myNs2
`)
m := th.Run("/app/prod", th.MakeDefaultOptions())
th.AssertActualEqualsExpected(m, `
apiVersion: v1
kind: Namespace
metadata:
name: p-b-myNs
---
apiVersion: v1
kind: Role
metadata:
name: p-b-myRole
---
apiVersion: v1
kind: Service
metadata:
name: p-b-myService
---
apiVersion: v1
kind: Deployment
metadata:
name: p-b-myDep
---
apiVersion: v1
kind: Service
metadata:
name: p-myService2
---
apiVersion: v1
kind: Namespace
metadata:
name: p-myNs2
`)
}
func TestBaseInResourceList(t *testing.T) {
th := makeTestHarness(t)
th.WriteK("/app/prod", `
namePrefix: b-
resources:
- ../base
`)
th.WriteK("/app/base", `
namePrefix: a-
resources:
- service.yaml
`)
th.WriteF("/app/base/service.yaml", `
apiVersion: v1
kind: Service
metadata:
name: myService
spec:
selector:
backend: bungie
`)
m := th.Run("/app/prod", th.MakeDefaultOptions())
th.AssertActualEqualsExpected(m, `
apiVersion: v1
kind: Service
metadata:
name: b-a-myService
spec:
selector:
backend: bungie
`)
}
func writeSmallBase(th testingHarness) {
th.WriteK("/app/base", `
namePrefix: a-
commonLabels:
app: myApp
resources:
- deployment.yaml
- service.yaml
`)
th.WriteF("/app/base/service.yaml", `
apiVersion: v1
kind: Service
metadata:
name: myService
spec:
selector:
backend: bungie
ports:
- port: 7002
`)
th.WriteF("/app/base/deployment.yaml", `
apiVersion: apps/v1
kind: Deployment
metadata:
name: myDeployment
spec:
template:
metadata:
labels:
backend: awesome
spec:
containers:
- name: whatever
image: whatever
`)
}
func TestSmallBase(t *testing.T) {
th := makeTestHarness(t)
writeSmallBase(th)
m := th.Run("/app/base", th.MakeDefaultOptions())
th.AssertActualEqualsExpected(m, `
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: myApp
name: a-myDeployment
spec:
selector:
matchLabels:
app: myApp
template:
metadata:
labels:
app: myApp
backend: awesome
spec:
containers:
- image: whatever
name: whatever
---
apiVersion: v1
kind: Service
metadata:
labels:
app: myApp
name: a-myService
spec:
ports:
- port: 7002
selector:
app: myApp
backend: bungie
`)
}
func TestSmallOverlay(t *testing.T) {
th := makeTestHarness(t)
writeSmallBase(th)
th.WriteK("/app/overlay", `
namePrefix: b-
commonLabels:
env: prod
resources:
- ../base
patchesStrategicMerge:
- deployment/deployment.yaml
images:
- name: whatever
newTag: 1.8.0
`)
th.WriteF("/app/overlay/configmap/app.env", `
DB_USERNAME=admin
DB_PASSWORD=somepw
`)
th.WriteF("/app/overlay/configmap/app-init.ini", `
FOO=bar
BAR=baz
`)
th.WriteF("/app/overlay/deployment/deployment.yaml", `
apiVersion: apps/v1
kind: Deployment
metadata:
name: myDeployment
spec:
replicas: 1000
`)
m := th.Run("/app/overlay", th.MakeDefaultOptions())
th.AssertActualEqualsExpected(m, `
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: myApp
env: prod
name: b-a-myDeployment
spec:
replicas: 1000
selector:
matchLabels:
app: myApp
env: prod
template:
metadata:
labels:
app: myApp
backend: awesome
env: prod
spec:
containers:
- image: whatever:1.8.0
name: whatever
---
apiVersion: v1
kind: Service
metadata:
labels:
app: myApp
env: prod
name: b-a-myService
spec:
ports:
- port: 7002
selector:
app: myApp
backend: bungie
env: prod
`)
}
func TestSharedPatchDisAllowed(t *testing.T) {
th := makeTestHarness(t)
writeSmallBase(th)
th.WriteK("/app/overlay", `
commonLabels:
env: prod
resources:
- ../base
patchesStrategicMerge:
- ../shared/deployment-patch.yaml
`)
th.WriteF("/app/shared/deployment-patch.yaml", `
apiVersion: apps/v1
kind: Deployment
metadata:
name: myDeployment
spec:
replicas: 1000
`)
err := th.RunWithErr("/app/overlay", func() Options {
o := th.MakeDefaultOptions()
o.LoadRestrictions = types.LoadRestrictionsRootOnly
return o
}())
if !strings.Contains(
err.Error(),
"security; file '/app/shared/deployment-patch.yaml' is not in or below '/app/overlay'") {
t.Fatalf("unexpected error: %s", err)
}
}
func TestSharedPatchAllowed(t *testing.T) {
th := makeTestHarness(t)
writeSmallBase(th)
th.WriteK("/app/overlay", `
commonLabels:
env: prod
resources:
- ../base
patchesStrategicMerge:
- ../shared/deployment-patch.yaml
`)
th.WriteF("/app/shared/deployment-patch.yaml", `
apiVersion: apps/v1
kind: Deployment
metadata:
name: myDeployment
spec:
replicas: 1000
`)
m := th.Run("/app/overlay", func() Options {
o := th.MakeDefaultOptions()
o.LoadRestrictions = types.LoadRestrictionsNone
return o
}())
th.AssertActualEqualsExpected(m, `
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: myApp
env: prod
name: a-myDeployment
spec:
replicas: 1000
selector:
matchLabels:
app: myApp
env: prod
template:
metadata:
labels:
app: myApp
backend: awesome
env: prod
spec:
containers:
- image: whatever
name: whatever
---
apiVersion: v1
kind: Service
metadata:
labels:
app: myApp
env: prod
name: a-myService
spec:
ports:
- port: 7002
selector:
app: myApp
backend: bungie
env: prod
`)
}
func TestSmallOverlayJSONPatch(t *testing.T) {
th := makeTestHarness(t)
writeSmallBase(th)
th.WriteK("/app/overlay", `
resources:
- ../base
patchesJson6902:
- target:
version: v1
kind: Service
name: a-myService
path: service-patch.yaml
`)
th.WriteF("/app/overlay/service-patch.yaml", `
- op: add
path: /spec/selector/backend
value: beagle
`)
m := th.Run("/app/overlay", th.MakeDefaultOptions())
th.AssertActualEqualsExpected(m, `
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: myApp
name: a-myDeployment
spec:
selector:
matchLabels:
app: myApp
template:
metadata:
labels:
app: myApp
backend: awesome
spec:
containers:
- image: whatever
name: whatever
---
apiVersion: v1
kind: Service
metadata:
labels:
app: myApp
name: a-myService
spec:
ports:
- port: 7002
selector:
app: myApp
backend: beagle
`)
}

View File

@@ -1,6 +1,11 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
// Package krusty holds a very high level API to kustomize.
// The functions here should be similar to the CLI api.
// Package krusty is intended as the entry point package
// for those seeking to add kustomize ability to other
// programs.
//
// To use, follow the example of the kustomize CLI's 'build'
// command. Also, see the high level tests in this package,
// which serve a dual purpose as examples.
package krusty

View File

@@ -22,7 +22,7 @@ import (
// performing an exec to a kustomize CLI subprocess.
// To use, load a filesystem with kustomization files (any
// number of overlays and bases), then make a Kustomizer
// injected with the given fileystem, then call Build.
// injected with the given fileystem, then call Run.
type Kustomizer struct {
fSys filesys.FileSystem
options *Options

View File

@@ -0,0 +1,168 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package krusty_test
import (
"fmt"
"path/filepath"
"strings"
"testing"
"sigs.k8s.io/kustomize/api/filesys"
"sigs.k8s.io/kustomize/api/konfig"
. "sigs.k8s.io/kustomize/api/krusty"
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/types"
)
type testingHarness struct {
t *testing.T
fSys filesys.FileSystem
}
func makeTestHarness(t *testing.T) testingHarness {
return testingHarness{
t: t,
fSys: filesys.MakeFsInMemory(),
}
}
func (th testingHarness) 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 testingHarness) WriteF(path string, content string) {
th.fSys.WriteFile(path, []byte(content))
}
func (th testingHarness) MakeDefaultOptions() Options {
return Options{
LoadRestrictions: types.LoadRestrictionsRootOnly,
PluginConfig: konfig.DisabledPluginConfig(),
}
}
func (th testingHarness) MakeEnabledPluginConfig() *types.PluginConfig {
// TODO: this doesn't work yet - need to set an env var.
// TODO: steal from kusttest_test.NewPluginTestEnv
c, err := konfig.EnabledPluginConfig()
if err != nil {
th.t.Fatal(err)
}
return c
}
// Run, failing on error.
func (th testingHarness) Run(path string, o Options) resmap.ResMap {
m, err := MakeKustomizer(th.fSys, &o).Run(path)
if err != nil {
th.t.Fatal(err)
}
return m
}
// Run, failing if there is no error.
func (th testingHarness) RunWithErr(path string, o Options) error {
_, err := MakeKustomizer(th.fSys, &o).Run(path)
if err == nil {
th.t.Fatalf("expected error")
}
return err
}
func (th testingHarness) AssertActualEqualsExpected(
m resmap.ResMap, expected string) {
th.AssertActualEqualsExpectedWithTweak(m, nil, expected)
}
func (th testingHarness) 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 testingHarness) 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")
}
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 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, "")
}