Unittests

pull/6/head
bprashanth 2016-10-28 17:14:33 -07:00
parent aee5b8099c
commit 11638e9ee1
10 changed files with 152 additions and 5 deletions

View File

@ -118,6 +118,11 @@ func (f *FakeRuntime) ClearCalls() {
f.StatusErr = nil f.StatusErr = nil
} }
// UpdatePodCIDR fulfills the cri interface.
func (f *FakeRuntime) UpdatePodCIDR(c string) error {
return nil
}
func (f *FakeRuntime) assertList(expect []string, test []string) error { func (f *FakeRuntime) assertList(expect []string, test []string) error {
if !reflect.DeepEqual(expect, test) { if !reflect.DeepEqual(expect, test) {
return fmt.Errorf("expected %#v, got %#v", expect, test) return fmt.Errorf("expected %#v, got %#v", expect, test)

View File

@ -153,3 +153,8 @@ func (r *Mock) ImageStats() (*ImageStats, error) {
args := r.Called() args := r.Called()
return args.Get(0).(*ImageStats), args.Error(1) return args.Get(0).(*ImageStats), args.Error(1)
} }
// UpdatePodCIDR fulfills the cri interface.
func (r *Mock) UpdatePodCIDR(c string) error {
return nil
}

View File

@ -27,11 +27,15 @@ go_library(
tags = ["automanaged"], tags = ["automanaged"],
deps = [ deps = [
"//pkg/api:go_default_library", "//pkg/api:go_default_library",
"//pkg/apis/componentconfig:go_default_library",
"//pkg/kubelet/api:go_default_library", "//pkg/kubelet/api:go_default_library",
"//pkg/kubelet/api/v1alpha1/runtime:go_default_library", "//pkg/kubelet/api/v1alpha1/runtime:go_default_library",
"//pkg/kubelet/container:go_default_library", "//pkg/kubelet/container:go_default_library",
"//pkg/kubelet/dockertools:go_default_library", "//pkg/kubelet/dockertools:go_default_library",
"//pkg/kubelet/leaky:go_default_library", "//pkg/kubelet/leaky:go_default_library",
"//pkg/kubelet/network:go_default_library",
"//pkg/kubelet/network/cni:go_default_library",
"//pkg/kubelet/network/kubenet:go_default_library",
"//pkg/kubelet/qos:go_default_library", "//pkg/kubelet/qos:go_default_library",
"//pkg/kubelet/server/streaming:go_default_library", "//pkg/kubelet/server/streaming:go_default_library",
"//pkg/kubelet/types:go_default_library", "//pkg/kubelet/types:go_default_library",
@ -63,12 +67,16 @@ go_test(
deps = [ deps = [
"//pkg/api:go_default_library", "//pkg/api:go_default_library",
"//pkg/kubelet/api/v1alpha1/runtime:go_default_library", "//pkg/kubelet/api/v1alpha1/runtime:go_default_library",
"//pkg/kubelet/container:go_default_library",
"//pkg/kubelet/container/testing:go_default_library", "//pkg/kubelet/container/testing:go_default_library",
"//pkg/kubelet/dockertools:go_default_library", "//pkg/kubelet/dockertools:go_default_library",
"//pkg/kubelet/network:go_default_library",
"//pkg/kubelet/network/mock_network:go_default_library",
"//pkg/kubelet/types:go_default_library", "//pkg/kubelet/types:go_default_library",
"//pkg/security/apparmor:go_default_library", "//pkg/security/apparmor:go_default_library",
"//pkg/util/clock:go_default_library", "//pkg/util/clock:go_default_library",
"//vendor:github.com/docker/engine-api/types", "//vendor:github.com/docker/engine-api/types",
"//vendor:github.com/golang/mock/gomock",
"//vendor:github.com/stretchr/testify/assert", "//vendor:github.com/stretchr/testify/assert",
], ],
) )

View File

@ -25,6 +25,7 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
runtimeApi "k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime" runtimeApi "k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
"k8s.io/kubernetes/pkg/kubelet/types" "k8s.io/kubernetes/pkg/kubelet/types"
) )
@ -99,12 +100,13 @@ func TestSandboxStatus(t *testing.T) {
state := runtimeApi.PodSandBoxState_READY state := runtimeApi.PodSandBoxState_READY
ct := int64(0) ct := int64(0)
hostNetwork := false
expected := &runtimeApi.PodSandboxStatus{ expected := &runtimeApi.PodSandboxStatus{
State: &state, State: &state,
CreatedAt: &ct, CreatedAt: &ct,
Metadata: config.Metadata, Metadata: config.Metadata,
Network: &runtimeApi.PodSandboxNetworkStatus{Ip: &fakeIP}, Network: &runtimeApi.PodSandboxNetworkStatus{Ip: &fakeIP},
Linux: &runtimeApi.LinuxPodSandboxStatus{Namespaces: &runtimeApi.Namespace{Network: &fakeNS}}, Linux: &runtimeApi.LinuxPodSandboxStatus{Namespaces: &runtimeApi.Namespace{Network: &fakeNS, Options: &runtimeApi.NamespaceOption{HostNetwork: &hostNetwork}}},
Labels: labels, Labels: labels,
Annotations: annotations, Annotations: annotations,
} }
@ -138,3 +140,57 @@ func TestSandboxStatus(t *testing.T) {
status, err = ds.PodSandboxStatus(id) status, err = ds.PodSandboxStatus(id)
assert.Error(t, err, fmt.Sprintf("status of sandbox: %+v", status)) assert.Error(t, err, fmt.Sprintf("status of sandbox: %+v", status))
} }
// TestNetworkPluginInvocation checks that the right SetUpPod and TearDownPod
// calls are made when we run/stop a sandbox.
func TestNetworkPluginInvocation(t *testing.T) {
ds, _, _ := newTestDockerService()
mockPlugin := newTestNetworkPlugin(t)
ds.networkPlugin = mockPlugin
defer mockPlugin.Finish()
name := "foo0"
ns := "bar0"
c := makeSandboxConfigWithLabelsAndAnnotations(
name, ns, "0", 0,
map[string]string{"label": name},
map[string]string{"annotation": ns},
)
cID := kubecontainer.ContainerID{Type: runtimeName, ID: fmt.Sprintf("/%v", makeSandboxName(c))}
setup := mockPlugin.EXPECT().SetUpPod(ns, name, cID)
// StopPodSandbox performs a lookup on status to figure out if the sandbox
// is running with hostnetworking, as all its given is the ID.
mockPlugin.EXPECT().GetPodNetworkStatus(ns, name, cID)
mockPlugin.EXPECT().TearDownPod(ns, name, cID).After(setup)
_, err := ds.RunPodSandbox(c)
assert.NoError(t, err)
err = ds.StopPodSandbox(cID.ID)
assert.NoError(t, err)
}
// TestHostNetworkPluginInvocation checks that *no* SetUp/TearDown calls happen
// for host network sandboxes.
func TestHostNetworkPluginInvocation(t *testing.T) {
ds, _, _ := newTestDockerService()
mockPlugin := newTestNetworkPlugin(t)
ds.networkPlugin = mockPlugin
defer mockPlugin.Finish()
name := "foo0"
ns := "bar0"
c := makeSandboxConfigWithLabelsAndAnnotations(
name, ns, "0", 0,
map[string]string{"label": name},
map[string]string{"annotation": ns},
)
hostNetwork := true
c.Linux = &runtimeApi.LinuxPodSandboxConfig{NamespaceOptions: &runtimeApi.NamespaceOption{HostNetwork: &hostNetwork}}
cID := kubecontainer.ContainerID{Type: runtimeName, ID: fmt.Sprintf("/%v", makeSandboxName(c))}
// No calls to network plugin are expected
_, err := ds.RunPodSandbox(c)
assert.NoError(t, err)
assert.NoError(t, ds.StopPodSandbox(cID.ID))
}

View File

@ -17,15 +17,25 @@ limitations under the License.
package dockershim package dockershim
import ( import (
"github.com/golang/mock/gomock"
"testing"
"time" "time"
containertest "k8s.io/kubernetes/pkg/kubelet/container/testing" containertest "k8s.io/kubernetes/pkg/kubelet/container/testing"
"k8s.io/kubernetes/pkg/kubelet/dockertools" "k8s.io/kubernetes/pkg/kubelet/dockertools"
"k8s.io/kubernetes/pkg/kubelet/network"
"k8s.io/kubernetes/pkg/kubelet/network/mock_network"
"k8s.io/kubernetes/pkg/util/clock" "k8s.io/kubernetes/pkg/util/clock"
) )
// newTestNetworkPlugin returns a mock plugin that implements network.NetworkPlugin
func newTestNetworkPlugin(t *testing.T) *mock_network.MockNetworkPlugin {
ctrl := gomock.NewController(t)
return mock_network.NewMockNetworkPlugin(ctrl)
}
func newTestDockerService() (*dockerService, *dockertools.FakeDockerClient, *clock.FakeClock) { func newTestDockerService() (*dockerService, *dockertools.FakeDockerClient, *clock.FakeClock) {
fakeClock := clock.NewFakeClock(time.Time{}) fakeClock := clock.NewFakeClock(time.Time{})
c := dockertools.NewFakeDockerClientWithClock(fakeClock) c := dockertools.NewFakeDockerClientWithClock(fakeClock)
return &dockerService{client: c, os: &containertest.FakeOS{}}, c, fakeClock return &dockerService{client: c, os: &containertest.FakeOS{}, networkPlugin: &network.NoopNetworkPlugin{}}, c, fakeClock
} }

View File

@ -138,6 +138,14 @@ func (fnh *fakeNetworkHost) GetRuntime() kubecontainer.Runtime {
return fnh.runtime return fnh.runtime
} }
func (fnh *fakeNetworkHost) GetNetNS(containerID string) (string, error) {
return fnh.GetRuntime().GetNetNS(kubecontainer.ContainerID{Type: "test", ID: containerID})
}
func (fnh *fakeNetworkHost) SupportsLegacyFeatures() bool {
return true
}
func TestCNIPlugin(t *testing.T) { func TestCNIPlugin(t *testing.T) {
// install some random plugin // install some random plugin
pluginName := fmt.Sprintf("test%d", rand.Intn(1000)) pluginName := fmt.Sprintf("test%d", rand.Intn(1000))

View File

@ -229,4 +229,40 @@ func TestGenerateMacAddress(t *testing.T) {
} }
} }
// TestInvocationWithoutRuntime invokes the plugin without a runtime.
// This is how kubenet is invoked from the cri.
func TestTearDownWithoutRuntime(t *testing.T) {
fhost := nettest.NewFakeHost(nil)
fhost.Legacy = false
fhost.Runtime = nil
mockcni := &mock_cni.MockCNI{}
fexec := &exec.FakeExec{
CommandScript: []exec.FakeCommandAction{},
LookPathFunc: func(file string) (string, error) {
return fmt.Sprintf("/fake-bin/%s", file), nil
},
}
kubenet := newFakeKubenetPlugin(map[kubecontainer.ContainerID]string{}, fexec, fhost)
kubenet.cniConfig = mockcni
kubenet.iptables = ipttest.NewFake()
details := make(map[string]interface{})
details[network.NET_PLUGIN_EVENT_POD_CIDR_CHANGE_DETAIL_CIDR] = "10.0.0.1/24"
kubenet.Event(network.NET_PLUGIN_EVENT_POD_CIDR_CHANGE, details)
existingContainerID := kubecontainer.BuildContainerID("docker", "123")
kubenet.podIPs[existingContainerID] = "10.0.0.1"
mockcni.On("DelNetwork", mock.AnythingOfType("*libcni.NetworkConfig"), mock.AnythingOfType("*libcni.RuntimeConf")).Return(nil)
if err := kubenet.TearDownPod("namespace", "name", existingContainerID); err != nil {
t.Fatalf("Unexpected error in TearDownPod: %v", err)
}
// Assert that the CNI DelNetwork made it through and we didn't crash
// without a runtime.
mockcni.AssertExpectations(t)
}
//TODO: add unit test for each implementation of network plugin interface //TODO: add unit test for each implementation of network plugin interface

View File

@ -55,6 +55,10 @@ func (_m *MockNetworkPlugin) Capabilities() sets.Int {
return ret0 return ret0
} }
func (_m *MockNetworkPlugin) Finish() {
_m.ctrl.Finish()
}
func (_mr *_MockNetworkPluginRecorder) Capabilities() *gomock.Call { func (_mr *_MockNetworkPluginRecorder) Capabilities() *gomock.Call {
return _mr.mock.ctrl.RecordCall(_mr.mock, "Capabilities") return _mr.mock.ctrl.RecordCall(_mr.mock, "Capabilities")
} }

View File

@ -27,11 +27,14 @@ import (
) )
type fakeNetworkHost struct { type fakeNetworkHost struct {
fakeNamespaceGetter
kubeClient clientset.Interface kubeClient clientset.Interface
Legacy bool
Runtime *containertest.FakeRuntime
} }
func NewFakeHost(kubeClient clientset.Interface) *fakeNetworkHost { func NewFakeHost(kubeClient clientset.Interface) *fakeNetworkHost {
host := &fakeNetworkHost{kubeClient: kubeClient} host := &fakeNetworkHost{kubeClient: kubeClient, Legacy: true, Runtime: &containertest.FakeRuntime{}}
return host return host
} }
@ -44,5 +47,17 @@ func (fnh *fakeNetworkHost) GetKubeClient() clientset.Interface {
} }
func (nh *fakeNetworkHost) GetRuntime() kubecontainer.Runtime { func (nh *fakeNetworkHost) GetRuntime() kubecontainer.Runtime {
return &containertest.FakeRuntime{} return nh.Runtime
}
func (nh *fakeNetworkHost) SupportsLegacyFeatures() bool {
return nh.Legacy
}
type fakeNamespaceGetter struct {
ns string
}
func (nh *fakeNamespaceGetter) GetNetNS(containerID string) (string, error) {
return nh.ns, nil
} }

View File

@ -63,7 +63,7 @@ type criNetworkHost struct {
// Any network plugin invoked by a cri must implement NamespaceGetter // Any network plugin invoked by a cri must implement NamespaceGetter
// to talk directly to the runtime instead. // to talk directly to the runtime instead.
func (c *criNetworkHost) GetNetNS(containerID string) (string, error) { func (c *criNetworkHost) GetNetNS(containerID string) (string, error) {
return c.kubelet.GetRuntime().GetNetNS(kubecontainer.ContainerID{"", containerID}) return c.kubelet.GetRuntime().GetNetNS(kubecontainer.ContainerID{Type: "", ID: containerID})
} }
// noOpLegacyHost implements the network.LegacyHost interface for the remote // noOpLegacyHost implements the network.LegacyHost interface for the remote