2017-02-01 00:45:59 +00:00
|
|
|
/*
|
|
|
|
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.
|
|
|
|
*/
|
|
|
|
|
2017-02-03 13:41:32 +00:00
|
|
|
package statefulset
|
2017-02-01 00:45:59 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"net/http/httptest"
|
|
|
|
"testing"
|
|
|
|
|
2017-02-03 13:41:32 +00:00
|
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
2017-02-01 00:45:59 +00:00
|
|
|
"k8s.io/apimachinery/pkg/runtime"
|
2017-02-03 13:41:32 +00:00
|
|
|
restclient "k8s.io/client-go/rest"
|
|
|
|
utiltesting "k8s.io/client-go/util/testing"
|
2017-02-01 00:45:59 +00:00
|
|
|
"k8s.io/kubernetes/pkg/api"
|
|
|
|
"k8s.io/kubernetes/pkg/api/testapi"
|
|
|
|
"k8s.io/kubernetes/pkg/api/v1"
|
|
|
|
"k8s.io/kubernetes/pkg/client/clientset_generated/clientset"
|
|
|
|
"k8s.io/kubernetes/pkg/client/clientset_generated/clientset/fake"
|
|
|
|
"k8s.io/kubernetes/pkg/client/testing/core"
|
|
|
|
)
|
|
|
|
|
|
|
|
func newPetClient(client *clientset.Clientset) *apiServerPetClient {
|
|
|
|
return &apiServerPetClient{
|
|
|
|
c: client,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func makeTwoDifferntPCB() (pcb1, pcb2 *pcb) {
|
|
|
|
userAdded := v1.Volume{
|
|
|
|
Name: "test",
|
|
|
|
VolumeSource: v1.VolumeSource{
|
|
|
|
EmptyDir: &v1.EmptyDirVolumeSource{Medium: v1.StorageMediumMemory},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
ps := newStatefulSet(2)
|
|
|
|
pcb1, _ = newPCB("1", ps)
|
|
|
|
pcb2, _ = newPCB("2", ps)
|
|
|
|
pcb2.pod.Spec.Volumes = append(pcb2.pod.Spec.Volumes, userAdded)
|
|
|
|
return pcb1, pcb2
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestUpdatePetWithoutRetry(t *testing.T) {
|
|
|
|
pcb1, pcb2 := makeTwoDifferntPCB()
|
|
|
|
// invalid pet with empty pod
|
|
|
|
invalidPcb := *pcb1
|
|
|
|
invalidPcb.pod = nil
|
|
|
|
|
|
|
|
testCases := []struct {
|
|
|
|
realPet *pcb
|
|
|
|
expectedPet *pcb
|
|
|
|
expectErr bool
|
|
|
|
requests int
|
|
|
|
}{
|
|
|
|
// case 0: error occurs, no need to update
|
|
|
|
{
|
|
|
|
realPet: pcb1,
|
|
|
|
expectedPet: &invalidPcb,
|
|
|
|
expectErr: true,
|
|
|
|
requests: 0,
|
|
|
|
},
|
|
|
|
// case 1: identical pet, no need to update
|
|
|
|
{
|
|
|
|
realPet: pcb1,
|
|
|
|
expectedPet: pcb1,
|
|
|
|
expectErr: false,
|
|
|
|
requests: 0,
|
|
|
|
},
|
|
|
|
// case 2: need to call update once
|
|
|
|
{
|
|
|
|
realPet: pcb1,
|
|
|
|
expectedPet: pcb2,
|
|
|
|
expectErr: false,
|
|
|
|
requests: 1,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for k, tc := range testCases {
|
2017-02-03 13:41:32 +00:00
|
|
|
body := runtime.EncodeOrDie(testapi.Default.Codec(), &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "empty_pod"}})
|
2017-02-01 00:45:59 +00:00
|
|
|
fakeHandler := utiltesting.FakeHandler{
|
|
|
|
StatusCode: 200,
|
|
|
|
ResponseBody: string(body),
|
|
|
|
}
|
|
|
|
testServer := httptest.NewServer(&fakeHandler)
|
|
|
|
|
|
|
|
client := clientset.NewForConfigOrDie(&restclient.Config{Host: testServer.URL, ContentConfig: restclient.ContentConfig{GroupVersion: &api.Registry.GroupOrDie(v1.GroupName).GroupVersion}})
|
|
|
|
petClient := newPetClient(client)
|
|
|
|
err := petClient.Update(tc.realPet, tc.expectedPet)
|
|
|
|
|
|
|
|
if tc.expectErr != (err != nil) {
|
|
|
|
t.Errorf("case %d: expect error(%v), got err: %v", k, tc.expectErr, err)
|
|
|
|
}
|
|
|
|
fakeHandler.ValidateRequestCount(t, tc.requests)
|
|
|
|
testServer.Close()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestUpdatePetWithFailure(t *testing.T) {
|
|
|
|
fakeHandler := utiltesting.FakeHandler{
|
|
|
|
StatusCode: 500,
|
|
|
|
ResponseBody: "{}",
|
|
|
|
}
|
|
|
|
testServer := httptest.NewServer(&fakeHandler)
|
|
|
|
defer testServer.Close()
|
|
|
|
|
|
|
|
client := clientset.NewForConfigOrDie(&restclient.Config{Host: testServer.URL, ContentConfig: restclient.ContentConfig{GroupVersion: &api.Registry.GroupOrDie(v1.GroupName).GroupVersion}})
|
|
|
|
petClient := newPetClient(client)
|
|
|
|
|
|
|
|
pcb1, pcb2 := makeTwoDifferntPCB()
|
|
|
|
|
|
|
|
if err := petClient.Update(pcb1, pcb2); err == nil {
|
|
|
|
t.Errorf("expect error, got nil")
|
|
|
|
}
|
|
|
|
// 1 Update and 1 GET, both of which fail
|
|
|
|
fakeHandler.ValidateRequestCount(t, 2)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestUpdatePetRetrySucceed(t *testing.T) {
|
|
|
|
pcb1, pcb2 := makeTwoDifferntPCB()
|
|
|
|
|
|
|
|
fakeClient := &fake.Clientset{}
|
|
|
|
fakeClient.AddReactor("get", "pods", func(action core.Action) (bool, runtime.Object, error) {
|
|
|
|
return true, pcb2.pod, nil
|
|
|
|
})
|
|
|
|
fakeClient.AddReactor("*", "*", func(action core.Action) (bool, runtime.Object, error) {
|
|
|
|
return true, nil, fmt.Errorf("Fake error")
|
|
|
|
})
|
|
|
|
petClient := apiServerPetClient{
|
|
|
|
c: fakeClient,
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := petClient.Update(pcb1, pcb2); err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
actions := fakeClient.Actions()
|
|
|
|
if len(actions) != 2 {
|
|
|
|
t.Errorf("Expect 2 actions, got %d actions", len(actions))
|
|
|
|
}
|
|
|
|
for i := 0; i < len(actions); i++ {
|
|
|
|
a := actions[i]
|
|
|
|
if a.GetResource().Resource != "pods" {
|
|
|
|
t.Errorf("Unexpected action %+v", a)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
switch action := a.(type) {
|
|
|
|
case core.GetAction:
|
|
|
|
if i%2 == 0 {
|
|
|
|
t.Errorf("Unexpected Get action")
|
|
|
|
}
|
|
|
|
// Make sure the get is for the right pod
|
|
|
|
if action.GetName() != pcb2.pod.Name {
|
|
|
|
t.Errorf("Expected get pod %v, got %q instead", pcb2.pod.Name, action.GetName())
|
|
|
|
}
|
|
|
|
case core.UpdateAction:
|
|
|
|
if i%2 == 1 {
|
|
|
|
t.Errorf("Unexpected Update action")
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
t.Errorf("Unexpected action %+v", a)
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|