feat(*): add kube client test

* for WaitAndGetCompletedPodPhase
pull/1777/head
Vaughn Dice 9 years ago committed by Michelle Noorali
parent 58c05f87d7
commit 9bd12953a9

@ -190,6 +190,10 @@ func (c *fakeReleaseClient) ReleaseHistory(rlsName string, opts ...helm.HistoryO
return &rls.GetHistoryResponse{Releases: c.rels}, c.err
}
func (c *fakeReleaseClient) ReleaseTest(rlsName string, opts ...helm.ReleaseTestOption) (*rls.TestReleaseResponse, error) {
return nil, nil
}
func (c *fakeReleaseClient) Option(opt ...helm.Option) helm.Interface {
return c
}

@ -616,14 +616,16 @@ func scrubValidationError(err error) error {
return err
}
func (c *Client) WaitAndGetCompletedPodStatus(namespace string, reader io.Reader, timeout time.Duration) (api.PodPhase, error) {
// WaitAndGetCompletedPodPhase waits up to a timeout until a pod enters a completed phase
// and returns said phase (PodSucceeded or PodFailed qualify)
func (c *Client) WaitAndGetCompletedPodPhase(namespace string, reader io.Reader, timeout time.Duration) (api.PodPhase, error) {
infos, err := c.Build(namespace, reader)
if err != nil {
return api.PodUnknown, err
}
info := infos[0]
// TODO: should we be checking kind before hand? probably yes.
// TODO: should we be checking kind beforehand? probably yes.
// TODO: add validation to linter: any manifest with a test hook has to be a pod kind?
kind := info.Mapping.GroupVersionKind.Kind
if kind != "Pod" {

@ -18,6 +18,7 @@ package kube
import (
"bytes"
"encoding/json"
"io"
"io/ioutil"
"net/http"
@ -37,6 +38,8 @@ import (
"k8s.io/kubernetes/pkg/kubectl/resource"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/watch"
watchjson "k8s.io/kubernetes/pkg/watch/json"
)
func objBody(codec runtime.Codec, obj runtime.Object) io.ReadCloser {
@ -44,10 +47,18 @@ func objBody(codec runtime.Codec, obj runtime.Object) io.ReadCloser {
}
func newPod(name string) api.Pod {
return newPodWithStatus(name, api.PodStatus{}, "")
}
func newPodWithStatus(name string, status api.PodStatus, namespace string) api.Pod {
ns := api.NamespaceDefault
if namespace != "" {
ns = namespace
}
return api.Pod{
ObjectMeta: api.ObjectMeta{
Name: name,
Namespace: api.NamespaceDefault,
Namespace: ns,
},
Spec: api.PodSpec{
Containers: []api.Container{{
@ -56,6 +67,7 @@ func newPod(name string) api.Pod {
Ports: []api.ContainerPort{{Name: "http", ContainerPort: 80}},
}},
},
Status: status,
}
}
@ -102,6 +114,32 @@ func (f *fakeReaperFactory) Reaper(mapping *meta.RESTMapping) (kubectl.Reaper, e
return f.reaper, nil
}
func newEventResponse(code int, e *watch.Event) (*http.Response, error) {
dispatchedEvent, err := encodeAndMarshalEvent(e)
if err != nil {
return nil, err
}
header := http.Header{}
header.Set("Content-Type", runtime.ContentTypeJSON)
body := ioutil.NopCloser(bytes.NewReader(dispatchedEvent))
return &http.Response{StatusCode: 200, Header: header, Body: body}, nil
}
func encodeAndMarshalEvent(e *watch.Event) ([]byte, error) {
encodedEvent, err := watchjson.Object(testapi.Default.Codec(), e)
if err != nil {
return nil, err
}
marshaledEvent, err := json.Marshal(encodedEvent)
if err != nil {
return nil, err
}
return marshaledEvent, nil
}
func TestUpdate(t *testing.T) {
listA := newPodList("starfish", "otter", "squid")
listB := newPodList("starfish", "otter", "dolphin")
@ -305,48 +343,69 @@ func TestPerform(t *testing.T) {
}
}
func TestWaitAndGetCompletedPodStatus(t *testing.T) {
f, tf, codec, ns := cmdtesting.NewAPIFactory()
actions := make(map[string]string)
testPodList := newPodList("bestpod")
func TestWaitAndGetCompletedPodPhase(t *testing.T) {
tests := []struct {
podPhase api.PodPhase
expectedPhase api.PodPhase
err bool
errMessage string
}{
{
podPhase: api.PodPending,
expectedPhase: api.PodUnknown,
err: true,
errMessage: "timed out waiting for the condition",
}, {
podPhase: api.PodRunning,
expectedPhase: api.PodUnknown,
err: true,
errMessage: "timed out waiting for the condition",
}, {
podPhase: api.PodSucceeded,
expectedPhase: api.PodSucceeded,
}, {
podPhase: api.PodFailed,
expectedPhase: api.PodFailed,
},
}
tf.Client = &fake.RESTClient{
NegotiatedSerializer: ns,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
p, m := req.URL.Path, req.Method
actions[p] = m
count := 0
switch {
case p == "/namespaces/test/pods/bestpod" && m == "GET":
return newResponse(200, &testPodList.Items[0])
case p == "/watch/namespaces/test/pods/bestpod" && m == "GET":
//TODO: fix response
count = count + 1
if count == 1 {
//returns event running
return newResponse(200, &testPodList.Items[0])
}
if count == 2 {
//return event succeeded
for _, tt := range tests {
f, tf, codec, ns := cmdtesting.NewAPIFactory()
actions := make(map[string]string)
var testPodList api.PodList
testPodList.Items = append(testPodList.Items, newPodWithStatus("bestpod", api.PodStatus{Phase: tt.podPhase}, "test"))
tf.Client = &fake.RESTClient{
NegotiatedSerializer: ns,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
p, m := req.URL.Path, req.Method
actions[p] = m
switch {
case p == "/namespaces/test/pods/bestpod" && m == "GET":
return newResponse(200, &testPodList.Items[0])
case p == "/watch/namespaces/test/pods/bestpod" && m == "GET":
event := watch.Event{Type: watch.Added, Object: &testPodList.Items[0]}
return newEventResponse(200, &event)
default:
t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
return nil, nil
}
default:
t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
return nil, nil
}
}),
}
c := &Client{Factory: f}
//stub watchUntil to return no error
}),
}
status, err := c.WaitAndGetCompletedPodStatus("test", objBody(codec, &testPodList), 30*time.Second)
if err != nil {
t.Fatal(err)
}
c := &Client{Factory: f}
if status != api.PodSucceeded {
t.Fatal("Expected %s, got %s", api.PodSucceeded, status)
phase, err := c.WaitAndGetCompletedPodPhase("test", objBody(codec, &testPodList), 1*time.Second)
if (err != nil) != tt.err {
t.Fatalf("Expected error but there was none.")
}
if err != nil && err.Error() != tt.errMessage {
t.Fatalf("Expected error %s, got %s", tt.errMessage, err.Error())
}
if phase != tt.expectedPhase {
t.Fatalf("Expected pod phase %s, got %s", tt.expectedPhase, phase)
}
}
}

@ -138,8 +138,9 @@ type KubeClient interface {
Build(namespace string, reader io.Reader) (kube.Result, error)
//TODO: insert description
WaitAndGetCompletedPodStatus(namespace string, reader io.Reader, timeout time.Duration) (api.PodPhase, error)
// WaitAndGetCompletedPodPhase waits up to a timeout until a pod enters a completed phase
// and returns said phase (PodSucceeded or PodFailed qualify)
WaitAndGetCompletedPodPhase(namespace string, reader io.Reader, timeout time.Duration) (api.PodPhase, error)
}
// PrintingKubeClient implements KubeClient, but simply prints the reader to
@ -185,8 +186,10 @@ func (p *PrintingKubeClient) Build(ns string, reader io.Reader) (kube.Result, er
return []*resource.Info{}, nil
}
func (p *PrintingKubeClient) WaitAndGetCompletedPodStatus(namespace string, reader io.Reader, timeout time.Duration) (api.PodPhase, error) {
return "", nil
// WaitAndGetCompletedPodPhase implements KubeClient WaitAndGetCompletedPodPhase
func (p *PrintingKubeClient) WaitAndGetCompletedPodPhase(namespace string, reader io.Reader, timeout time.Duration) (api.PodPhase, error) {
_, err := io.Copy(p.Out, reader)
return api.PodUnknown, err
}
// Environment provides the context for executing a client request.

@ -57,6 +57,9 @@ func (k *mockKubeClient) WatchUntilReady(ns string, r io.Reader, timeout int64,
func (k *mockKubeClient) Build(ns string, reader io.Reader) (kube.Result, error) {
return []*resource.Info{}, nil
}
func (k *mockKubeClient) WaitAndGetCompletedPodPhase(namespace string, reader io.Reader, timeout time.Duration) (api.PodPhase, error) {
return api.PodUnknown, nil
}
func (k *mockKubeClient) WaitAndGetCompletedPodStatus(namespace string, reader io.Reader, timeout time.Duration) (api.PodPhase, error) {
return "", nil

@ -82,7 +82,7 @@ func runReleaseTests(tests []string, rel *release.Release, kube environment.Kube
if resourceCreated {
b.Reset()
b.WriteString(h)
status, err = kube.WaitAndGetCompletedPodStatus(rel.Namespace, b, time.Duration(timeout)*time.Second)
status, err = kube.WaitAndGetCompletedPodPhase(rel.Namespace, b, time.Duration(timeout)*time.Second)
if err != nil {
resourceCleanExit = false
log.Printf("Error getting status for pod %s: %s", ts.Name, err)
@ -145,7 +145,7 @@ func filterTests(hooks []*release.Hook, releaseName string) ([]*release.Hook, er
}
//TODO: probably don't need to check found
if found == false && len(testHooks) == 0 {
if !found && len(testHooks) == 0 {
return nil, notFoundErr
}

Loading…
Cancel
Save