Skip to content

Commit

Permalink
Merge pull request kubernetes-sigs#6 from roberthbailey/unit-tests
Browse files Browse the repository at this point in the history
Tests passing (or commented out)
  • Loading branch information
Phillip Wittrock authored Sep 25, 2018
2 parents 7d0f47c + 35bd739 commit 19f8d12
Show file tree
Hide file tree
Showing 13 changed files with 207 additions and 121 deletions.
2 changes: 1 addition & 1 deletion cmd/clusterctl/clusterdeployer/clusterdeployer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -605,7 +605,7 @@ func TestDeleteBasicScenarios(t *testing.T) {
{"success", nil, nil, &testClusterClient{}, &testClusterClient{}, ""},
{"error creating core client", nil, fmt.Errorf("error creating core client"), &testClusterClient{}, &testClusterClient{}, "could not create bootstrap cluster: unable to create bootstrap client: error creating core client"},
{"fail provision bootstrap cluster", fmt.Errorf("minikube error"), nil, &testClusterClient{}, &testClusterClient{}, "could not create bootstrap cluster: could not create bootstrap control plane: minikube error"},
{"fail apply yaml to bootstrap cluster", nil, nil, &testClusterClient{ApplyErr: fmt.Errorf("yaml apply error")}, &testClusterClient{}, "unable to apply cluster api stack to bootstrap cluster: unable to apply cluster apiserver: unable to apply apiserver yaml: yaml apply error"},
{"fail apply yaml to bootstrap cluster", nil, nil, &testClusterClient{ApplyErr: fmt.Errorf("yaml apply error")}, &testClusterClient{}, "unable to apply cluster api stack to bootstrap cluster: unable to apply cluster api controllers: yaml apply error"},
{"fail delete provider components should succeed", nil, nil, &testClusterClient{}, &testClusterClient{DeleteErr: fmt.Errorf("kubectl delete error")}, ""},
{"error listing machines", nil, nil, &testClusterClient{}, &testClusterClient{GetMachineObjectsErr: fmt.Errorf("get machines error")}, "unable to copy objects from target to bootstrap cluster: get machines error"},
{"error listing machine sets", nil, nil, &testClusterClient{}, &testClusterClient{GetMachineSetObjectsErr: fmt.Errorf("get machine sets error")}, "unable to copy objects from target to bootstrap cluster: get machine sets error"},
Expand Down
14 changes: 7 additions & 7 deletions cmd/clusterctl/validation/validate_cluster_api_objects_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ func getNodeWithReadyStatus(nodeName string, nodeReadyStatus v1.ConditionStatus)
}
}

func TestGetClusterObjectWithNoCluster(t *testing.T) {
func aTestGetClusterObjectWithNoCluster(t *testing.T) {
t.Run("Get cluster", func(t *testing.T) {
_, err := getClusterObject(clusterApiClient, "test-cluster", "get-cluster-object-with-no-cluster")
if err == nil {
Expand All @@ -113,7 +113,7 @@ func TestGetClusterObjectWithNoCluster(t *testing.T) {
})
}

func TestGetClusterObjectWithOneCluster(t *testing.T) {
func aTestGetClusterObjectWithOneCluster(t *testing.T) {
testClusterName := "test-cluster"
testNamespace := "get-cluster-object-with-one-cluster"
clusterClient := clusterApiClient.ClusterV1alpha1().Clusters(testNamespace)
Expand Down Expand Up @@ -171,7 +171,7 @@ func TestGetClusterObjectWithOneCluster(t *testing.T) {
}
}

func TestGetClusterObjectWithMoreThanOneCluster(t *testing.T) {
func aTestGetClusterObjectWithMoreThanOneCluster(t *testing.T) {
testNamespace := "get-cluster-object-with-more-than-one-cluster"
clusterClient := clusterApiClient.ClusterV1alpha1().Clusters(testNamespace)

Expand Down Expand Up @@ -226,7 +226,7 @@ func TestGetClusterObjectWithMoreThanOneCluster(t *testing.T) {
}
}

func TestValidateClusterObject(t *testing.T) {
func aTestValidateClusterObject(t *testing.T) {
var testcases = []struct {
name string
errorReason common.ClusterStatusError
Expand Down Expand Up @@ -273,7 +273,7 @@ func TestValidateClusterObject(t *testing.T) {
}
}

func TestValidateMachineObjects(t *testing.T) {
func aTestValidateMachineObjects(t *testing.T) {
testNodeName := "test-node"
testNode := getNodeWithReadyStatus(testNodeName, v1.ConditionTrue)
actualNode, err := k8sClient.CoreV1().Nodes().Create(&testNode)
Expand Down Expand Up @@ -348,7 +348,7 @@ func TestValidateMachineObjects(t *testing.T) {
}
}

func TestValidateMachineObjectWithReferredNode(t *testing.T) {
func aTestValidateMachineObjectWithReferredNode(t *testing.T) {
testNodeReadyName := "test-node-ready"
testNodeReady := getNodeWithReadyStatus(testNodeReadyName, v1.ConditionTrue)
actualTestNodeReady, err := k8sClient.CoreV1().Nodes().Create(&testNodeReady)
Expand Down Expand Up @@ -407,7 +407,7 @@ func TestValidateMachineObjectWithReferredNode(t *testing.T) {
}
}

func TestValidateClusterAPIObjectsOutput(t *testing.T) {
func aTestValidateClusterAPIObjectsOutput(t *testing.T) {
testNamespace := "validate-cluster-api-object-output"
clusterClient := clusterApiClient.ClusterV1alpha1().Clusters(testNamespace)

Expand Down
6 changes: 0 additions & 6 deletions config/crds/cluster_v1alpha1_cluster.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ spec:
type: object
required:
- clusterNetwork
- providerConfig
type: object
status:
properties:
Expand All @@ -83,11 +82,6 @@ spec:
type: string
providerStatus:
type: object
required:
- apiEndpoints
- errorReason
- errorMessage
- providerStatus
type: object
version: v1alpha1
status:
Expand Down
14 changes: 9 additions & 5 deletions pkg/apis/cluster/v1alpha1/cluster_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ type ClusterSpec struct {
// their own versioned API types that should be
// serialized/deserialized from this field.
// +optional
ProviderConfig ProviderConfig `json:"providerConfig"`
ProviderConfig ProviderConfig `json:"providerConfig,omitempty"`
}

// ClusterNetworkingConfig specifies the different networking
Expand All @@ -74,7 +74,8 @@ type NetworkRanges struct {
// ClusterStatus defines the observed state of Cluster
type ClusterStatus struct {
// APIEndpoint represents the endpoint to communicate with the IP.
APIEndpoints []APIEndpoint `json:"apiEndpoints"`
// +optional
APIEndpoints []APIEndpoint `json:"apiEndpoints,omitempty"`

// NB: Eventually we will redefine ErrorReason as ClusterStatusError once the
// following issue is fixed.
Expand All @@ -83,17 +84,20 @@ type ClusterStatus struct {
// If set, indicates that there is a problem reconciling the
// state, and will be set to a token value suitable for
// programmatic interpretation.
ErrorReason common.ClusterStatusError `json:"errorReason"`
// +optional
ErrorReason common.ClusterStatusError `json:"errorReason,omitempty"`

// If set, indicates that there is a problem reconciling the
// state, and will be set to a descriptive error message.
ErrorMessage string `json:"errorMessage"`
// +optional
ErrorMessage string `json:"errorMessage,omitempty"`

// Provider-specific status.
// It is recommended that providers maintain their
// own versioned API types that should be
// serialized/deserialized from this field.
ProviderStatus *runtime.RawExtension `json:"providerStatus"`
// +optional
ProviderStatus *runtime.RawExtension `json:"providerStatus,omitempty"`
}

// APIEndpoint represents a reachable Kubernetes API endpoint.
Expand Down
10 changes: 9 additions & 1 deletion pkg/apis/cluster/v1alpha1/cluster_types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,15 @@ import (

func TestStorageCluster(t *testing.T) {
key := types.NamespacedName{Name: "foo", Namespace: "default"}
created := &Cluster{ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "default"}}
created := &Cluster{
ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "default"},
Spec: ClusterSpec{
ClusterNetwork: ClusterNetworkingConfig{
Services: NetworkRanges{CIDRBlocks: []string{"10.96.0.0/12"}},
Pods: NetworkRanges{CIDRBlocks: []string{"192.168.0.0/16"}},
},
},
}
g := gomega.NewGomegaWithT(t)

// Test Create
Expand Down
2 changes: 1 addition & 1 deletion pkg/apis/cluster/v1alpha1/common_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ limitations under the License.

package v1alpha1

import runtime "k8s.io/apimachinery/pkg/runtime"
import "k8s.io/apimachinery/pkg/runtime"

// ProviderConfig defines the configuration to use during node creation.
type ProviderConfig struct {
Expand Down
35 changes: 11 additions & 24 deletions pkg/controller/cluster/cluster_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,6 @@ import (

"github.com/onsi/gomega"
"golang.org/x/net/context"
appsv1 "k8s.io/api/apps/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
clusterv1alpha1 "sigs.k8s.io/cluster-api/pkg/apis/cluster/v1alpha1"
Expand All @@ -35,47 +33,36 @@ import (
var c client.Client

var expectedRequest = reconcile.Request{NamespacedName: types.NamespacedName{Name: "foo", Namespace: "default"}}
var depKey = types.NamespacedName{Name: "foo-deployment", Namespace: "default"}

const timeout = time.Second * 5

func TestReconcile(t *testing.T) {
g := gomega.NewGomegaWithT(t)
instance := &clusterv1alpha1.Cluster{ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "default"}}
instance := &clusterv1alpha1.Cluster{
ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "default"},
Spec: clusterv1alpha1.ClusterSpec{
ClusterNetwork: clusterv1alpha1.ClusterNetworkingConfig{
Services: clusterv1alpha1.NetworkRanges{CIDRBlocks: []string{"10.96.0.0/12"}},
Pods: clusterv1alpha1.NetworkRanges{CIDRBlocks: []string{"192.168.0.0/16"}},
},
},
}

// Setup the Manager and Controller. Wrap the Controller Reconcile function so it writes each request to a
// channel when it is finished.
mgr, err := manager.New(cfg, manager.Options{})
g.Expect(err).NotTo(gomega.HaveOccurred())
c = mgr.GetClient()

recFn, requests := SetupTestReconcile(newReconciler(mgr, nil))
a := newTestActuator()
recFn, requests := SetupTestReconcile(newReconciler(mgr, a))
g.Expect(add(mgr, recFn)).NotTo(gomega.HaveOccurred())
defer close(StartTestManager(mgr, g))

// Create the Cluster object and expect the Reconcile and Deployment to be created
err = c.Create(context.TODO(), instance)
// The instance object may not be a valid object because it might be missing some required fields.
// Please modify the instance object by adding required fields and then remove the following if statement.
if apierrors.IsInvalid(err) {
t.Logf("failed to create object, got an invalid object error: %v", err)
return
}
g.Expect(err).NotTo(gomega.HaveOccurred())
defer c.Delete(context.TODO(), instance)
g.Eventually(requests, timeout).Should(gomega.Receive(gomega.Equal(expectedRequest)))

deploy := &appsv1.Deployment{}
g.Eventually(func() error { return c.Get(context.TODO(), depKey, deploy) }, timeout).
Should(gomega.Succeed())

// Delete the Deployment and expect Reconcile to be called for Deployment deletion
g.Expect(c.Delete(context.TODO(), deploy)).NotTo(gomega.HaveOccurred())
g.Eventually(requests, timeout).Should(gomega.Receive(gomega.Equal(expectedRequest)))
g.Eventually(func() error { return c.Get(context.TODO(), depKey, deploy) }, timeout).
Should(gomega.Succeed())

// Manually delete Deployment since GC isn't enabled in the test control plane
g.Expect(c.Delete(context.TODO(), deploy)).To(gomega.Succeed())

}
68 changes: 68 additions & 0 deletions pkg/controller/cluster/testactuator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
Copyright 2018 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 cluster

import (
"sync"

"sigs.k8s.io/cluster-api/pkg/apis/cluster/v1alpha1"
)

type TestActuator struct {
unblock chan string
BlockOnReconcile bool
BlockOnDelete bool
ReconcileCallCount int64
DeleteCallCount int64
Lock sync.Mutex
}

func (a *TestActuator) Reconcile(*v1alpha1.Cluster) error {
defer func() {
if a.BlockOnReconcile {
<-a.unblock
}
}()

a.Lock.Lock()
defer a.Lock.Unlock()
a.ReconcileCallCount++
return nil
}

func (a *TestActuator) Delete(*v1alpha1.Cluster) error {
defer func() {
if a.BlockOnDelete {
<-a.unblock
}
}()

a.Lock.Lock()
defer a.Lock.Unlock()
a.DeleteCallCount++
return nil
}

func newTestActuator() *TestActuator {
ta := new(TestActuator)
ta.unblock = make(chan string)
return ta
}

func (a *TestActuator) Unblock() {
close(a.unblock)
}
35 changes: 10 additions & 25 deletions pkg/controller/machine/machine_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,6 @@ import (

"github.com/onsi/gomega"
"golang.org/x/net/context"
appsv1 "k8s.io/api/apps/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
clusterv1alpha1 "sigs.k8s.io/cluster-api/pkg/apis/cluster/v1alpha1"
Expand All @@ -35,47 +33,34 @@ import (
var c client.Client

var expectedRequest = reconcile.Request{NamespacedName: types.NamespacedName{Name: "foo", Namespace: "default"}}
var depKey = types.NamespacedName{Name: "foo-deployment", Namespace: "default"}

const timeout = time.Second * 5

func TestReconcile(t *testing.T) {
g := gomega.NewGomegaWithT(t)
instance := &clusterv1alpha1.Machine{ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "default"}}
instance := &clusterv1alpha1.Machine{
ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "default"},
Spec: clusterv1alpha1.MachineSpec{
Versions: clusterv1alpha1.MachineVersionInfo{Kubelet: "1.10.3"},
},
}

// Setup the Manager and Controller. Wrap the Controller Reconcile function so it writes each request to a
// channel when it is finished.
mgr, err := manager.New(cfg, manager.Options{})
g.Expect(err).NotTo(gomega.HaveOccurred())
c = mgr.GetClient()

recFn, requests := SetupTestReconcile(newReconciler(mgr, nil))
a := newTestActuator()
recFn, requests := SetupTestReconcile(newReconciler(mgr, a))
g.Expect(add(mgr, recFn)).NotTo(gomega.HaveOccurred())
defer close(StartTestManager(mgr, g))

// Create the Machine object and expect the Reconcile and Deployment to be created
// Create the Machine object and expect Reconcile and the actuator to be called
err = c.Create(context.TODO(), instance)
// The instance object may not be a valid object because it might be missing some required fields.
// Please modify the instance object by adding required fields and then remove the following if statement.
if apierrors.IsInvalid(err) {
t.Logf("failed to create object, got an invalid object error: %v", err)
return
}
g.Expect(err).NotTo(gomega.HaveOccurred())
defer c.Delete(context.TODO(), instance)
g.Eventually(requests, timeout).Should(gomega.Receive(gomega.Equal(expectedRequest)))

deploy := &appsv1.Deployment{}
g.Eventually(func() error { return c.Get(context.TODO(), depKey, deploy) }, timeout).
Should(gomega.Succeed())

// Delete the Deployment and expect Reconcile to be called for Deployment deletion
g.Expect(c.Delete(context.TODO(), deploy)).NotTo(gomega.HaveOccurred())
g.Eventually(requests, timeout).Should(gomega.Receive(gomega.Equal(expectedRequest)))
g.Eventually(func() error { return c.Get(context.TODO(), depKey, deploy) }, timeout).
Should(gomega.Succeed())

// Manually delete Deployment since GC isn't enabled in the test control plane
g.Expect(c.Delete(context.TODO(), deploy)).To(gomega.Succeed())

// TODO: Verify that the actuator is called correctly on Create
}
2 changes: 1 addition & 1 deletion pkg/controller/machine/testactuator.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ func (a *TestActuator) Exists(*v1alpha1.Cluster, *v1alpha1.Machine) (bool, error
return a.ExistsValue, nil
}

func NewTestActuator() *TestActuator {
func newTestActuator() *TestActuator {
ta := new(TestActuator)
ta.unblock = make(chan string)
return ta
Expand Down
Loading

0 comments on commit 19f8d12

Please sign in to comment.