cluster/tools/kartongips: init

This forks bitnami/kubecfg into kartongips. The rationale is that we
want to implement hscloud-specific functionality that wouldn't really be
upstreamable into kubecfg (like secret support, mulit-cluster support).

We forked off from github.com/q3k/kubecfg at commit b6817a94492c561ed61a44eeea2d92dcf2e6b8c0.

Change-Id: If5ba513905e0a86f971576fe7061a471c1d8b398
diff --git a/cluster/tools/kartongips/utils/meta_test.go b/cluster/tools/kartongips/utils/meta_test.go
new file mode 100644
index 0000000..e83e3a7
--- /dev/null
+++ b/cluster/tools/kartongips/utils/meta_test.go
@@ -0,0 +1,179 @@
+package utils
+
+import (
+	"testing"
+
+	apiequality "k8s.io/apimachinery/pkg/api/equality"
+	"k8s.io/apimachinery/pkg/api/meta"
+	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
+	"k8s.io/apimachinery/pkg/runtime/schema"
+	"k8s.io/apimachinery/pkg/util/diff"
+	"k8s.io/apimachinery/pkg/version"
+)
+
+func TestParseVersion(t *testing.T) {
+	tests := []struct {
+		input    version.Info
+		expected ServerVersion
+		error    bool
+	}{
+		{
+			input:    version.Info{Major: "1", Minor: "6"},
+			expected: ServerVersion{Major: 1, Minor: 6},
+		},
+		{
+			input:    version.Info{Major: "1", Minor: "70"},
+			expected: ServerVersion{Major: 1, Minor: 70},
+		},
+		{
+			input: version.Info{Major: "1", Minor: "6x"},
+			error: true,
+		},
+		{
+			input:    version.Info{Major: "1", Minor: "8+"},
+			expected: ServerVersion{Major: 1, Minor: 8},
+		},
+		{
+			input:    version.Info{Major: "", Minor: "", GitVersion: "v1.8.0"},
+			expected: ServerVersion{Major: 1, Minor: 8},
+		},
+		{
+			input:    version.Info{Major: "1", Minor: "", GitVersion: "v1.8.0"},
+			expected: ServerVersion{Major: 1, Minor: 8},
+		},
+		{
+			input:    version.Info{Major: "", Minor: "8", GitVersion: "v1.8.0"},
+			expected: ServerVersion{Major: 1, Minor: 8},
+		},
+		{
+			input:    version.Info{Major: "", Minor: "", GitVersion: "v1.8.8-test.0"},
+			expected: ServerVersion{Major: 1, Minor: 8},
+		},
+		{
+			input:    version.Info{Major: "1", Minor: "8", GitVersion: "v1.9.0"},
+			expected: ServerVersion{Major: 1, Minor: 8},
+		},
+		{
+			input: version.Info{Major: "", Minor: "", GitVersion: "v1.a"},
+			error: true,
+		},
+	}
+
+	for _, test := range tests {
+		v, err := ParseVersion(&test.input)
+		if test.error {
+			if err == nil {
+				t.Errorf("test %s should have failed and did not", test.input)
+			}
+			continue
+		}
+		if err != nil {
+			t.Errorf("test %v failed: %v", test.input, err)
+			continue
+		}
+		if v != test.expected {
+			t.Errorf("Expected %v, got %v", test.expected, v)
+		}
+	}
+}
+
+func TestVersionCompare(t *testing.T) {
+	v := ServerVersion{Major: 2, Minor: 3}
+	tests := []struct {
+		major, minor, result int
+	}{
+		{major: 1, minor: 0, result: 1},
+		{major: 2, minor: 0, result: 1},
+		{major: 2, minor: 2, result: 1},
+		{major: 2, minor: 3, result: 0},
+		{major: 2, minor: 4, result: -1},
+		{major: 3, minor: 0, result: -1},
+	}
+	for _, test := range tests {
+		res := v.Compare(test.major, test.minor)
+		if res != test.result {
+			t.Errorf("%d.%d => Expected %d, got %d", test.major, test.minor, test.result, res)
+		}
+	}
+}
+
+func TestResourceNameFor(t *testing.T) {
+	obj := &unstructured.Unstructured{
+		Object: map[string]interface{}{
+			"apiVersion": "tests/v1alpha1",
+			"kind":       "Test",
+			"metadata": map[string]interface{}{
+				"name":      "myname",
+				"namespace": "mynamespace",
+			},
+		},
+	}
+
+	mapper := meta.NewDefaultRESTMapper([]schema.GroupVersion{})
+	mapper.Add(schema.GroupVersionKind{Group: "tests", Version: "v1alpha1", Kind: "Test"}, meta.RESTScopeNamespace)
+
+	if n := ResourceNameFor(mapper, obj); n != "tests" {
+		t.Errorf("Got resource name %q for %v", n, obj)
+	}
+
+	obj.SetKind("Unknown")
+	if n := ResourceNameFor(mapper, obj); n != "unknown" {
+		t.Errorf("Got resource name %q for %v", n, obj)
+	}
+
+	obj.SetGroupVersionKind(schema.GroupVersionKind{Group: "unknown", Version: "noversion", Kind: "SomeKind"})
+	if n := ResourceNameFor(mapper, obj); n != "somekind" {
+		t.Errorf("Got resource name %q for %v", n, obj)
+	}
+}
+
+func TestFqName(t *testing.T) {
+	obj := &unstructured.Unstructured{
+		Object: map[string]interface{}{
+			"apiVersion": "tests/v1alpha1",
+			"kind":       "Test",
+			"metadata": map[string]interface{}{
+				"name": "myname",
+			},
+		},
+	}
+
+	if n := FqName(obj); n != "myname" {
+		t.Errorf("Got %q for %v", n, obj)
+	}
+
+	obj.SetNamespace("mynamespace")
+	if n := FqName(obj); n != "mynamespace.myname" {
+		t.Errorf("Got %q for %v", n, obj)
+	}
+}
+
+func TestCompactEncodeRoundTrip(t *testing.T) {
+	obj := &unstructured.Unstructured{
+		Object: map[string]interface{}{
+			"apiVersion": "tests/v1alpha1",
+			"kind":       "Test",
+			"metadata": map[string]interface{}{
+				"name": "myname",
+			},
+			"foo": true,
+		},
+	}
+
+	data, err := CompactEncodeObject(obj)
+	if err != nil {
+		t.Errorf("CompactEncodeObject returned %v", err)
+	}
+	t.Logf("compact encoding is %d bytes", len(data))
+
+	out := &unstructured.Unstructured{}
+	if err := CompactDecodeObject(data, out); err != nil {
+		t.Errorf("CompactDecodeObject returned %v", err)
+	}
+
+	t.Logf("in:  %#v", obj)
+	t.Logf("out: %#v", out)
+	if !apiequality.Semantic.DeepEqual(obj, out) {
+		t.Error("Objects differed: ", diff.ObjectDiff(obj, out))
+	}
+}