github.com/alloyci/alloy-runner@v1.0.1-0.20180222164613-925503ccafd6/executors/kubernetes/exec_test.go (about)

     1  /*
     2  Copyright 2014 The Kubernetes Authors All rights reserved.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package kubernetes
    18  
    19  import (
    20  	"bytes"
    21  	"fmt"
    22  	"io"
    23  	"io/ioutil"
    24  	"net/http"
    25  	"net/url"
    26  	"testing"
    27  
    28  	"k8s.io/kubernetes/pkg/api"
    29  	"k8s.io/kubernetes/pkg/api/testapi"
    30  	"k8s.io/kubernetes/pkg/api/unversioned"
    31  	"k8s.io/kubernetes/pkg/client/restclient"
    32  	client "k8s.io/kubernetes/pkg/client/unversioned"
    33  	"k8s.io/kubernetes/pkg/client/unversioned/fake"
    34  	"k8s.io/kubernetes/pkg/runtime"
    35  )
    36  
    37  type fakeRemoteExecutor struct {
    38  	method  string
    39  	url     *url.URL
    40  	execErr error
    41  }
    42  
    43  func (f *fakeRemoteExecutor) Execute(method string, url *url.URL, config *restclient.Config, stdin io.Reader, stdout, stderr io.Writer, tty bool) error {
    44  	f.method = method
    45  	f.url = url
    46  	return f.execErr
    47  }
    48  
    49  func TestExec(t *testing.T) {
    50  	version := testapi.Default.GroupVersion().Version
    51  	tests := []struct {
    52  		name, version, podPath, execPath, container string
    53  		pod                                         *api.Pod
    54  		tty, execErr                                bool
    55  	}{
    56  		{
    57  			name:     "pod exec",
    58  			version:  version,
    59  			podPath:  "/api/" + version + "/namespaces/test/pods/foo",
    60  			execPath: "/api/" + version + "/namespaces/test/pods/foo/exec",
    61  			pod:      execPod(),
    62  		},
    63  		{
    64  			name:     "pod exec with tty",
    65  			version:  version,
    66  			podPath:  "/api/" + version + "/namespaces/test/pods/foo",
    67  			execPath: "/api/" + version + "/namespaces/test/pods/foo/exec",
    68  			pod:      execPod(),
    69  			tty:      true,
    70  		},
    71  		{
    72  			name:     "pod exec error",
    73  			version:  version,
    74  			podPath:  "/api/" + version + "/namespaces/test/pods/foo",
    75  			execPath: "/api/" + version + "/namespaces/test/pods/foo/exec",
    76  			pod:      execPod(),
    77  			execErr:  true,
    78  		},
    79  	}
    80  
    81  	codec := testapi.Default.Codec()
    82  
    83  	for _, test := range tests {
    84  		// Create a fake kubeClient
    85  		fakeClient := fake.RESTClient{
    86  			Codec: codec,
    87  			Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
    88  				switch p, m := req.URL.Path, req.Method; {
    89  				case p == test.podPath && m == "GET":
    90  					body := objBody(codec, test.pod)
    91  					return &http.Response{StatusCode: http.StatusOK, Body: body, Header: map[string][]string{
    92  						"Content-Type": []string{"application/json"},
    93  					}}, nil
    94  				default:
    95  					// Ensures no GET is performed when deleting by name
    96  					t.Errorf("%s: unexpected request: %s %#v\n%#v", test.name, req.Method, req.URL, req)
    97  					return nil, fmt.Errorf("unexpected request")
    98  				}
    99  			}),
   100  		}
   101  		c := client.NewOrDie(&restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: &unversioned.GroupVersion{Version: test.version}}})
   102  		c.Client = fakeClient.Client
   103  		c.ExtensionsClient.Client = fakeClient.Client
   104  
   105  		ex := &fakeRemoteExecutor{}
   106  		if test.execErr {
   107  			ex.execErr = fmt.Errorf("exec error")
   108  		}
   109  
   110  		bufOut := bytes.NewBuffer([]byte{})
   111  		bufErr := bytes.NewBuffer([]byte{})
   112  		bufIn := bytes.NewBuffer([]byte{})
   113  
   114  		params := &ExecOptions{
   115  			PodName:       "foo",
   116  			ContainerName: "bar",
   117  			Namespace:     "test",
   118  			Command:       []string{"command"},
   119  			In:            bufIn,
   120  			Out:           bufOut,
   121  			Err:           bufErr,
   122  			Stdin:         true,
   123  			Executor:      ex,
   124  			Client:        c,
   125  		}
   126  		err := params.Run()
   127  		if test.execErr && err != ex.execErr {
   128  			t.Errorf("%s: Unexpected exec error: %v", test.name, err)
   129  			continue
   130  		}
   131  		if !test.execErr && err != nil {
   132  			t.Errorf("%s: Unexpected error: %v", test.name, err)
   133  			continue
   134  		}
   135  		if test.execErr {
   136  			continue
   137  		}
   138  		if ex.url.Path != test.execPath {
   139  			t.Errorf("%s: Did not get expected path for exec request", test.name)
   140  			continue
   141  		}
   142  		if ex.method != "POST" {
   143  			t.Errorf("%s: Did not get method for exec request: %s", test.name, ex.method)
   144  		}
   145  	}
   146  }
   147  
   148  func execPod() *api.Pod {
   149  	return &api.Pod{
   150  		ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: "test", ResourceVersion: "10"},
   151  		Spec: api.PodSpec{
   152  			RestartPolicy: api.RestartPolicyAlways,
   153  			DNSPolicy:     api.DNSClusterFirst,
   154  			Containers: []api.Container{
   155  				{
   156  					Name: "bar",
   157  				},
   158  			},
   159  		},
   160  		Status: api.PodStatus{
   161  			Phase: api.PodRunning,
   162  		},
   163  	}
   164  }
   165  
   166  func objBody(codec runtime.Codec, obj runtime.Object) io.ReadCloser {
   167  	return ioutil.NopCloser(bytes.NewReader([]byte(runtime.EncodeOrDie(codec, obj))))
   168  }