Skip to content

Add code coverage #18

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jun 11, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 9 additions & 17 deletions pkg/controller/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,10 @@ import (
"github.com/kubernetes-sigs/controller-runtime/pkg/manager"
"github.com/kubernetes-sigs/controller-runtime/pkg/predicate"
"github.com/kubernetes-sigs/controller-runtime/pkg/reconcile"
logf "github.com/kubernetes-sigs/controller-runtime/pkg/runtime/log"
"github.com/kubernetes-sigs/controller-runtime/pkg/source"
"k8s.io/client-go/util/workqueue"
)

var log = logf.KBLog.WithName("controller")

// Options are the arguments for creating a new Controller
type Options struct {
// MaxConcurrentReconciles is the maximum number of concurrent Reconciles which can be run. Defaults to 1.
Expand All @@ -43,6 +40,9 @@ type Options struct {
// Controller is a work queue that watches for changes to objects (i.e. Create / Update / Delete events) and
// then reconciles an object (i.e. make changes to ensure the system state matches what is specified in the object).
type Controller interface {
// Reconcile is called to Reconcile an object by Namespace/Name
reconcile.Reconcile

// Watch takes events provided by a Source and uses the EventHandler to enqueue reconcile.Requests in
// response to the events.
//
Expand All @@ -68,27 +68,19 @@ func New(name string, mrg manager.Manager, options Options) (Controller, error)
options.MaxConcurrentReconciles = 1
}

if options.Reconcile == nil {
options.Reconcile = reconcile.Func(func(o reconcile.Request) (reconcile.Result, error) {
log.Error(nil, "Reconcile function not implemented", "Controller", name)
fmt.Printf("Received Reconcile request on Controller %s for %s/%s", name, o.Namespace, o.Name)
return reconcile.Result{}, nil
})
}

// Inject dependencies into Reconcile
if err := mrg.SetFields(options.Reconcile); err != nil {
return nil, err
}

// Create controller with dependencies set
c := &controller.Controller{
Reconcile: options.Reconcile,
Cache: mrg.GetCache(),
Config: mrg.GetConfig(),
Scheme: mrg.GetScheme(),
Client: mrg.GetClient(),
Queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), name),
Do: options.Reconcile,
Cache: mrg.GetCache(),
Config: mrg.GetConfig(),
Scheme: mrg.GetScheme(),
Client: mrg.GetClient(),
Queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), name),
MaxConcurrentReconciles: options.MaxConcurrentReconciles,
Name: name,
}
Expand Down
40 changes: 1 addition & 39 deletions pkg/controller/controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,16 @@ package controller_test
import (
"fmt"

"github.com/kubernetes-sigs/controller-runtime/pkg/cache"
"github.com/kubernetes-sigs/controller-runtime/pkg/client"
"github.com/kubernetes-sigs/controller-runtime/pkg/controller"
"github.com/kubernetes-sigs/controller-runtime/pkg/manager"
"github.com/kubernetes-sigs/controller-runtime/pkg/reconcile"
"github.com/kubernetes-sigs/controller-runtime/pkg/runtime/inject"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/rest"
)

var _ = Describe("controller", func() {
var _ = Describe("controller.Controller", func() {
var stop chan struct{}

rec := reconcile.Func(func(reconcile.Request) (reconcile.Result, error) {
Expand Down Expand Up @@ -93,38 +90,3 @@ func (*failRec) Reconcile(reconcile.Request) (reconcile.Result, error) {
func (*failRec) InjectClient(client.Client) error {
return fmt.Errorf("expected error")
}

type injectable struct {
scheme func(scheme *runtime.Scheme) error
client func(client.Client) error
config func(config *rest.Config) error
cache func(cache.Cache) error
}

func (i *injectable) InjectCache(c cache.Cache) error {
if i.cache == nil {
return nil
}
return i.cache(c)
}

func (i *injectable) InjectConfig(config *rest.Config) error {
if i.config == nil {
return nil
}
return i.config(config)
}

func (i *injectable) InjectClient(c client.Client) error {
if i.client == nil {
return nil
}
return i.client(c)
}

func (i *injectable) InjectScheme(scheme *runtime.Scheme) error {
if i.scheme == nil {
return nil
}
return i.scheme(scheme)
}
9 changes: 7 additions & 2 deletions pkg/internal/controller/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ type Controller struct {
// Reconcile is a function that can be called at any time with the Name / Namespace of an object and
// ensures that the state of the system matches the state specified in the object.
// Defaults to the DefaultReconcileFunc.
Reconcile reconcile.Reconcile
Do reconcile.Reconcile

// Client is a lazily initialized Client. The controllerManager will initialize this when Start is called.
Client client.Client
Expand Down Expand Up @@ -90,6 +90,11 @@ type Controller struct {
// TODO(community): Consider initializing a logger with the Controller Name as the tag
}

// Reconcile implements reconcile.Reconcile
func (c *Controller) Reconcile(r reconcile.Request) (reconcile.Result, error) {
return c.Do.Reconcile(r)
}

// Watch implements controller.Controller
func (c *Controller) Watch(src source.Source, evthdler handler.EventHandler, prct ...predicate.Predicate) error {
c.mu.Lock()
Expand Down Expand Up @@ -203,7 +208,7 @@ func (c *Controller) processNextWorkItem() bool {

// RunInformersAndControllers the syncHandler, passing it the namespace/Name string of the
// resource to be synced.
if result, err := c.Reconcile.Reconcile(req); err != nil {
if result, err := c.Do.Reconcile(req); err != nil {
c.Queue.AddRateLimited(req)
log.Error(nil, "Reconcile error", "Controller", c.Name, "Request", req)

Expand Down
24 changes: 18 additions & 6 deletions pkg/internal/controller/controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,9 @@ var _ = Describe("controller", func() {
informers = &informertest.FakeInformers{}
ctrl = &Controller{
MaxConcurrentReconciles: 1,
Reconcile: fakeReconcile,
Queue: queue,
Cache: informers,
Do: fakeReconcile,
Queue: queue,
Cache: informers,
}
ctrl.InjectFunc(func(interface{}) error { return nil })
})
Expand All @@ -72,7 +72,19 @@ var _ = Describe("controller", func() {
close(stop)
})

Describe("Starting a Controller", func() {
Describe("Reconcile", func() {
It("should call the Reconcile function", func() {
ctrl.Do = reconcile.Func(func(reconcile.Request) (reconcile.Result, error) {
return reconcile.Result{Requeue: true}, nil
})
result, err := ctrl.Reconcile(
reconcile.Request{NamespacedName: types.NamespacedName{Namespace: "foo", Name: "bar"}})
Expect(err).NotTo(HaveOccurred())
Expect(result).To(Equal(reconcile.Result{Requeue: true}))
})
})

Describe("Start", func() {
It("should return an error if there is an error waiting for the informers", func(done Done) {
ctrl.WaitForCache = func(<-chan struct{}, ...toolscache.InformerSynced) bool { return false }
ctrl.Name = "foo"
Expand Down Expand Up @@ -105,7 +117,7 @@ var _ = Describe("controller", func() {
})
})

Describe("Calling Watch on a Controller", func() {
Describe("Watch", func() {
It("should inject dependencies into the Source", func() {
src := &source.Kind{Type: &corev1.Pod{}}
src.InjectCache(ctrl.Cache)
Expand Down Expand Up @@ -270,7 +282,7 @@ var _ = Describe("controller", func() {
})

It("should continue to process additional queue items after the first", func(done Done) {
ctrl.Reconcile = reconcile.Func(func(reconcile.Request) (reconcile.Result, error) {
ctrl.Do = reconcile.Func(func(reconcile.Request) (reconcile.Result, error) {
defer GinkgoRecover()
Fail("Reconcile should not have been called")
return reconcile.Result{}, nil
Expand Down
8 changes: 8 additions & 0 deletions pkg/manager/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,14 @@ type Runnable interface {
Start(<-chan struct{}) error
}

// RunnableFunc implements Runnable
type RunnableFunc func(<-chan struct{}) error

// Start implements Runnable
func (r RunnableFunc) Start(s <-chan struct{}) error {
return r(s)
}

// New returns a new Manager
func New(config *rest.Config, options Options) (Manager, error) {
cm := &controllerManager{config: config, scheme: options.Scheme, errChan: make(chan error)}
Expand Down
Loading