123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269 |
- /*
- Copyright 2014 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 resource
- import (
- "bytes"
- "fmt"
- "io"
- "io/ioutil"
- "net/http"
- "net/http/httptest"
- "os"
- "reflect"
- "strings"
- "testing"
- "github.com/ghodss/yaml"
- "k8s.io/kubernetes/pkg/api"
- "k8s.io/kubernetes/pkg/api/meta"
- "k8s.io/kubernetes/pkg/api/resource"
- "k8s.io/kubernetes/pkg/api/testapi"
- apitesting "k8s.io/kubernetes/pkg/api/testing"
- "k8s.io/kubernetes/pkg/api/unversioned"
- "k8s.io/kubernetes/pkg/api/v1"
- "k8s.io/kubernetes/pkg/client/unversioned/fake"
- "k8s.io/kubernetes/pkg/runtime"
- "k8s.io/kubernetes/pkg/runtime/serializer/streaming"
- utilerrors "k8s.io/kubernetes/pkg/util/errors"
- utiltesting "k8s.io/kubernetes/pkg/util/testing"
- "k8s.io/kubernetes/pkg/watch"
- "k8s.io/kubernetes/pkg/watch/versioned"
- )
- func stringBody(body string) io.ReadCloser {
- return ioutil.NopCloser(bytes.NewReader([]byte(body)))
- }
- func watchBody(events ...watch.Event) string {
- buf := &bytes.Buffer{}
- codec := testapi.Default.Codec()
- enc := versioned.NewEncoder(streaming.NewEncoder(buf, codec), codec)
- for _, e := range events {
- enc.Encode(&e)
- }
- return buf.String()
- }
- func fakeClient() ClientMapper {
- return ClientMapperFunc(func(*meta.RESTMapping) (RESTClient, error) {
- return &fake.RESTClient{}, nil
- })
- }
- func fakeClientWith(testName string, t *testing.T, data map[string]string) ClientMapper {
- return ClientMapperFunc(func(*meta.RESTMapping) (RESTClient, error) {
- return &fake.RESTClient{
- NegotiatedSerializer: testapi.Default.NegotiatedSerializer(),
- Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
- p := req.URL.Path
- q := req.URL.RawQuery
- if len(q) != 0 {
- p = p + "?" + q
- }
- body, ok := data[p]
- if !ok {
- t.Fatalf("%s: unexpected request: %s (%s)\n%#v", testName, p, req.URL, req)
- }
- header := http.Header{}
- header.Set("Content-Type", runtime.ContentTypeJSON)
- return &http.Response{
- StatusCode: http.StatusOK,
- Header: header,
- Body: stringBody(body),
- }, nil
- }),
- }, nil
- })
- }
- func testData() (*api.PodList, *api.ServiceList) {
- pods := &api.PodList{
- ListMeta: unversioned.ListMeta{
- ResourceVersion: "15",
- },
- Items: []api.Pod{
- {
- ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: "test", ResourceVersion: "10"},
- Spec: apitesting.DeepEqualSafePodSpec(),
- },
- {
- ObjectMeta: api.ObjectMeta{Name: "bar", Namespace: "test", ResourceVersion: "11"},
- Spec: apitesting.DeepEqualSafePodSpec(),
- },
- },
- }
- svc := &api.ServiceList{
- ListMeta: unversioned.ListMeta{
- ResourceVersion: "16",
- },
- Items: []api.Service{
- {
- ObjectMeta: api.ObjectMeta{Name: "baz", Namespace: "test", ResourceVersion: "12"},
- Spec: api.ServiceSpec{
- Type: "ClusterIP",
- SessionAffinity: "None",
- },
- },
- },
- }
- return pods, svc
- }
- func streamTestData() (io.Reader, *api.PodList, *api.ServiceList) {
- pods, svc := testData()
- r, w := io.Pipe()
- go func() {
- defer w.Close()
- w.Write([]byte(runtime.EncodeOrDie(testapi.Default.Codec(), pods)))
- w.Write([]byte(runtime.EncodeOrDie(testapi.Default.Codec(), svc)))
- }()
- return r, pods, svc
- }
- func JSONToYAMLOrDie(in []byte) []byte {
- data, err := yaml.JSONToYAML(in)
- if err != nil {
- panic(err)
- }
- return data
- }
- func streamYAMLTestData() (io.Reader, *api.PodList, *api.ServiceList) {
- pods, svc := testData()
- r, w := io.Pipe()
- go func() {
- defer w.Close()
- w.Write(JSONToYAMLOrDie([]byte(runtime.EncodeOrDie(testapi.Default.Codec(), pods))))
- w.Write([]byte("\n---\n"))
- w.Write(JSONToYAMLOrDie([]byte(runtime.EncodeOrDie(testapi.Default.Codec(), svc))))
- }()
- return r, pods, svc
- }
- func streamTestObject(obj runtime.Object) io.Reader {
- r, w := io.Pipe()
- go func() {
- defer w.Close()
- w.Write([]byte(runtime.EncodeOrDie(testapi.Default.Codec(), obj)))
- }()
- return r
- }
- type testVisitor struct {
- InjectErr error
- Infos []*Info
- }
- func (v *testVisitor) Handle(info *Info, err error) error {
- if err != nil {
- return err
- }
- v.Infos = append(v.Infos, info)
- return v.InjectErr
- }
- func (v *testVisitor) Objects() []runtime.Object {
- objects := []runtime.Object{}
- for i := range v.Infos {
- objects = append(objects, v.Infos[i].Object)
- }
- return objects
- }
- var aPod string = `
- {
- "kind": "Pod",
- "apiVersion": "` + testapi.Default.GroupVersion().String() + `",
- "metadata": {
- "name": "busybox{id}",
- "labels": {
- "name": "busybox{id}"
- }
- },
- "spec": {
- "containers": [
- {
- "name": "busybox",
- "image": "busybox",
- "command": [
- "sleep",
- "3600"
- ],
- "imagePullPolicy": "IfNotPresent"
- }
- ],
- "restartPolicy": "Always"
- }
- }
- `
- var aRC string = `
- {
- "kind": "ReplicationController",
- "apiVersion": "` + testapi.Default.GroupVersion().String() + `",
- "metadata": {
- "name": "busybox{id}",
- "labels": {
- "app": "busybox"
- }
- },
- "spec": {
- "replicas": 1,
- "template": {
- "metadata": {
- "name": "busybox{id}",
- "labels": {
- "app": "busybox{id}"
- }
- },
- "spec": {
- "containers": [
- {
- "name": "busybox",
- "image": "busybox",
- "command": [
- "sleep",
- "3600"
- ],
- "imagePullPolicy": "IfNotPresent"
- }
- ],
- "restartPolicy": "Always"
- }
- }
- }
- }
- `
- func TestPathBuilderAndVersionedObjectNotDefaulted(t *testing.T) {
- b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClient(), testapi.Default.Codec()).
- FilenameParam(false, false, "../../../test/fixtures/pkg/kubectl/builder/kitten-rc.yaml")
- test := &testVisitor{}
- singular := false
- err := b.Do().IntoSingular(&singular).Visit(test.Handle)
- if err != nil || !singular || len(test.Infos) != 1 {
- t.Fatalf("unexpected response: %v %t %#v", err, singular, test.Infos)
- }
- info := test.Infos[0]
- if info.Name != "update-demo-kitten" || info.Namespace != "" || info.Object == nil {
- t.Errorf("unexpected info: %#v", info)
- }
- version, ok := info.VersionedObject.(*v1.ReplicationController)
- // versioned object does not have defaulting applied
- if info.VersionedObject == nil || !ok || version.Spec.Replicas != nil {
- t.Errorf("unexpected versioned object: %#v", info.VersionedObject)
- }
- }
- func TestNodeBuilder(t *testing.T) {
- node := &api.Node{
- ObjectMeta: api.ObjectMeta{Name: "node1", Namespace: "should-not-have", ResourceVersion: "10"},
- Spec: api.NodeSpec{},
- Status: api.NodeStatus{
- Capacity: api.ResourceList{
- api.ResourceCPU: resource.MustParse("1000m"),
- api.ResourceMemory: resource.MustParse("1Mi"),
- },
- },
- }
- r, w := io.Pipe()
- go func() {
- defer w.Close()
- w.Write([]byte(runtime.EncodeOrDie(testapi.Default.Codec(), node)))
- }()
- b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClient(), testapi.Default.Codec()).
- NamespaceParam("test").Stream(r, "STDIN")
- test := &testVisitor{}
- err := b.Do().Visit(test.Handle)
- if err != nil || len(test.Infos) != 1 {
- t.Fatalf("unexpected response: %v %#v", err, test.Infos)
- }
- info := test.Infos[0]
- if info.Name != "node1" || info.Namespace != "" || info.Object == nil {
- t.Errorf("unexpected info: %#v", info)
- }
- }
- func createTestDir(t *testing.T, path string) {
- if err := os.MkdirAll(path, 0750); err != nil {
- t.Fatalf("error creating test dir: %v", err)
- }
- }
- func writeTestFile(t *testing.T, path string, contents string) {
- if err := ioutil.WriteFile(path, []byte(contents), 0644); err != nil {
- t.Fatalf("error creating test file %#v", err)
- }
- }
- func TestPathBuilderWithMultiple(t *testing.T) {
- // create test dirs
- tmpDir, err := utiltesting.MkTmpdir("recursive_test_multiple")
- if err != nil {
- t.Fatalf("error creating temp dir: %v", err)
- }
- createTestDir(t, fmt.Sprintf("%s/%s", tmpDir, "recursive/pod/pod_1"))
- createTestDir(t, fmt.Sprintf("%s/%s", tmpDir, "recursive/rc/rc_1"))
- createTestDir(t, fmt.Sprintf("%s/%s", tmpDir, "inode/hardlink"))
- defer os.RemoveAll(tmpDir)
- // create test files
- writeTestFile(t, fmt.Sprintf("%s/recursive/pod/busybox.json", tmpDir), strings.Replace(aPod, "{id}", "0", -1))
- writeTestFile(t, fmt.Sprintf("%s/recursive/pod/pod_1/busybox.json", tmpDir), strings.Replace(aPod, "{id}", "1", -1))
- writeTestFile(t, fmt.Sprintf("%s/recursive/rc/busybox.json", tmpDir), strings.Replace(aRC, "{id}", "0", -1))
- writeTestFile(t, fmt.Sprintf("%s/recursive/rc/rc_1/busybox.json", tmpDir), strings.Replace(aRC, "{id}", "1", -1))
- writeTestFile(t, fmt.Sprintf("%s/inode/hardlink/busybox.json", tmpDir), strings.Replace(aPod, "{id}", "0", -1))
- if err := os.Link(fmt.Sprintf("%s/inode/hardlink/busybox.json", tmpDir), fmt.Sprintf("%s/inode/hardlink/busybox-link.json", tmpDir)); err != nil {
- t.Fatalf("error creating test file: %v", err)
- }
- tests := []struct {
- name string
- object runtime.Object
- recursive bool
- directory string
- expectedNames []string
- }{
- {"pod", &api.Pod{}, false, "../../../examples/pod", []string{"nginx"}},
- {"recursive-pod", &api.Pod{}, true, fmt.Sprintf("%s/recursive/pod", tmpDir), []string{"busybox0", "busybox1"}},
- {"rc", &api.ReplicationController{}, false, "../../../examples/guestbook/legacy/redis-master-controller.yaml", []string{"redis-master"}},
- {"recursive-rc", &api.ReplicationController{}, true, fmt.Sprintf("%s/recursive/rc", tmpDir), []string{"busybox0", "busybox1"}},
- {"hardlink", &api.Pod{}, false, fmt.Sprintf("%s/inode/hardlink/busybox-link.json", tmpDir), []string{"busybox0"}},
- {"hardlink", &api.Pod{}, true, fmt.Sprintf("%s/inode/hardlink/busybox-link.json", tmpDir), []string{"busybox0"}},
- }
- for _, test := range tests {
- b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClient(), testapi.Default.Codec()).
- FilenameParam(false, test.recursive, test.directory).
- NamespaceParam("test").DefaultNamespace()
- testVisitor := &testVisitor{}
- singular := false
- err := b.Do().IntoSingular(&singular).Visit(testVisitor.Handle)
- if err != nil {
- t.Fatalf("unexpected response: %v %t %#v %s", err, singular, testVisitor.Infos, test.name)
- }
- info := testVisitor.Infos
- for i, v := range info {
- switch test.object.(type) {
- case *api.Pod:
- if _, ok := v.Object.(*api.Pod); !ok || v.Name != test.expectedNames[i] || v.Namespace != "test" {
- t.Errorf("unexpected info: %#v", v)
- }
- case *api.ReplicationController:
- if _, ok := v.Object.(*api.ReplicationController); !ok || v.Name != test.expectedNames[i] || v.Namespace != "test" {
- t.Errorf("unexpected info: %#v", v)
- }
- }
- }
- }
- }
- func TestPathBuilderWithMultipleInvalid(t *testing.T) {
- // create test dirs
- tmpDir, err := utiltesting.MkTmpdir("recursive_test_multiple_invalid")
- if err != nil {
- t.Fatalf("error creating temp dir: %v", err)
- }
- createTestDir(t, fmt.Sprintf("%s/%s", tmpDir, "inode/symlink/pod"))
- defer os.RemoveAll(tmpDir)
- // create test files
- writeTestFile(t, fmt.Sprintf("%s/inode/symlink/pod/busybox.json", tmpDir), strings.Replace(aPod, "{id}", "0", -1))
- if err := os.Symlink(fmt.Sprintf("%s/inode/symlink/pod", tmpDir), fmt.Sprintf("%s/inode/symlink/pod-link", tmpDir)); err != nil {
- t.Fatalf("error creating test file: %v", err)
- }
- if err := os.Symlink(fmt.Sprintf("%s/inode/symlink/loop", tmpDir), fmt.Sprintf("%s/inode/symlink/loop", tmpDir)); err != nil {
- t.Fatalf("error creating test file: %v", err)
- }
- tests := []struct {
- name string
- recursive bool
- directory string
- }{
- {"symlink", false, fmt.Sprintf("%s/inode/symlink/pod-link", tmpDir)},
- {"symlink", true, fmt.Sprintf("%s/inode/symlink/pod-link", tmpDir)},
- {"loop", false, fmt.Sprintf("%s/inode/symlink/loop", tmpDir)},
- {"loop", true, fmt.Sprintf("%s/inode/symlink/loop", tmpDir)},
- }
- for _, test := range tests {
- b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClient(), testapi.Default.Codec()).
- FilenameParam(false, test.recursive, test.directory).
- NamespaceParam("test").DefaultNamespace()
- testVisitor := &testVisitor{}
- singular := false
- err := b.Do().IntoSingular(&singular).Visit(testVisitor.Handle)
- if err == nil {
- t.Fatalf("unexpected response: %v %t %#v %s", err, singular, testVisitor.Infos, test.name)
- }
- }
- }
- func TestDirectoryBuilder(t *testing.T) {
- b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClient(), testapi.Default.Codec()).
- FilenameParam(false, false, "../../../examples/guestbook/legacy").
- NamespaceParam("test").DefaultNamespace()
- test := &testVisitor{}
- singular := false
- err := b.Do().IntoSingular(&singular).Visit(test.Handle)
- if err != nil || singular || len(test.Infos) < 3 {
- t.Fatalf("unexpected response: %v %t %#v", err, singular, test.Infos)
- }
- found := false
- for _, info := range test.Infos {
- if info.Name == "redis-master" && info.Namespace == "test" && info.Object != nil {
- found = true
- break
- }
- }
- if !found {
- t.Errorf("unexpected responses: %#v", test.Infos)
- }
- }
- func TestNamespaceOverride(t *testing.T) {
- s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
- w.WriteHeader(http.StatusOK)
- w.Write([]byte(runtime.EncodeOrDie(testapi.Default.Codec(), &api.Pod{ObjectMeta: api.ObjectMeta{Namespace: "foo", Name: "test"}})))
- }))
- defer s.Close()
- b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClient(), testapi.Default.Codec()).
- FilenameParam(false, false, s.URL).
- NamespaceParam("test")
- test := &testVisitor{}
- err := b.Do().Visit(test.Handle)
- if err != nil || len(test.Infos) != 1 && test.Infos[0].Namespace != "foo" {
- t.Fatalf("unexpected response: %v %#v", err, test.Infos)
- }
- b = NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClient(), testapi.Default.Codec()).
- FilenameParam(true, false, s.URL).
- NamespaceParam("test")
- test = &testVisitor{}
- err = b.Do().Visit(test.Handle)
- if err == nil {
- t.Fatalf("expected namespace error. got: %#v", test.Infos)
- }
- }
- func TestURLBuilder(t *testing.T) {
- s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
- w.WriteHeader(http.StatusOK)
- w.Write([]byte(runtime.EncodeOrDie(testapi.Default.Codec(), &api.Pod{ObjectMeta: api.ObjectMeta{Namespace: "foo", Name: "test"}})))
- w.Write([]byte(runtime.EncodeOrDie(testapi.Default.Codec(), &api.Pod{ObjectMeta: api.ObjectMeta{Namespace: "foo", Name: "test1"}})))
- }))
- defer s.Close()
- b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClient(), testapi.Default.Codec()).
- FilenameParam(false, false, s.URL).
- NamespaceParam("foo")
- test := &testVisitor{}
- err := b.Do().Visit(test.Handle)
- if err != nil || len(test.Infos) != 2 {
- t.Fatalf("unexpected response: %v %#v", err, test.Infos)
- }
- info := test.Infos[0]
- if info.Name != "test" || info.Namespace != "foo" || info.Object == nil {
- t.Errorf("unexpected info: %#v", info)
- }
- info = test.Infos[1]
- if info.Name != "test1" || info.Namespace != "foo" || info.Object == nil {
- t.Errorf("unexpected info: %#v", info)
- }
- }
- func TestURLBuilderRequireNamespace(t *testing.T) {
- s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
- w.WriteHeader(http.StatusOK)
- w.Write([]byte(runtime.EncodeOrDie(testapi.Default.Codec(), &api.Pod{ObjectMeta: api.ObjectMeta{Namespace: "foo", Name: "test"}})))
- }))
- defer s.Close()
- b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClient(), testapi.Default.Codec()).
- FilenameParam(false, false, s.URL).
- NamespaceParam("test").RequireNamespace()
- test := &testVisitor{}
- singular := false
- err := b.Do().IntoSingular(&singular).Visit(test.Handle)
- if err == nil || !singular || len(test.Infos) != 0 {
- t.Fatalf("unexpected response: %v %t %#v", err, singular, test.Infos)
- }
- }
- func TestResourceByName(t *testing.T) {
- pods, _ := testData()
- b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClientWith("", t, map[string]string{
- "/namespaces/test/pods/foo": runtime.EncodeOrDie(testapi.Default.Codec(), &pods.Items[0]),
- }), testapi.Default.Codec()).
- NamespaceParam("test")
- test := &testVisitor{}
- singular := false
- if b.Do().Err() == nil {
- t.Errorf("unexpected non-error")
- }
- b.ResourceTypeOrNameArgs(true, "pods", "foo")
- err := b.Do().IntoSingular(&singular).Visit(test.Handle)
- if err != nil || !singular || len(test.Infos) != 1 {
- t.Fatalf("unexpected response: %v %t %#v", err, singular, test.Infos)
- }
- if !reflect.DeepEqual(&pods.Items[0], test.Objects()[0]) {
- t.Errorf("unexpected object: %#v", test.Objects()[0])
- }
- mapping, err := b.Do().ResourceMapping()
- if err != nil {
- t.Fatalf("unexpected error: %v", err)
- }
- if mapping.Resource != "pods" {
- t.Errorf("unexpected resource mapping: %#v", mapping)
- }
- }
- func TestMultipleResourceByTheSameName(t *testing.T) {
- pods, svcs := testData()
- b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClientWith("", t, map[string]string{
- "/namespaces/test/pods/foo": runtime.EncodeOrDie(testapi.Default.Codec(), &pods.Items[0]),
- "/namespaces/test/pods/baz": runtime.EncodeOrDie(testapi.Default.Codec(), &pods.Items[1]),
- "/namespaces/test/services/foo": runtime.EncodeOrDie(testapi.Default.Codec(), &svcs.Items[0]),
- "/namespaces/test/services/baz": runtime.EncodeOrDie(testapi.Default.Codec(), &svcs.Items[0]),
- }), testapi.Default.Codec()).
- NamespaceParam("test")
- test := &testVisitor{}
- singular := false
- if b.Do().Err() == nil {
- t.Errorf("unexpected non-error")
- }
- b.ResourceTypeOrNameArgs(true, "pods,services", "foo", "baz")
- err := b.Do().IntoSingular(&singular).Visit(test.Handle)
- if err != nil || singular || len(test.Infos) != 4 {
- t.Fatalf("unexpected response: %v %t %#v", err, singular, test.Infos)
- }
- if !api.Semantic.DeepDerivative([]runtime.Object{&pods.Items[0], &pods.Items[1], &svcs.Items[0], &svcs.Items[0]}, test.Objects()) {
- t.Errorf("unexpected visited objects: %#v", test.Objects())
- }
- if _, err := b.Do().ResourceMapping(); err == nil {
- t.Errorf("unexpected non-error")
- }
- }
- func TestResourceNames(t *testing.T) {
- pods, svc := testData()
- b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClientWith("", t, map[string]string{
- "/namespaces/test/pods/foo": runtime.EncodeOrDie(testapi.Default.Codec(), &pods.Items[0]),
- "/namespaces/test/services/baz": runtime.EncodeOrDie(testapi.Default.Codec(), &svc.Items[0]),
- }), testapi.Default.Codec()).
- NamespaceParam("test")
- test := &testVisitor{}
- if b.Do().Err() == nil {
- t.Errorf("unexpected non-error")
- }
- b.ResourceNames("pods", "foo", "services/baz")
- err := b.Do().Visit(test.Handle)
- if err != nil || len(test.Infos) != 2 {
- t.Fatalf("unexpected response: %v %#v", err, test.Infos)
- }
- if !reflect.DeepEqual(&pods.Items[0], test.Objects()[0]) {
- t.Errorf("unexpected object: \n%#v, expected: \n%#v", test.Objects()[0], &pods.Items[0])
- }
- if !reflect.DeepEqual(&svc.Items[0], test.Objects()[1]) {
- t.Errorf("unexpected object: \n%#v, expected: \n%#v", test.Objects()[1], &svc.Items[0])
- }
- }
- func TestResourceNamesWithoutResource(t *testing.T) {
- pods, svc := testData()
- b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClientWith("", t, map[string]string{
- "/namespaces/test/pods/foo": runtime.EncodeOrDie(testapi.Default.Codec(), &pods.Items[0]),
- "/namespaces/test/services/baz": runtime.EncodeOrDie(testapi.Default.Codec(), &svc.Items[0]),
- }), testapi.Default.Codec()).
- NamespaceParam("test")
- test := &testVisitor{}
- if b.Do().Err() == nil {
- t.Errorf("unexpected non-error")
- }
- b.ResourceNames("", "foo", "services/baz")
- err := b.Do().Visit(test.Handle)
- if err == nil || !strings.Contains(err.Error(), "must be RESOURCE/NAME") {
- t.Fatalf("unexpected response: %v", err)
- }
- }
- func TestResourceByNameWithoutRequireObject(t *testing.T) {
- b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClientWith("", t, map[string]string{}), testapi.Default.Codec()).
- NamespaceParam("test")
- test := &testVisitor{}
- singular := false
- if b.Do().Err() == nil {
- t.Errorf("unexpected non-error")
- }
- b.ResourceTypeOrNameArgs(true, "pods", "foo").RequireObject(false)
- err := b.Do().IntoSingular(&singular).Visit(test.Handle)
- if err != nil || !singular || len(test.Infos) != 1 {
- t.Fatalf("unexpected response: %v %t %#v", err, singular, test.Infos)
- }
- if test.Infos[0].Name != "foo" {
- t.Errorf("unexpected name: %#v", test.Infos[0].Name)
- }
- if test.Infos[0].Object != nil {
- t.Errorf("unexpected object: %#v", test.Infos[0].Object)
- }
- mapping, err := b.Do().ResourceMapping()
- if err != nil {
- t.Fatalf("unexpected error: %v", err)
- }
- if mapping.GroupVersionKind.Kind != "Pod" || mapping.Resource != "pods" {
- t.Errorf("unexpected resource mapping: %#v", mapping)
- }
- }
- func TestResourceByNameAndEmptySelector(t *testing.T) {
- pods, _ := testData()
- b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClientWith("", t, map[string]string{
- "/namespaces/test/pods/foo": runtime.EncodeOrDie(testapi.Default.Codec(), &pods.Items[0]),
- }), testapi.Default.Codec()).
- NamespaceParam("test").
- SelectorParam("").
- ResourceTypeOrNameArgs(true, "pods", "foo")
- singular := false
- infos, err := b.Do().IntoSingular(&singular).Infos()
- if err != nil || !singular || len(infos) != 1 {
- t.Fatalf("unexpected response: %v %t %#v", err, singular, infos)
- }
- if !reflect.DeepEqual(&pods.Items[0], infos[0].Object) {
- t.Errorf("unexpected object: %#v", infos[0])
- }
- mapping, err := b.Do().ResourceMapping()
- if err != nil {
- t.Fatalf("unexpected error: %v", err)
- }
- if mapping.Resource != "pods" {
- t.Errorf("unexpected resource mapping: %#v", mapping)
- }
- }
- func TestSelector(t *testing.T) {
- pods, svc := testData()
- labelKey := unversioned.LabelSelectorQueryParam(testapi.Default.GroupVersion().String())
- b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClientWith("", t, map[string]string{
- "/namespaces/test/pods?" + labelKey + "=a%3Db": runtime.EncodeOrDie(testapi.Default.Codec(), pods),
- "/namespaces/test/services?" + labelKey + "=a%3Db": runtime.EncodeOrDie(testapi.Default.Codec(), svc),
- }), testapi.Default.Codec()).
- SelectorParam("a=b").
- NamespaceParam("test").
- Flatten()
- test := &testVisitor{}
- singular := false
- if b.Do().Err() == nil {
- t.Errorf("unexpected non-error")
- }
- b.ResourceTypeOrNameArgs(true, "pods,service")
- err := b.Do().IntoSingular(&singular).Visit(test.Handle)
- if err != nil || singular || len(test.Infos) != 3 {
- t.Fatalf("unexpected response: %v %t %#v", err, singular, test.Infos)
- }
- if !api.Semantic.DeepDerivative([]runtime.Object{&pods.Items[0], &pods.Items[1], &svc.Items[0]}, test.Objects()) {
- t.Errorf("unexpected visited objects: %#v", test.Objects())
- }
- if _, err := b.Do().ResourceMapping(); err == nil {
- t.Errorf("unexpected non-error")
- }
- }
- func TestSelectorRequiresKnownTypes(t *testing.T) {
- b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClient(), testapi.Default.Codec()).
- SelectorParam("a=b").
- NamespaceParam("test").
- ResourceTypes("unknown")
- if b.Do().Err() == nil {
- t.Errorf("unexpected non-error")
- }
- }
- func TestSingleResourceType(t *testing.T) {
- b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClient(), testapi.Default.Codec()).
- SelectorParam("a=b").
- SingleResourceType().
- ResourceTypeOrNameArgs(true, "pods,services")
- if b.Do().Err() == nil {
- t.Errorf("unexpected non-error")
- }
- }
- func TestResourceTuple(t *testing.T) {
- expectNoErr := func(err error) bool { return err == nil }
- expectErr := func(err error) bool { return err != nil }
- testCases := map[string]struct {
- args []string
- errFn func(error) bool
- }{
- "valid": {
- args: []string{"pods/foo"},
- errFn: expectNoErr,
- },
- "valid multiple with name indirection": {
- args: []string{"pods/foo", "pod/bar"},
- errFn: expectNoErr,
- },
- "valid multiple with namespaced and non-namespaced types": {
- args: []string{"nodes/foo", "pod/bar"},
- errFn: expectNoErr,
- },
- "mixed arg types": {
- args: []string{"pods/foo", "bar"},
- errFn: expectErr,
- },
- /*"missing resource": {
- args: []string{"pods/foo2"},
- errFn: expectNoErr, // not an error because resources are lazily visited
- },*/
- "comma in resource": {
- args: []string{",pods/foo"},
- errFn: expectErr,
- },
- "multiple types in resource": {
- args: []string{"pods,services/foo"},
- errFn: expectErr,
- },
- "unknown resource type": {
- args: []string{"unknown/foo"},
- errFn: expectErr,
- },
- "leading slash": {
- args: []string{"/bar"},
- errFn: expectErr,
- },
- "trailing slash": {
- args: []string{"bar/"},
- errFn: expectErr,
- },
- }
- for k, testCase := range testCases {
- for _, requireObject := range []bool{true, false} {
- expectedRequests := map[string]string{}
- if requireObject {
- pods, _ := testData()
- expectedRequests = map[string]string{
- "/namespaces/test/pods/foo": runtime.EncodeOrDie(testapi.Default.Codec(), &pods.Items[0]),
- "/namespaces/test/pods/bar": runtime.EncodeOrDie(testapi.Default.Codec(), &pods.Items[0]),
- "/nodes/foo": runtime.EncodeOrDie(testapi.Default.Codec(), &api.Node{ObjectMeta: api.ObjectMeta{Name: "foo"}}),
- }
- }
- b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClientWith(k, t, expectedRequests), testapi.Default.Codec()).
- NamespaceParam("test").DefaultNamespace().
- ResourceTypeOrNameArgs(true, testCase.args...).RequireObject(requireObject)
- r := b.Do()
- if !testCase.errFn(r.Err()) {
- t.Errorf("%s: unexpected error: %v", k, r.Err())
- }
- if r.Err() != nil {
- continue
- }
- switch {
- case (r.singular && len(testCase.args) != 1),
- (!r.singular && len(testCase.args) == 1):
- t.Errorf("%s: result had unexpected singular value", k)
- }
- info, err := r.Infos()
- if err != nil {
- // test error
- continue
- }
- if len(info) != len(testCase.args) {
- t.Errorf("%s: unexpected number of infos returned: %#v", k, info)
- }
- }
- }
- }
- func TestStream(t *testing.T) {
- r, pods, rc := streamTestData()
- b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClient(), testapi.Default.Codec()).
- NamespaceParam("test").Stream(r, "STDIN").Flatten()
- test := &testVisitor{}
- singular := false
- err := b.Do().IntoSingular(&singular).Visit(test.Handle)
- if err != nil || singular || len(test.Infos) != 3 {
- t.Fatalf("unexpected response: %v %t %#v", err, singular, test.Infos)
- }
- if !api.Semantic.DeepDerivative([]runtime.Object{&pods.Items[0], &pods.Items[1], &rc.Items[0]}, test.Objects()) {
- t.Errorf("unexpected visited objects: %#v", test.Objects())
- }
- }
- func TestYAMLStream(t *testing.T) {
- r, pods, rc := streamYAMLTestData()
- b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClient(), testapi.Default.Codec()).
- NamespaceParam("test").Stream(r, "STDIN").Flatten()
- test := &testVisitor{}
- singular := false
- err := b.Do().IntoSingular(&singular).Visit(test.Handle)
- if err != nil || singular || len(test.Infos) != 3 {
- t.Fatalf("unexpected response: %v %t %#v", err, singular, test.Infos)
- }
- if !api.Semantic.DeepDerivative([]runtime.Object{&pods.Items[0], &pods.Items[1], &rc.Items[0]}, test.Objects()) {
- t.Errorf("unexpected visited objects: %#v", test.Objects())
- }
- }
- func TestMultipleObject(t *testing.T) {
- r, pods, svc := streamTestData()
- obj, err := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClient(), testapi.Default.Codec()).
- NamespaceParam("test").Stream(r, "STDIN").Flatten().
- Do().Object()
- if err != nil {
- t.Fatalf("unexpected error: %v", err)
- }
- expected := &api.List{
- Items: []runtime.Object{
- &pods.Items[0],
- &pods.Items[1],
- &svc.Items[0],
- },
- }
- if !api.Semantic.DeepDerivative(expected, obj) {
- t.Errorf("unexpected visited objects: %#v", obj)
- }
- }
- func TestContinueOnErrorVisitor(t *testing.T) {
- r, _, _ := streamTestData()
- req := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClient(), testapi.Default.Codec()).
- ContinueOnError().
- NamespaceParam("test").Stream(r, "STDIN").Flatten().
- Do()
- count := 0
- testErr := fmt.Errorf("test error")
- err := req.Visit(func(_ *Info, _ error) error {
- count++
- if count > 1 {
- return testErr
- }
- return nil
- })
- if err == nil {
- t.Fatalf("unexpected error: %v", err)
- }
- if count != 3 {
- t.Fatalf("did not visit all infos: %d", count)
- }
- agg, ok := err.(utilerrors.Aggregate)
- if !ok {
- t.Fatalf("unexpected error: %v", err)
- }
- if len(agg.Errors()) != 2 || agg.Errors()[0] != testErr || agg.Errors()[1] != testErr {
- t.Fatalf("unexpected error: %v", err)
- }
- }
- func TestSingularObject(t *testing.T) {
- obj, err := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClient(), testapi.Default.Codec()).
- NamespaceParam("test").DefaultNamespace().
- FilenameParam(false, false, "../../../examples/guestbook/legacy/redis-master-controller.yaml").
- Flatten().
- Do().Object()
- if err != nil {
- t.Fatalf("unexpected error: %v", err)
- }
- rc, ok := obj.(*api.ReplicationController)
- if !ok {
- t.Fatalf("unexpected object: %#v", obj)
- }
- if rc.Name != "redis-master" || rc.Namespace != "test" {
- t.Errorf("unexpected controller: %#v", rc)
- }
- }
- func TestSingularObjectNoExtension(t *testing.T) {
- obj, err := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClient(), testapi.Default.Codec()).
- NamespaceParam("test").DefaultNamespace().
- FilenameParam(false, false, "../../../examples/pod").
- Flatten().
- Do().Object()
- if err != nil {
- t.Fatalf("unexpected error: %v", err)
- }
- pod, ok := obj.(*api.Pod)
- if !ok {
- t.Fatalf("unexpected object: %#v", obj)
- }
- if pod.Name != "nginx" || pod.Namespace != "test" {
- t.Errorf("unexpected pod: %#v", pod)
- }
- }
- func TestSingularRootScopedObject(t *testing.T) {
- node := &api.Node{ObjectMeta: api.ObjectMeta{Name: "test"}, Spec: api.NodeSpec{ExternalID: "test"}}
- r := streamTestObject(node)
- infos, err := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClient(), testapi.Default.Codec()).
- NamespaceParam("test").DefaultNamespace().
- Stream(r, "STDIN").
- Flatten().
- Do().Infos()
- if err != nil || len(infos) != 1 {
- t.Fatalf("unexpected error: %v", err)
- }
- if infos[0].Namespace != "" {
- t.Errorf("namespace should be empty: %#v", infos[0])
- }
- n, ok := infos[0].Object.(*api.Node)
- if !ok {
- t.Fatalf("unexpected object: %#v", infos[0].Object)
- }
- if n.Name != "test" || n.Namespace != "" {
- t.Errorf("unexpected object: %#v", n)
- }
- }
- func TestListObject(t *testing.T) {
- pods, _ := testData()
- labelKey := unversioned.LabelSelectorQueryParam(testapi.Default.GroupVersion().String())
- b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClientWith("", t, map[string]string{
- "/namespaces/test/pods?" + labelKey + "=a%3Db": runtime.EncodeOrDie(testapi.Default.Codec(), pods),
- }), testapi.Default.Codec()).
- SelectorParam("a=b").
- NamespaceParam("test").
- ResourceTypeOrNameArgs(true, "pods").
- Flatten()
- obj, err := b.Do().Object()
- if err != nil {
- t.Fatalf("unexpected error: %v", err)
- }
- list, ok := obj.(*api.List)
- if !ok {
- t.Fatalf("unexpected object: %#v", obj)
- }
- if list.ResourceVersion != pods.ResourceVersion || len(list.Items) != 2 {
- t.Errorf("unexpected list: %#v", list)
- }
- mapping, err := b.Do().ResourceMapping()
- if err != nil {
- t.Fatalf("unexpected error: %v", err)
- }
- if mapping.Resource != "pods" {
- t.Errorf("unexpected resource mapping: %#v", mapping)
- }
- }
- func TestListObjectWithDifferentVersions(t *testing.T) {
- pods, svc := testData()
- labelKey := unversioned.LabelSelectorQueryParam(testapi.Default.GroupVersion().String())
- obj, err := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClientWith("", t, map[string]string{
- "/namespaces/test/pods?" + labelKey + "=a%3Db": runtime.EncodeOrDie(testapi.Default.Codec(), pods),
- "/namespaces/test/services?" + labelKey + "=a%3Db": runtime.EncodeOrDie(testapi.Default.Codec(), svc),
- }), testapi.Default.Codec()).
- SelectorParam("a=b").
- NamespaceParam("test").
- ResourceTypeOrNameArgs(true, "pods,services").
- Flatten().
- Do().Object()
- if err != nil {
- t.Fatalf("unexpected error: %v", err)
- }
- list, ok := obj.(*api.List)
- if !ok {
- t.Fatalf("unexpected object: %#v", obj)
- }
- // resource version differs between type lists, so it's not possible to get a single version.
- if list.ResourceVersion != "" || len(list.Items) != 3 {
- t.Errorf("unexpected list: %#v", list)
- }
- }
- func TestWatch(t *testing.T) {
- _, svc := testData()
- w, err := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClientWith("", t, map[string]string{
- "/watch/namespaces/test/services/redis-master?resourceVersion=12": watchBody(watch.Event{
- Type: watch.Added,
- Object: &svc.Items[0],
- }),
- }), testapi.Default.Codec()).
- NamespaceParam("test").DefaultNamespace().
- FilenameParam(false, false, "../../../examples/guestbook/redis-master-service.yaml").Flatten().
- Do().Watch("12")
- if err != nil {
- t.Fatalf("unexpected error: %v", err)
- }
- defer w.Stop()
- ch := w.ResultChan()
- select {
- case obj := <-ch:
- if obj.Type != watch.Added {
- t.Fatalf("unexpected watch event %#v", obj)
- }
- service, ok := obj.Object.(*api.Service)
- if !ok {
- t.Fatalf("unexpected object: %#v", obj)
- }
- if service.Name != "baz" || service.ResourceVersion != "12" {
- t.Errorf("unexpected service: %#v", service)
- }
- }
- }
- func TestWatchMultipleError(t *testing.T) {
- _, err := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClient(), testapi.Default.Codec()).
- NamespaceParam("test").DefaultNamespace().
- FilenameParam(false, false, "../../../examples/guestbook/legacy/redis-master-controller.yaml").Flatten().
- FilenameParam(false, false, "../../../examples/guestbook/legacy/redis-master-controller.yaml").Flatten().
- Do().Watch("")
- if err == nil {
- t.Fatalf("unexpected non-error")
- }
- }
- func TestLatest(t *testing.T) {
- r, _, _ := streamTestData()
- newPod := &api.Pod{
- ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: "test", ResourceVersion: "13"},
- }
- newPod2 := &api.Pod{
- ObjectMeta: api.ObjectMeta{Name: "bar", Namespace: "test", ResourceVersion: "14"},
- }
- newSvc := &api.Service{
- ObjectMeta: api.ObjectMeta{Name: "baz", Namespace: "test", ResourceVersion: "15"},
- }
- b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClientWith("", t, map[string]string{
- "/namespaces/test/pods/foo": runtime.EncodeOrDie(testapi.Default.Codec(), newPod),
- "/namespaces/test/pods/bar": runtime.EncodeOrDie(testapi.Default.Codec(), newPod2),
- "/namespaces/test/services/baz": runtime.EncodeOrDie(testapi.Default.Codec(), newSvc),
- }), testapi.Default.Codec()).
- NamespaceParam("other").Stream(r, "STDIN").Flatten().Latest()
- test := &testVisitor{}
- singular := false
- err := b.Do().IntoSingular(&singular).Visit(test.Handle)
- if err != nil || singular || len(test.Infos) != 3 {
- t.Fatalf("unexpected response: %v %t %#v", err, singular, test.Infos)
- }
- if !api.Semantic.DeepDerivative([]runtime.Object{newPod, newPod2, newSvc}, test.Objects()) {
- t.Errorf("unexpected visited objects: %#v", test.Objects())
- }
- }
- func TestReceiveMultipleErrors(t *testing.T) {
- pods, svc := testData()
- r, w := io.Pipe()
- go func() {
- defer w.Close()
- w.Write([]byte(`{}`))
- w.Write([]byte(runtime.EncodeOrDie(testapi.Default.Codec(), &pods.Items[0])))
- }()
- r2, w2 := io.Pipe()
- go func() {
- defer w2.Close()
- w2.Write([]byte(`{}`))
- w2.Write([]byte(runtime.EncodeOrDie(testapi.Default.Codec(), &svc.Items[0])))
- }()
- b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClient(), testapi.Default.Codec()).
- Stream(r, "1").Stream(r2, "2").
- ContinueOnError()
- test := &testVisitor{}
- singular := false
- err := b.Do().IntoSingular(&singular).Visit(test.Handle)
- if err == nil || singular || len(test.Infos) != 2 {
- t.Fatalf("unexpected response: %v %t %#v", err, singular, test.Infos)
- }
- errs, ok := err.(utilerrors.Aggregate)
- if !ok {
- t.Fatalf("unexpected error: %v", reflect.TypeOf(err))
- }
- if len(errs.Errors()) != 2 {
- t.Errorf("unexpected errors %v", errs)
- }
- }
- func TestReplaceAliases(t *testing.T) {
- tests := []struct {
- name string
- arg string
- expected string
- }{
- {
- name: "no-replacement",
- arg: "service",
- expected: "service",
- },
- {
- name: "all-replacement",
- arg: "all",
- expected: "rc,svc,pods,pvc",
- },
- {
- name: "alias-in-comma-separated-arg",
- arg: "all,secrets",
- expected: "rc,svc,pods,pvc,secrets",
- },
- }
- b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClient(), testapi.Default.Codec())
- for _, test := range tests {
- replaced := b.replaceAliases(test.arg)
- if replaced != test.expected {
- t.Errorf("%s: unexpected argument: expected %s, got %s", test.name, test.expected, replaced)
- }
- }
- }
- func TestHasNames(t *testing.T) {
- tests := []struct {
- args []string
- expectedHasName bool
- expectedError error
- }{
- {
- args: []string{""},
- expectedHasName: false,
- expectedError: nil,
- },
- {
- args: []string{"rc"},
- expectedHasName: false,
- expectedError: nil,
- },
- {
- args: []string{"rc,pod,svc"},
- expectedHasName: false,
- expectedError: nil,
- },
- {
- args: []string{"rc/foo"},
- expectedHasName: true,
- expectedError: nil,
- },
- {
- args: []string{"rc", "foo"},
- expectedHasName: true,
- expectedError: nil,
- },
- {
- args: []string{"rc,pod,svc", "foo"},
- expectedHasName: true,
- expectedError: nil,
- },
- {
- args: []string{"rc/foo", "rc/bar", "rc/zee"},
- expectedHasName: true,
- expectedError: nil,
- },
- {
- args: []string{"rc/foo", "bar"},
- expectedHasName: false,
- expectedError: fmt.Errorf("there is no need to specify a resource type as a separate argument when passing arguments in resource/name form (e.g. 'resource.test get resource/<resource_name>' instead of 'resource.test get resource resource/<resource_name>'"),
- },
- }
- for _, test := range tests {
- hasNames, err := HasNames(test.args)
- if !reflect.DeepEqual(test.expectedError, err) {
- t.Errorf("expected HasName to error %v, got %s", test.expectedError, err)
- }
- if hasNames != test.expectedHasName {
- t.Errorf("expected HasName to return %v for %s", test.expectedHasName, test.args)
- }
- }
- }
|