mirror of
https://github.com/ceph/ceph-csi.git
synced 2025-06-14 02:43:36 +00:00
vendor files
This commit is contained in:
64
vendor/k8s.io/kubernetes/pkg/client/tests/BUILD
generated
vendored
Normal file
64
vendor/k8s.io/kubernetes/pkg/client/tests/BUILD
generated
vendored
Normal file
@ -0,0 +1,64 @@
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = [
|
||||
"fake_client_test.go",
|
||||
"listwatch_test.go",
|
||||
"portfoward_test.go",
|
||||
"remotecommand_test.go",
|
||||
],
|
||||
importpath = "k8s.io/kubernetes/pkg/client/tests",
|
||||
library = ":go_default_library",
|
||||
deps = [
|
||||
"//pkg/api/legacyscheme:go_default_library",
|
||||
"//pkg/api/testapi:go_default_library",
|
||||
"//pkg/apis/core:go_default_library",
|
||||
"//pkg/apis/core/install:go_default_library",
|
||||
"//pkg/client/clientset_generated/internalclientset:go_default_library",
|
||||
"//pkg/client/clientset_generated/internalclientset/fake:go_default_library",
|
||||
"//pkg/kubelet/server/portforward:go_default_library",
|
||||
"//pkg/kubelet/server/remotecommand:go_default_library",
|
||||
"//vendor/github.com/stretchr/testify/require:go_default_library",
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/fields:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/httpstream:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/remotecommand:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/watch:go_default_library",
|
||||
"//vendor/k8s.io/client-go/rest:go_default_library",
|
||||
"//vendor/k8s.io/client-go/tools/cache:go_default_library",
|
||||
"//vendor/k8s.io/client-go/tools/portforward:go_default_library",
|
||||
"//vendor/k8s.io/client-go/tools/remotecommand:go_default_library",
|
||||
"//vendor/k8s.io/client-go/transport/spdy:go_default_library",
|
||||
"//vendor/k8s.io/client-go/util/testing:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["doc.go"],
|
||||
importpath = "k8s.io/kubernetes/pkg/client/tests",
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
18
vendor/k8s.io/kubernetes/pkg/client/tests/doc.go
generated
vendored
Normal file
18
vendor/k8s.io/kubernetes/pkg/client/tests/doc.go
generated
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes 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.
|
||||
*/
|
||||
|
||||
// This package runs tests against the client which require an internal client
|
||||
package tests
|
182
vendor/k8s.io/kubernetes/pkg/client/tests/fake_client_test.go
generated
vendored
Normal file
182
vendor/k8s.io/kubernetes/pkg/client/tests/fake_client_test.go
generated
vendored
Normal file
@ -0,0 +1,182 @@
|
||||
/*
|
||||
Copyright 2016 The Kubernetes 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 tests
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
clientsetfake "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake"
|
||||
|
||||
_ "k8s.io/kubernetes/pkg/apis/core/install"
|
||||
)
|
||||
|
||||
func TestFakeClientSetFiltering(t *testing.T) {
|
||||
tc := clientsetfake.NewSimpleClientset(
|
||||
testPod("nsA", "pod-1"),
|
||||
testPod("nsB", "pod-2"),
|
||||
testSA("nsA", "sa-1"),
|
||||
testSA("nsA", "sa-2"),
|
||||
testSA("nsB", "sa-1"),
|
||||
testSA("nsB", "sa-2"),
|
||||
testSA("nsB", "sa-3"),
|
||||
)
|
||||
|
||||
saList1, err := tc.Core().ServiceAccounts("nsA").List(metav1.ListOptions{})
|
||||
if err != nil {
|
||||
t.Fatalf("ServiceAccounts.List: %s", err)
|
||||
}
|
||||
if actual, expected := len(saList1.Items), 2; expected != actual {
|
||||
t.Fatalf("Expected %d records to match, got %d", expected, actual)
|
||||
}
|
||||
for _, sa := range saList1.Items {
|
||||
if sa.Namespace != "nsA" {
|
||||
t.Fatalf("Expected namespace %q; got %q", "nsA", sa.Namespace)
|
||||
}
|
||||
}
|
||||
|
||||
saList2, err := tc.Core().ServiceAccounts("nsB").List(metav1.ListOptions{})
|
||||
if err != nil {
|
||||
t.Fatalf("ServiceAccounts.List: %s", err)
|
||||
}
|
||||
if actual, expected := len(saList2.Items), 3; expected != actual {
|
||||
t.Fatalf("Expected %d records to match, got %d", expected, actual)
|
||||
}
|
||||
for _, sa := range saList2.Items {
|
||||
if sa.Namespace != "nsB" {
|
||||
t.Fatalf("Expected namespace %q; got %q", "nsA", sa.Namespace)
|
||||
}
|
||||
}
|
||||
|
||||
pod1, err := tc.Core().Pods("nsA").Get("pod-1", metav1.GetOptions{})
|
||||
if err != nil {
|
||||
t.Fatalf("Pods.Get: %s", err)
|
||||
}
|
||||
if pod1 == nil {
|
||||
t.Fatalf("Expected to find pod nsA/pod-1 but it wasn't found")
|
||||
}
|
||||
if pod1.Namespace != "nsA" || pod1.Name != "pod-1" {
|
||||
t.Fatalf("Expected to find pod nsA/pod-1t, got %s/%s", pod1.Namespace, pod1.Name)
|
||||
}
|
||||
|
||||
wrongPod, err := tc.Core().Pods("nsB").Get("pod-1", metav1.GetOptions{})
|
||||
if err == nil {
|
||||
t.Fatalf("Pods.Get: expected nsB/pod-1 not to match, but it matched %s/%s", wrongPod.Namespace, wrongPod.Name)
|
||||
}
|
||||
|
||||
allPods, err := tc.Core().Pods(metav1.NamespaceAll).List(metav1.ListOptions{})
|
||||
if err != nil {
|
||||
t.Fatalf("Pods.List: %s", err)
|
||||
}
|
||||
if actual, expected := len(allPods.Items), 2; expected != actual {
|
||||
t.Fatalf("Expected %d pods to match, got %d", expected, actual)
|
||||
}
|
||||
|
||||
allSAs, err := tc.Core().ServiceAccounts(metav1.NamespaceAll).List(metav1.ListOptions{})
|
||||
if err != nil {
|
||||
t.Fatalf("ServiceAccounts.List: %s", err)
|
||||
}
|
||||
if actual, expected := len(allSAs.Items), 5; expected != actual {
|
||||
t.Fatalf("Expected %d service accounts to match, got %d", expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFakeClientsetInheritsNamespace(t *testing.T) {
|
||||
tc := clientsetfake.NewSimpleClientset(
|
||||
testNamespace("nsA"),
|
||||
testPod("nsA", "pod-1"),
|
||||
)
|
||||
|
||||
_, err := tc.Core().Namespaces().Create(testNamespace("nsB"))
|
||||
if err != nil {
|
||||
t.Fatalf("Namespaces.Create: %s", err)
|
||||
}
|
||||
|
||||
allNS, err := tc.Core().Namespaces().List(metav1.ListOptions{})
|
||||
if err != nil {
|
||||
t.Fatalf("Namespaces.List: %s", err)
|
||||
}
|
||||
if actual, expected := len(allNS.Items), 2; expected != actual {
|
||||
t.Fatalf("Expected %d namespaces to match, got %d", expected, actual)
|
||||
}
|
||||
|
||||
_, err = tc.Core().Pods("nsB").Create(testPod("", "pod-1"))
|
||||
if err != nil {
|
||||
t.Fatalf("Pods.Create nsB/pod-1: %s", err)
|
||||
}
|
||||
|
||||
podB1, err := tc.Core().Pods("nsB").Get("pod-1", metav1.GetOptions{})
|
||||
if err != nil {
|
||||
t.Fatalf("Pods.Get nsB/pod-1: %s", err)
|
||||
}
|
||||
if podB1 == nil {
|
||||
t.Fatalf("Expected to find pod nsB/pod-1 but it wasn't found")
|
||||
}
|
||||
if podB1.Namespace != "nsB" || podB1.Name != "pod-1" {
|
||||
t.Fatalf("Expected to find pod nsB/pod-1t, got %s/%s", podB1.Namespace, podB1.Name)
|
||||
}
|
||||
|
||||
_, err = tc.Core().Pods("nsA").Create(testPod("", "pod-1"))
|
||||
if err == nil {
|
||||
t.Fatalf("Expected Pods.Create to fail with already exists error")
|
||||
}
|
||||
|
||||
_, err = tc.Core().Pods("nsA").Update(testPod("", "pod-1"))
|
||||
if err != nil {
|
||||
t.Fatalf("Pods.Update nsA/pod-1: %s", err)
|
||||
}
|
||||
|
||||
_, err = tc.Core().Pods("nsA").Create(testPod("nsB", "pod-2"))
|
||||
if err == nil {
|
||||
t.Fatalf("Expected Pods.Create to fail with bad request from namespace mismtach")
|
||||
}
|
||||
if err.Error() != `request namespace does not match object namespace, request: "nsA" object: "nsB"` {
|
||||
t.Fatalf("Expected Pods.Create error to provide object and request namespaces, got %q", err)
|
||||
}
|
||||
|
||||
_, err = tc.Core().Pods("nsA").Update(testPod("", "pod-3"))
|
||||
if err == nil {
|
||||
t.Fatalf("Expected Pods.Update nsA/pod-3 to fail with not found error")
|
||||
}
|
||||
}
|
||||
|
||||
func testSA(ns, name string) *api.ServiceAccount {
|
||||
return &api.ServiceAccount{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: ns,
|
||||
Name: name,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func testPod(ns, name string) *api.Pod {
|
||||
return &api.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: ns,
|
||||
Name: name,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func testNamespace(ns string) *api.Namespace {
|
||||
return &api.Namespace{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: ns,
|
||||
},
|
||||
}
|
||||
}
|
229
vendor/k8s.io/kubernetes/pkg/client/tests/listwatch_test.go
generated
vendored
Normal file
229
vendor/k8s.io/kubernetes/pkg/client/tests/listwatch_test.go
generated
vendored
Normal file
@ -0,0 +1,229 @@
|
||||
/*
|
||||
Copyright 2015 The Kubernetes 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 tests
|
||||
|
||||
import (
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/fields"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
. "k8s.io/client-go/tools/cache"
|
||||
utiltesting "k8s.io/client-go/util/testing"
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
"k8s.io/kubernetes/pkg/api/testapi"
|
||||
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
||||
)
|
||||
|
||||
func parseSelectorOrDie(s string) fields.Selector {
|
||||
selector, err := fields.ParseSelector(s)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return selector
|
||||
}
|
||||
|
||||
// buildQueryValues is a convenience function for knowing if a namespace should be in a query param or not
|
||||
func buildQueryValues(query url.Values) url.Values {
|
||||
v := url.Values{}
|
||||
if query != nil {
|
||||
for key, values := range query {
|
||||
for _, value := range values {
|
||||
v.Add(key, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
func buildLocation(resourcePath string, query url.Values) string {
|
||||
return resourcePath + "?" + query.Encode()
|
||||
}
|
||||
|
||||
func TestListWatchesCanList(t *testing.T) {
|
||||
fieldSelectorQueryParamName := metav1.FieldSelectorQueryParam(legacyscheme.Registry.GroupOrDie(v1.GroupName).GroupVersion.String())
|
||||
table := []struct {
|
||||
location string
|
||||
resource string
|
||||
namespace string
|
||||
fieldSelector fields.Selector
|
||||
}{
|
||||
// Node
|
||||
{
|
||||
location: testapi.Default.ResourcePath("nodes", metav1.NamespaceAll, ""),
|
||||
resource: "nodes",
|
||||
namespace: metav1.NamespaceAll,
|
||||
fieldSelector: parseSelectorOrDie(""),
|
||||
},
|
||||
// pod with "assigned" field selector.
|
||||
{
|
||||
location: buildLocation(
|
||||
testapi.Default.ResourcePath("pods", metav1.NamespaceAll, ""),
|
||||
buildQueryValues(url.Values{fieldSelectorQueryParamName: []string{"spec.host="}})),
|
||||
resource: "pods",
|
||||
namespace: metav1.NamespaceAll,
|
||||
fieldSelector: fields.Set{"spec.host": ""}.AsSelector(),
|
||||
},
|
||||
// pod in namespace "foo"
|
||||
{
|
||||
location: buildLocation(
|
||||
testapi.Default.ResourcePath("pods", "foo", ""),
|
||||
buildQueryValues(url.Values{fieldSelectorQueryParamName: []string{"spec.host="}})),
|
||||
resource: "pods",
|
||||
namespace: "foo",
|
||||
fieldSelector: fields.Set{"spec.host": ""}.AsSelector(),
|
||||
},
|
||||
}
|
||||
for _, item := range table {
|
||||
handler := utiltesting.FakeHandler{
|
||||
StatusCode: 500,
|
||||
ResponseBody: "",
|
||||
T: t,
|
||||
}
|
||||
server := httptest.NewServer(&handler)
|
||||
defer server.Close()
|
||||
client := clientset.NewForConfigOrDie(&restclient.Config{Host: server.URL, ContentConfig: restclient.ContentConfig{GroupVersion: &legacyscheme.Registry.GroupOrDie(v1.GroupName).GroupVersion}})
|
||||
lw := NewListWatchFromClient(client.Core().RESTClient(), item.resource, item.namespace, item.fieldSelector)
|
||||
lw.DisableChunking = true
|
||||
// This test merely tests that the correct request is made.
|
||||
lw.List(metav1.ListOptions{})
|
||||
handler.ValidateRequest(t, item.location, "GET", nil)
|
||||
}
|
||||
}
|
||||
|
||||
func TestListWatchesCanWatch(t *testing.T) {
|
||||
fieldSelectorQueryParamName := metav1.FieldSelectorQueryParam(legacyscheme.Registry.GroupOrDie(v1.GroupName).GroupVersion.String())
|
||||
table := []struct {
|
||||
rv string
|
||||
location string
|
||||
resource string
|
||||
namespace string
|
||||
fieldSelector fields.Selector
|
||||
}{
|
||||
// Node
|
||||
{
|
||||
location: buildLocation(
|
||||
testapi.Default.ResourcePath("nodes", metav1.NamespaceAll, ""),
|
||||
buildQueryValues(url.Values{"watch": []string{"true"}})),
|
||||
rv: "",
|
||||
resource: "nodes",
|
||||
namespace: metav1.NamespaceAll,
|
||||
fieldSelector: parseSelectorOrDie(""),
|
||||
},
|
||||
{
|
||||
location: buildLocation(
|
||||
testapi.Default.ResourcePath("nodes", metav1.NamespaceAll, ""),
|
||||
buildQueryValues(url.Values{"resourceVersion": []string{"42"}, "watch": []string{"true"}})),
|
||||
rv: "42",
|
||||
resource: "nodes",
|
||||
namespace: metav1.NamespaceAll,
|
||||
fieldSelector: parseSelectorOrDie(""),
|
||||
},
|
||||
// pod with "assigned" field selector.
|
||||
{
|
||||
location: buildLocation(
|
||||
testapi.Default.ResourcePath("pods", metav1.NamespaceAll, ""),
|
||||
buildQueryValues(url.Values{fieldSelectorQueryParamName: []string{"spec.host="}, "resourceVersion": []string{"0"}, "watch": []string{"true"}})),
|
||||
rv: "0",
|
||||
resource: "pods",
|
||||
namespace: metav1.NamespaceAll,
|
||||
fieldSelector: fields.Set{"spec.host": ""}.AsSelector(),
|
||||
},
|
||||
// pod with namespace foo and assigned field selector
|
||||
{
|
||||
location: buildLocation(
|
||||
testapi.Default.ResourcePath("pods", "foo", ""),
|
||||
buildQueryValues(url.Values{fieldSelectorQueryParamName: []string{"spec.host="}, "resourceVersion": []string{"0"}, "watch": []string{"true"}})),
|
||||
rv: "0",
|
||||
resource: "pods",
|
||||
namespace: "foo",
|
||||
fieldSelector: fields.Set{"spec.host": ""}.AsSelector(),
|
||||
},
|
||||
}
|
||||
|
||||
for _, item := range table {
|
||||
handler := utiltesting.FakeHandler{
|
||||
StatusCode: 500,
|
||||
ResponseBody: "",
|
||||
T: t,
|
||||
}
|
||||
server := httptest.NewServer(&handler)
|
||||
defer server.Close()
|
||||
client := clientset.NewForConfigOrDie(&restclient.Config{Host: server.URL, ContentConfig: restclient.ContentConfig{GroupVersion: &legacyscheme.Registry.GroupOrDie(v1.GroupName).GroupVersion}})
|
||||
lw := NewListWatchFromClient(client.Core().RESTClient(), item.resource, item.namespace, item.fieldSelector)
|
||||
// This test merely tests that the correct request is made.
|
||||
lw.Watch(metav1.ListOptions{ResourceVersion: item.rv})
|
||||
handler.ValidateRequest(t, item.location, "GET", nil)
|
||||
}
|
||||
}
|
||||
|
||||
type lw struct {
|
||||
list runtime.Object
|
||||
watch watch.Interface
|
||||
}
|
||||
|
||||
func (w lw) List(options metav1.ListOptions) (runtime.Object, error) {
|
||||
return w.list, nil
|
||||
}
|
||||
|
||||
func (w lw) Watch(options metav1.ListOptions) (watch.Interface, error) {
|
||||
return w.watch, nil
|
||||
}
|
||||
|
||||
func TestListWatchUntil(t *testing.T) {
|
||||
fw := watch.NewFake()
|
||||
go func() {
|
||||
var obj *v1.Pod
|
||||
fw.Modify(obj)
|
||||
}()
|
||||
listwatch := lw{
|
||||
list: &v1.PodList{Items: []v1.Pod{{}}},
|
||||
watch: fw,
|
||||
}
|
||||
|
||||
conditions := []watch.ConditionFunc{
|
||||
func(event watch.Event) (bool, error) {
|
||||
t.Logf("got %#v", event)
|
||||
return event.Type == watch.Added, nil
|
||||
},
|
||||
func(event watch.Event) (bool, error) {
|
||||
t.Logf("got %#v", event)
|
||||
return event.Type == watch.Modified, nil
|
||||
},
|
||||
}
|
||||
|
||||
timeout := 10 * time.Second
|
||||
lastEvent, err := ListWatchUntil(timeout, listwatch, conditions...)
|
||||
if err != nil {
|
||||
t.Fatalf("expected nil error, got %#v", err)
|
||||
}
|
||||
if lastEvent == nil {
|
||||
t.Fatal("expected an event")
|
||||
}
|
||||
if lastEvent.Type != watch.Modified {
|
||||
t.Fatalf("expected MODIFIED event type, got %v", lastEvent.Type)
|
||||
}
|
||||
if got, isPod := lastEvent.Object.(*v1.Pod); !isPod {
|
||||
t.Fatalf("expected a pod event, got %#v", got)
|
||||
}
|
||||
}
|
232
vendor/k8s.io/kubernetes/pkg/client/tests/portfoward_test.go
generated
vendored
Normal file
232
vendor/k8s.io/kubernetes/pkg/client/tests/portfoward_test.go
generated
vendored
Normal file
@ -0,0 +1,232 @@
|
||||
/*
|
||||
Copyright 2015 The Kubernetes 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 tests
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
. "k8s.io/client-go/tools/portforward"
|
||||
"k8s.io/client-go/transport/spdy"
|
||||
"k8s.io/kubernetes/pkg/kubelet/server/portforward"
|
||||
)
|
||||
|
||||
// fakePortForwarder simulates port forwarding for testing. It implements
|
||||
// portforward.PortForwarder.
|
||||
type fakePortForwarder struct {
|
||||
lock sync.Mutex
|
||||
// stores data expected from the stream per port
|
||||
expected map[int32]string
|
||||
// stores data received from the stream per port
|
||||
received map[int32]string
|
||||
// data to be sent to the stream per port
|
||||
send map[int32]string
|
||||
}
|
||||
|
||||
var _ portforward.PortForwarder = &fakePortForwarder{}
|
||||
|
||||
func (pf *fakePortForwarder) PortForward(name string, uid types.UID, port int32, stream io.ReadWriteCloser) error {
|
||||
defer stream.Close()
|
||||
|
||||
// read from the client
|
||||
received := make([]byte, len(pf.expected[port]))
|
||||
n, err := stream.Read(received)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error reading from client for port %d: %v", port, err)
|
||||
}
|
||||
if n != len(pf.expected[port]) {
|
||||
return fmt.Errorf("unexpected length read from client for port %d: got %d, expected %d. data=%q", port, n, len(pf.expected[port]), string(received))
|
||||
}
|
||||
|
||||
// store the received content
|
||||
pf.lock.Lock()
|
||||
pf.received[port] = string(received)
|
||||
pf.lock.Unlock()
|
||||
|
||||
// send the hardcoded data to the client
|
||||
io.Copy(stream, strings.NewReader(pf.send[port]))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// fakePortForwardServer creates an HTTP server that can handle port forwarding
|
||||
// requests.
|
||||
func fakePortForwardServer(t *testing.T, testName string, serverSends, expectedFromClient map[int32]string) http.HandlerFunc {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||
pf := &fakePortForwarder{
|
||||
expected: expectedFromClient,
|
||||
received: make(map[int32]string),
|
||||
send: serverSends,
|
||||
}
|
||||
portforward.ServePortForward(w, req, pf, "pod", "uid", nil, 0, 10*time.Second, portforward.SupportedProtocols)
|
||||
|
||||
for port, expected := range expectedFromClient {
|
||||
actual, ok := pf.received[port]
|
||||
if !ok {
|
||||
t.Errorf("%s: server didn't receive any data for port %d", testName, port)
|
||||
continue
|
||||
}
|
||||
|
||||
if expected != actual {
|
||||
t.Errorf("%s: server expected to receive %q, got %q for port %d", testName, expected, actual, port)
|
||||
}
|
||||
}
|
||||
|
||||
for port, actual := range pf.received {
|
||||
if _, ok := expectedFromClient[port]; !ok {
|
||||
t.Errorf("%s: server unexpectedly received %q for port %d", testName, actual, port)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestForwardPorts(t *testing.T) {
|
||||
tests := map[string]struct {
|
||||
ports []string
|
||||
clientSends map[int32]string
|
||||
serverSends map[int32]string
|
||||
}{
|
||||
"forward 1 port with no data either direction": {
|
||||
ports: []string{"5000"},
|
||||
},
|
||||
"forward 2 ports with bidirectional data": {
|
||||
ports: []string{"5001", "6000"},
|
||||
clientSends: map[int32]string{
|
||||
5001: "abcd",
|
||||
6000: "ghij",
|
||||
},
|
||||
serverSends: map[int32]string{
|
||||
5001: "1234",
|
||||
6000: "5678",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for testName, test := range tests {
|
||||
server := httptest.NewServer(fakePortForwardServer(t, testName, test.serverSends, test.clientSends))
|
||||
|
||||
transport, upgrader, err := spdy.RoundTripperFor(&restclient.Config{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
url, _ := url.Parse(server.URL)
|
||||
dialer := spdy.NewDialer(upgrader, &http.Client{Transport: transport}, "POST", url)
|
||||
|
||||
stopChan := make(chan struct{}, 1)
|
||||
readyChan := make(chan struct{})
|
||||
|
||||
pf, err := New(dialer, test.ports, stopChan, readyChan, os.Stdout, os.Stderr)
|
||||
if err != nil {
|
||||
t.Fatalf("%s: unexpected error calling New: %v", testName, err)
|
||||
}
|
||||
|
||||
doneChan := make(chan error)
|
||||
go func() {
|
||||
doneChan <- pf.ForwardPorts()
|
||||
}()
|
||||
<-pf.Ready
|
||||
|
||||
for port, data := range test.clientSends {
|
||||
clientConn, err := net.Dial("tcp", fmt.Sprintf("localhost:%d", port))
|
||||
if err != nil {
|
||||
t.Errorf("%s: error dialing %d: %s", testName, port, err)
|
||||
server.Close()
|
||||
continue
|
||||
}
|
||||
defer clientConn.Close()
|
||||
|
||||
n, err := clientConn.Write([]byte(data))
|
||||
if err != nil && err != io.EOF {
|
||||
t.Errorf("%s: Error sending data '%s': %s", testName, data, err)
|
||||
server.Close()
|
||||
continue
|
||||
}
|
||||
if n == 0 {
|
||||
t.Errorf("%s: unexpected write of 0 bytes", testName)
|
||||
server.Close()
|
||||
continue
|
||||
}
|
||||
b := make([]byte, 4)
|
||||
n, err = clientConn.Read(b)
|
||||
if err != nil && err != io.EOF {
|
||||
t.Errorf("%s: Error reading data: %s", testName, err)
|
||||
server.Close()
|
||||
continue
|
||||
}
|
||||
if !bytes.Equal([]byte(test.serverSends[port]), b) {
|
||||
t.Errorf("%s: expected to read '%s', got '%s'", testName, test.serverSends[port], b)
|
||||
server.Close()
|
||||
continue
|
||||
}
|
||||
}
|
||||
// tell r.ForwardPorts to stop
|
||||
close(stopChan)
|
||||
|
||||
// wait for r.ForwardPorts to actually return
|
||||
err = <-doneChan
|
||||
if err != nil {
|
||||
t.Errorf("%s: unexpected error: %s", testName, err)
|
||||
}
|
||||
server.Close()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestForwardPortsReturnsErrorWhenAllBindsFailed(t *testing.T) {
|
||||
server := httptest.NewServer(fakePortForwardServer(t, "allBindsFailed", nil, nil))
|
||||
defer server.Close()
|
||||
|
||||
transport, upgrader, err := spdy.RoundTripperFor(&restclient.Config{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
url, _ := url.Parse(server.URL)
|
||||
dialer := spdy.NewDialer(upgrader, &http.Client{Transport: transport}, "POST", url)
|
||||
|
||||
stopChan1 := make(chan struct{}, 1)
|
||||
defer close(stopChan1)
|
||||
readyChan1 := make(chan struct{})
|
||||
|
||||
pf1, err := New(dialer, []string{"5555"}, stopChan1, readyChan1, os.Stdout, os.Stderr)
|
||||
if err != nil {
|
||||
t.Fatalf("error creating pf1: %v", err)
|
||||
}
|
||||
go pf1.ForwardPorts()
|
||||
<-pf1.Ready
|
||||
|
||||
stopChan2 := make(chan struct{}, 1)
|
||||
readyChan2 := make(chan struct{})
|
||||
pf2, err := New(dialer, []string{"5555"}, stopChan2, readyChan2, os.Stdout, os.Stderr)
|
||||
if err != nil {
|
||||
t.Fatalf("error creating pf2: %v", err)
|
||||
}
|
||||
if err := pf2.ForwardPorts(); err == nil {
|
||||
t.Fatal("expected non-nil error for pf2.ForwardPorts")
|
||||
}
|
||||
}
|
366
vendor/k8s.io/kubernetes/pkg/client/tests/remotecommand_test.go
generated
vendored
Normal file
366
vendor/k8s.io/kubernetes/pkg/client/tests/remotecommand_test.go
generated
vendored
Normal file
@ -0,0 +1,366 @@
|
||||
/*
|
||||
Copyright 2015 The Kubernetes 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 tests
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/httpstream"
|
||||
remotecommandconsts "k8s.io/apimachinery/pkg/util/remotecommand"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
remoteclient "k8s.io/client-go/tools/remotecommand"
|
||||
"k8s.io/client-go/transport/spdy"
|
||||
"k8s.io/kubernetes/pkg/api/testapi"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
"k8s.io/kubernetes/pkg/kubelet/server/remotecommand"
|
||||
)
|
||||
|
||||
type fakeExecutor struct {
|
||||
t *testing.T
|
||||
testName string
|
||||
errorData string
|
||||
stdoutData string
|
||||
stderrData string
|
||||
expectStdin bool
|
||||
stdinReceived bytes.Buffer
|
||||
tty bool
|
||||
messageCount int
|
||||
command []string
|
||||
exec bool
|
||||
}
|
||||
|
||||
func (ex *fakeExecutor) ExecInContainer(name string, uid types.UID, container string, cmd []string, in io.Reader, out, err io.WriteCloser, tty bool, resize <-chan remoteclient.TerminalSize, timeout time.Duration) error {
|
||||
return ex.run(name, uid, container, cmd, in, out, err, tty)
|
||||
}
|
||||
|
||||
func (ex *fakeExecutor) AttachContainer(name string, uid types.UID, container string, in io.Reader, out, err io.WriteCloser, tty bool, resize <-chan remoteclient.TerminalSize) error {
|
||||
return ex.run(name, uid, container, nil, in, out, err, tty)
|
||||
}
|
||||
|
||||
func (ex *fakeExecutor) run(name string, uid types.UID, container string, cmd []string, in io.Reader, out, err io.WriteCloser, tty bool) error {
|
||||
ex.command = cmd
|
||||
ex.tty = tty
|
||||
|
||||
if e, a := "pod", name; e != a {
|
||||
ex.t.Errorf("%s: pod: expected %q, got %q", ex.testName, e, a)
|
||||
}
|
||||
if e, a := "uid", uid; e != string(a) {
|
||||
ex.t.Errorf("%s: uid: expected %q, got %q", ex.testName, e, a)
|
||||
}
|
||||
if ex.exec {
|
||||
if e, a := "ls /", strings.Join(ex.command, " "); e != a {
|
||||
ex.t.Errorf("%s: command: expected %q, got %q", ex.testName, e, a)
|
||||
}
|
||||
} else {
|
||||
if len(ex.command) > 0 {
|
||||
ex.t.Errorf("%s: command: expected nothing, got %v", ex.testName, ex.command)
|
||||
}
|
||||
}
|
||||
|
||||
if len(ex.errorData) > 0 {
|
||||
return errors.New(ex.errorData)
|
||||
}
|
||||
|
||||
if len(ex.stdoutData) > 0 {
|
||||
for i := 0; i < ex.messageCount; i++ {
|
||||
fmt.Fprint(out, ex.stdoutData)
|
||||
}
|
||||
}
|
||||
|
||||
if len(ex.stderrData) > 0 {
|
||||
for i := 0; i < ex.messageCount; i++ {
|
||||
fmt.Fprint(err, ex.stderrData)
|
||||
}
|
||||
}
|
||||
|
||||
if ex.expectStdin {
|
||||
io.Copy(&ex.stdinReceived, in)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func fakeServer(t *testing.T, testName string, exec bool, stdinData, stdoutData, stderrData, errorData string, tty bool, messageCount int, serverProtocols []string) http.HandlerFunc {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||
executor := &fakeExecutor{
|
||||
t: t,
|
||||
testName: testName,
|
||||
errorData: errorData,
|
||||
stdoutData: stdoutData,
|
||||
stderrData: stderrData,
|
||||
expectStdin: len(stdinData) > 0,
|
||||
tty: tty,
|
||||
messageCount: messageCount,
|
||||
exec: exec,
|
||||
}
|
||||
|
||||
opts, err := remotecommand.NewOptions(req)
|
||||
require.NoError(t, err)
|
||||
if exec {
|
||||
cmd := req.URL.Query()[api.ExecCommandParam]
|
||||
remotecommand.ServeExec(w, req, executor, "pod", "uid", "container", cmd, opts, 0, 10*time.Second, serverProtocols)
|
||||
} else {
|
||||
remotecommand.ServeAttach(w, req, executor, "pod", "uid", "container", opts, 0, 10*time.Second, serverProtocols)
|
||||
}
|
||||
|
||||
if e, a := strings.Repeat(stdinData, messageCount), executor.stdinReceived.String(); e != a {
|
||||
t.Errorf("%s: stdin: expected %q, got %q", testName, e, a)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestStream(t *testing.T) {
|
||||
testCases := []struct {
|
||||
TestName string
|
||||
Stdin string
|
||||
Stdout string
|
||||
Stderr string
|
||||
Error string
|
||||
Tty bool
|
||||
MessageCount int
|
||||
ClientProtocols []string
|
||||
ServerProtocols []string
|
||||
}{
|
||||
{
|
||||
TestName: "error",
|
||||
Error: "bail",
|
||||
Stdout: "a",
|
||||
ClientProtocols: []string{remotecommandconsts.StreamProtocolV2Name},
|
||||
ServerProtocols: []string{remotecommandconsts.StreamProtocolV2Name},
|
||||
},
|
||||
{
|
||||
TestName: "in/out/err",
|
||||
Stdin: "a",
|
||||
Stdout: "b",
|
||||
Stderr: "c",
|
||||
MessageCount: 100,
|
||||
ClientProtocols: []string{remotecommandconsts.StreamProtocolV2Name},
|
||||
ServerProtocols: []string{remotecommandconsts.StreamProtocolV2Name},
|
||||
},
|
||||
{
|
||||
TestName: "in/out/tty",
|
||||
Stdin: "a",
|
||||
Stdout: "b",
|
||||
Tty: true,
|
||||
MessageCount: 100,
|
||||
ClientProtocols: []string{remotecommandconsts.StreamProtocolV2Name},
|
||||
ServerProtocols: []string{remotecommandconsts.StreamProtocolV2Name},
|
||||
},
|
||||
{
|
||||
// 1.0 kubectl, 1.0 kubelet
|
||||
TestName: "unversioned client, unversioned server",
|
||||
Stdout: "b",
|
||||
Stderr: "c",
|
||||
MessageCount: 1,
|
||||
ClientProtocols: []string{},
|
||||
ServerProtocols: []string{},
|
||||
},
|
||||
{
|
||||
// 1.0 kubectl, 1.1+ kubelet
|
||||
TestName: "unversioned client, versioned server",
|
||||
Stdout: "b",
|
||||
Stderr: "c",
|
||||
MessageCount: 1,
|
||||
ClientProtocols: []string{},
|
||||
ServerProtocols: []string{remotecommandconsts.StreamProtocolV2Name, remotecommandconsts.StreamProtocolV1Name},
|
||||
},
|
||||
{
|
||||
// 1.1+ kubectl, 1.0 kubelet
|
||||
TestName: "versioned client, unversioned server",
|
||||
Stdout: "b",
|
||||
Stderr: "c",
|
||||
MessageCount: 1,
|
||||
ClientProtocols: []string{remotecommandconsts.StreamProtocolV2Name, remotecommandconsts.StreamProtocolV1Name},
|
||||
ServerProtocols: []string{},
|
||||
},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
for _, exec := range []bool{true, false} {
|
||||
var name string
|
||||
if exec {
|
||||
name = testCase.TestName + " (exec)"
|
||||
} else {
|
||||
name = testCase.TestName + " (attach)"
|
||||
}
|
||||
var (
|
||||
streamIn io.Reader
|
||||
streamOut, streamErr io.Writer
|
||||
)
|
||||
localOut := &bytes.Buffer{}
|
||||
localErr := &bytes.Buffer{}
|
||||
|
||||
server := httptest.NewServer(fakeServer(t, name, exec, testCase.Stdin, testCase.Stdout, testCase.Stderr, testCase.Error, testCase.Tty, testCase.MessageCount, testCase.ServerProtocols))
|
||||
|
||||
url, _ := url.ParseRequestURI(server.URL)
|
||||
config := restclient.ContentConfig{
|
||||
GroupVersion: &schema.GroupVersion{Group: "x"},
|
||||
NegotiatedSerializer: testapi.Default.NegotiatedSerializer(),
|
||||
}
|
||||
c, err := restclient.NewRESTClient(url, "", config, -1, -1, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create a client: %v", err)
|
||||
}
|
||||
req := c.Post().Resource("testing")
|
||||
|
||||
if exec {
|
||||
req.Param("command", "ls")
|
||||
req.Param("command", "/")
|
||||
}
|
||||
|
||||
if len(testCase.Stdin) > 0 {
|
||||
req.Param(api.ExecStdinParam, "1")
|
||||
streamIn = strings.NewReader(strings.Repeat(testCase.Stdin, testCase.MessageCount))
|
||||
}
|
||||
|
||||
if len(testCase.Stdout) > 0 {
|
||||
req.Param(api.ExecStdoutParam, "1")
|
||||
streamOut = localOut
|
||||
}
|
||||
|
||||
if testCase.Tty {
|
||||
req.Param(api.ExecTTYParam, "1")
|
||||
} else if len(testCase.Stderr) > 0 {
|
||||
req.Param(api.ExecStderrParam, "1")
|
||||
streamErr = localErr
|
||||
}
|
||||
|
||||
conf := &restclient.Config{
|
||||
Host: server.URL,
|
||||
}
|
||||
transport, upgradeTransport, err := spdy.RoundTripperFor(conf)
|
||||
if err != nil {
|
||||
t.Errorf("%s: unexpected error: %v", name, err)
|
||||
continue
|
||||
}
|
||||
e, err := remoteclient.NewSPDYExecutorForProtocols(transport, upgradeTransport, "POST", req.URL(), testCase.ClientProtocols...)
|
||||
if err != nil {
|
||||
t.Errorf("%s: unexpected error: %v", name, err)
|
||||
continue
|
||||
}
|
||||
err = e.Stream(remoteclient.StreamOptions{
|
||||
Stdin: streamIn,
|
||||
Stdout: streamOut,
|
||||
Stderr: streamErr,
|
||||
Tty: testCase.Tty,
|
||||
})
|
||||
hasErr := err != nil
|
||||
|
||||
if len(testCase.Error) > 0 {
|
||||
if !hasErr {
|
||||
t.Errorf("%s: expected an error", name)
|
||||
} else {
|
||||
if e, a := testCase.Error, err.Error(); !strings.Contains(a, e) {
|
||||
t.Errorf("%s: expected error stream read %q, got %q", name, e, a)
|
||||
}
|
||||
}
|
||||
|
||||
server.Close()
|
||||
continue
|
||||
}
|
||||
|
||||
if hasErr {
|
||||
t.Errorf("%s: unexpected error: %v", name, err)
|
||||
server.Close()
|
||||
continue
|
||||
}
|
||||
|
||||
if len(testCase.Stdout) > 0 {
|
||||
if e, a := strings.Repeat(testCase.Stdout, testCase.MessageCount), localOut; e != a.String() {
|
||||
t.Errorf("%s: expected stdout data %q, got %q", name, e, a)
|
||||
}
|
||||
}
|
||||
|
||||
if testCase.Stderr != "" {
|
||||
if e, a := strings.Repeat(testCase.Stderr, testCase.MessageCount), localErr; e != a.String() {
|
||||
t.Errorf("%s: expected stderr data %q, got %q", name, e, a)
|
||||
}
|
||||
}
|
||||
|
||||
server.Close()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type fakeUpgrader struct {
|
||||
req *http.Request
|
||||
resp *http.Response
|
||||
conn httpstream.Connection
|
||||
err, connErr error
|
||||
checkResponse bool
|
||||
called bool
|
||||
|
||||
t *testing.T
|
||||
}
|
||||
|
||||
func (u *fakeUpgrader) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
u.called = true
|
||||
u.req = req
|
||||
return u.resp, u.err
|
||||
}
|
||||
|
||||
func (u *fakeUpgrader) NewConnection(resp *http.Response) (httpstream.Connection, error) {
|
||||
if u.checkResponse && u.resp != resp {
|
||||
u.t.Errorf("response objects passed did not match: %#v", resp)
|
||||
}
|
||||
return u.conn, u.connErr
|
||||
}
|
||||
|
||||
type fakeConnection struct {
|
||||
httpstream.Connection
|
||||
}
|
||||
|
||||
// Dial is the common functionality between any stream based upgrader, regardless of protocol.
|
||||
// This method ensures that someone can use a generic stream executor without being dependent
|
||||
// on the core Kube client config behavior.
|
||||
func TestDial(t *testing.T) {
|
||||
upgrader := &fakeUpgrader{
|
||||
t: t,
|
||||
checkResponse: true,
|
||||
conn: &fakeConnection{},
|
||||
resp: &http.Response{
|
||||
StatusCode: http.StatusSwitchingProtocols,
|
||||
Body: ioutil.NopCloser(&bytes.Buffer{}),
|
||||
},
|
||||
}
|
||||
dialer := spdy.NewDialer(upgrader, &http.Client{Transport: upgrader}, "POST", &url.URL{Host: "something.com", Scheme: "https"})
|
||||
conn, protocol, err := dialer.Dial("protocol1")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if conn != upgrader.conn {
|
||||
t.Errorf("unexpected connection: %#v", conn)
|
||||
}
|
||||
if !upgrader.called {
|
||||
t.Errorf("request not called")
|
||||
}
|
||||
_ = protocol
|
||||
}
|
Reference in New Issue
Block a user