diff --git a/hack/verify-lint.sh b/hack/verify-lint.sh index 56d80e884..12df1702b 100755 --- a/hack/verify-lint.sh +++ b/hack/verify-lint.sh @@ -23,6 +23,7 @@ for d in $(find . -type d -a \( -iwholename './pkg*' -o -iwholename './cmd*' \)) --exclude='error return value not checked.*(Close|Log|Print).*\(errcheck\)$' \ --exclude='.*_test\.go:.*error return value not checked.*\(errcheck\)$' \ --exclude='duplicate of.*_test.go.*\(dupl\)$' \ + --exclude='.*/mock_.*\.go:.*\(golint\)$' \ --disable=aligncheck \ --disable=gotype \ --disable=gas \ diff --git a/pkg/server/status_test.go b/pkg/server/status_test.go new file mode 100644 index 000000000..a3f625536 --- /dev/null +++ b/pkg/server/status_test.go @@ -0,0 +1,97 @@ +/* +Copyright 2017 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 server + +import ( + "errors" + "testing" + + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "golang.org/x/net/context" + healthapi "google.golang.org/grpc/health/grpc_health_v1" + runtime "k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1" + + servertesting "github.com/kubernetes-incubator/cri-containerd/pkg/server/testing" +) + +func TestStatus(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + for desc, test := range map[string]struct { + containerdCheckRes *healthapi.HealthCheckResponse + containerdCheckErr error + networkStatusErr error + + expectRuntimeNotReady bool + expectNetworkNotReady bool + }{ + "runtime should not be ready when containerd is not serving": { + containerdCheckRes: &healthapi.HealthCheckResponse{ + Status: healthapi.HealthCheckResponse_NOT_SERVING, + }, + expectRuntimeNotReady: true, + }, + "runtime should not be ready when containerd healthcheck returns error": { + containerdCheckErr: errors.New("healthcheck error"), + expectRuntimeNotReady: true, + }, + "network should not be ready when network plugin status returns error": { + containerdCheckRes: &healthapi.HealthCheckResponse{ + Status: healthapi.HealthCheckResponse_SERVING, + }, + networkStatusErr: errors.New("status error"), + expectNetworkNotReady: true, + }, + "runtime should be ready when containerd is serving": { + containerdCheckRes: &healthapi.HealthCheckResponse{ + Status: healthapi.HealthCheckResponse_SERVING, + }, + }, + } { + t.Logf("TestCase %q", desc) + c := newTestCRIContainerdService() + ctx := context.Background() + mock := servertesting.NewMockHealthClient(ctrl) + mock.EXPECT().Check(ctx, &healthapi.HealthCheckRequest{}).Return( + test.containerdCheckRes, test.containerdCheckErr) + c.healthService = mock + if test.networkStatusErr != nil { + c.netPlugin.(*servertesting.FakeCNIPlugin).InjectError( + "Status", test.networkStatusErr) + } + + resp, err := c.Status(ctx, &runtime.StatusRequest{}) + assert.NoError(t, err) + require.NotNil(t, resp) + runtimeCondition := resp.Status.Conditions[0] + networkCondition := resp.Status.Conditions[1] + assert.Equal(t, runtime.RuntimeReady, runtimeCondition.Type) + assert.Equal(t, test.expectRuntimeNotReady, !runtimeCondition.Status) + if test.expectRuntimeNotReady { + assert.Equal(t, runtimeNotReadyReason, runtimeCondition.Reason) + assert.NotEmpty(t, runtimeCondition.Message) + } + assert.Equal(t, runtime.NetworkReady, networkCondition.Type) + assert.Equal(t, test.expectNetworkNotReady, !networkCondition.Status) + if test.expectNetworkNotReady { + assert.Equal(t, networkNotReadyReason, networkCondition.Reason) + assert.NotEmpty(t, networkCondition.Message) + } + } +} diff --git a/pkg/server/testing/fake_cni_plugin.go b/pkg/server/testing/fake_cni_plugin.go index a41ba7339..09fc829d3 100644 --- a/pkg/server/testing/fake_cni_plugin.go +++ b/pkg/server/testing/fake_cni_plugin.go @@ -168,7 +168,10 @@ func (f *FakeCNIPlugin) GetContainerNetworkStatus(netnsPath string, namespace st // Status get the status of the plugin. func (f *FakeCNIPlugin) Status() error { - return nil + f.Lock() + defer f.Unlock() + f.appendCalled("Status", nil) + return f.getError("Status") } func generateIP() string { diff --git a/pkg/server/testing/mock_health_client.go b/pkg/server/testing/mock_health_client.go new file mode 100644 index 000000000..e5e4e8b32 --- /dev/null +++ b/pkg/server/testing/mock_health_client.go @@ -0,0 +1,64 @@ +/* +Copyright 2017 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. +*/ + +// Automatically generated by MockGen. DO NOT EDIT! +// Source: google.golang.org/grpc/health/grpc_health_v1 (interfaces: HealthClient) + +package testing + +import ( + gomock "github.com/golang/mock/gomock" + context "golang.org/x/net/context" + grpc "google.golang.org/grpc" + grpc_health_v1 "google.golang.org/grpc/health/grpc_health_v1" +) + +// Mock of HealthClient interface +type MockHealthClient struct { + ctrl *gomock.Controller + recorder *_MockHealthClientRecorder +} + +// Recorder for MockHealthClient (not exported) +type _MockHealthClientRecorder struct { + mock *MockHealthClient +} + +func NewMockHealthClient(ctrl *gomock.Controller) *MockHealthClient { + mock := &MockHealthClient{ctrl: ctrl} + mock.recorder = &_MockHealthClientRecorder{mock} + return mock +} + +func (_m *MockHealthClient) EXPECT() *_MockHealthClientRecorder { + return _m.recorder +} + +func (_m *MockHealthClient) Check(_param0 context.Context, _param1 *grpc_health_v1.HealthCheckRequest, _param2 ...grpc.CallOption) (*grpc_health_v1.HealthCheckResponse, error) { + _s := []interface{}{_param0, _param1} + for _, _x := range _param2 { + _s = append(_s, _x) + } + ret := _m.ctrl.Call(_m, "Check", _s...) + ret0, _ := ret[0].(*grpc_health_v1.HealthCheckResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +func (_mr *_MockHealthClientRecorder) Check(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { + _s := append([]interface{}{arg0, arg1}, arg2...) + return _mr.mock.ctrl.RecordCall(_mr.mock, "Check", _s...) +} diff --git a/pkg/server/testing/mock_version_client.go b/pkg/server/testing/mock_version_client.go new file mode 100644 index 000000000..b33723b9a --- /dev/null +++ b/pkg/server/testing/mock_version_client.go @@ -0,0 +1,65 @@ +/* +Copyright 2017 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. +*/ + +// Automatically generated by MockGen. DO NOT EDIT! +// Source: github.com/containerd/containerd/api/services/version (interfaces: VersionClient) + +package testing + +import ( + version "github.com/containerd/containerd/api/services/version" + gomock "github.com/golang/mock/gomock" + empty "github.com/golang/protobuf/ptypes/empty" + context "golang.org/x/net/context" + grpc "google.golang.org/grpc" +) + +// Mock of VersionClient interface +type MockVersionClient struct { + ctrl *gomock.Controller + recorder *_MockVersionClientRecorder +} + +// Recorder for MockVersionClient (not exported) +type _MockVersionClientRecorder struct { + mock *MockVersionClient +} + +func NewMockVersionClient(ctrl *gomock.Controller) *MockVersionClient { + mock := &MockVersionClient{ctrl: ctrl} + mock.recorder = &_MockVersionClientRecorder{mock} + return mock +} + +func (_m *MockVersionClient) EXPECT() *_MockVersionClientRecorder { + return _m.recorder +} + +func (_m *MockVersionClient) Version(_param0 context.Context, _param1 *empty.Empty, _param2 ...grpc.CallOption) (*version.VersionResponse, error) { + _s := []interface{}{_param0, _param1} + for _, _x := range _param2 { + _s = append(_s, _x) + } + ret := _m.ctrl.Call(_m, "Version", _s...) + ret0, _ := ret[0].(*version.VersionResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +func (_mr *_MockVersionClientRecorder) Version(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { + _s := append([]interface{}{arg0, arg1}, arg2...) + return _mr.mock.ctrl.RecordCall(_mr.mock, "Version", _s...) +} diff --git a/pkg/server/version_test.go b/pkg/server/version_test.go new file mode 100644 index 000000000..75866a508 --- /dev/null +++ b/pkg/server/version_test.go @@ -0,0 +1,61 @@ +/* +Copyright 2017 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 server + +import ( + "errors" + "testing" + + versionapi "github.com/containerd/containerd/api/services/version" + "github.com/golang/mock/gomock" + "github.com/golang/protobuf/ptypes/empty" + "github.com/stretchr/testify/assert" + "golang.org/x/net/context" + runtime "k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1" + + servertesting "github.com/kubernetes-incubator/cri-containerd/pkg/server/testing" +) + +func TestVersion(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + // TODO(random-liu): Check containerd version after containerd fixes its version. + for desc, test := range map[string]struct { + versionRes *versionapi.VersionResponse + versionErr error + expectErr bool + }{ + "should return error if containerd version returns error": { + versionErr: errors.New("random error"), + expectErr: true, + }, + "should not return error if containerd version returns successfully": { + versionRes: &versionapi.VersionResponse{Version: "1.1.1"}, + expectErr: false, + }, + } { + t.Logf("TestCase %q", desc) + c := newTestCRIContainerdService() + ctx := context.Background() + mock := servertesting.NewMockVersionClient(ctrl) + mock.EXPECT().Version(ctx, &empty.Empty{}).Return(test.versionRes, test.versionErr) + + c.versionService = mock + _, err := c.Version(ctx, &runtime.VersionRequest{}) + assert.Equal(t, test.expectErr, err != nil) + } +}