Skip to content

Commit

Permalink
Add bcommand for creation of a plain trigger
Browse files Browse the repository at this point in the history
  • Loading branch information
Daisy Guo committed Dec 11, 2019
1 parent 2c1e5dc commit 88367ed
Show file tree
Hide file tree
Showing 45 changed files with 8,316 additions and 237 deletions.
60 changes: 60 additions & 0 deletions pkg/eventing/v1alpha1/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Copyright © 2019 The Knative 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 v1alpha1

import (
kn_errors "knative.dev/client/pkg/errors"
"knative.dev/eventing/pkg/apis/eventing/v1alpha1"
client_v1alpha1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/eventing/v1alpha1"
)

// KnEventingClient to Eventing Sources. All methods are relative to the
// namespace specified during construction
type KnEventingClient interface {
// Namespace in which this client is operating for
Namespace() string

CreateTrigger(trigger *v1alpha1.Trigger) (*v1alpha1.Trigger, error)
}

// KnEventingClient is a combination of Sources client interface and namespace
// Temporarily help to add sources dependencies
// May be changed when adding real sources features
type knEventingClient struct {
client client_v1alpha1.EventingV1alpha1Interface
namespace string
}

// NewKnEventingClient is to invoke Eventing Sources Client API to create object
func NewKnEventingClient(client client_v1alpha1.EventingV1alpha1Interface, namespace string) KnEventingClient {
return &knEventingClient{
namespace: namespace,
client: client,
}
}

//CreateTrigger is used to create an instance of Trigger
func (c *knEventingClient) CreateTrigger(trigger *v1alpha1.Trigger) (*v1alpha1.Trigger, error) {
ins, err := c.client.Triggers(c.namespace).Create(trigger)
if err != nil {
return nil, kn_errors.GetError(err)
}
return ins, nil
}

// Return the client's namespace
func (c *knEventingClient) Namespace() string {
return c.namespace
}
21 changes: 21 additions & 0 deletions pkg/kn/commands/testing_helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ import (
dynamic_fake "k8s.io/client-go/dynamic/fake"
dynamic_kn "knative.dev/client/pkg/dynamic"
sources_client "knative.dev/client/pkg/eventing/sources/v1alpha1"
eventing_client "knative.dev/client/pkg/eventing/v1alpha1"
eventing_fake "knative.dev/eventing/pkg/client/clientset/versioned/typed/eventing/v1alpha1/fake"
sources_fake "knative.dev/eventing/pkg/client/clientset/versioned/typed/sources/v1alpha1/fake"
)

Expand Down Expand Up @@ -78,6 +80,25 @@ func CreateSourcesTestKnCommand(cmd *cobra.Command, knParams *KnParams) (*cobra.
return knCommand, fakeEventing, buf
}

// CreateEventingTestKnCommand helper for creating test commands
func CreateEventingTestKnCommand(cmd *cobra.Command, knParams *KnParams) (*cobra.Command, *eventing_fake.FakeEventingV1alpha1, *bytes.Buffer) {
buf := new(bytes.Buffer)
// create fake serving client because the sink of source depends on serving client
fakeServing := &fake.FakeServingV1alpha1{&client_testing.Fake{}}
knParams.NewServingClient = func(namespace string) (v1alpha1.KnServingClient, error) {
return v1alpha1.NewKnServingClient(fakeServing, FakeNamespace), nil
}
// create fake sources client
fakeEventing := &eventing_fake.FakeEventingV1alpha1{&client_testing.Fake{}}
knParams.Output = buf
knParams.NewEventingClient = func(namespace string) (eventing_client.KnEventingClient, error) {
return eventing_client.NewKnEventingClient(fakeEventing, FakeNamespace), nil
}
knParams.fixedCurrentNamespace = FakeNamespace
knCommand := NewKnTestCommand(cmd, knParams)
return knCommand, fakeEventing, buf
}

// CreateDynamicTestKnCommand helper for creating test commands using dynamic client
func CreateDynamicTestKnCommand(cmd *cobra.Command, knParams *KnParams, objects ...runtime.Object) (*cobra.Command, *dynamic_fake.FakeDynamicClient, *bytes.Buffer) {
buf := new(bytes.Buffer)
Expand Down
120 changes: 120 additions & 0 deletions pkg/kn/commands/trigger/create.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
// Copyright © 2019 The Knative 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 trigger

import (
"errors"
"fmt"

"github.com/spf13/cobra"

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"knative.dev/client/pkg/kn/commands"
"knative.dev/client/pkg/kn/commands/flags"
"knative.dev/eventing/pkg/apis/eventing/v1alpha1"
duckv1 "knative.dev/pkg/apis/duck/v1"
)

func NewTriggerCreateCommand(p *commands.KnParams) *cobra.Command {
var triggerUpdateFlags TriggerUpdateFlags
var sinkFlags flags.SinkFlags

cmd := &cobra.Command{
Use: "create NAME --broker BROKER --filter KEY=VALUE --sink SINK",
Short: "Create a Trigger",
Example: `
# Create a Trigger 'mytrigger' which subscribes to events with attribute 'type=dev.knative.foo' from default broker and send events to service 'mysvc'
kn trigger create mytrigger --broker default --filter type=dev.knative.foo --sink svc:mysvc`,

RunE: func(cmd *cobra.Command, args []string) (err error) {
if len(args) != 1 {
return errors.New("'trigger create' requires the name of the trigger as single argument")
}
name := args[0]

// get namespace
namespace, err := p.GetNamespace(cmd)
if err != nil {
return err
}

// get client
eventingClient, err := p.NewEventingClient(namespace)
if err != nil {
return err
}

// resolve sink
servingClient, err := p.NewServingClient(namespace)
if err != nil {
return err
}

objectRef, err := sinkFlags.ResolveSink(servingClient)
if err != nil {
return fmt.Errorf(
"cannot create Trigger '%s' in namespace '%s' "+
"because %s", name, namespace, err)
}

// construct Trigger
trigger := constructTrigger(name, namespace, triggerUpdateFlags)
trigger.Spec.Subscriber = &duckv1.Destination{
Ref: objectRef.Ref,
URI: objectRef.URI,
}

// create
_, err = eventingClient.CreateTrigger(trigger)
if err != nil {
return fmt.Errorf(
"cannot create Trigger '%s' in namespace '%s' "+
"because %s", name, namespace, err)
}
fmt.Fprintf(cmd.OutOrStdout(), "Trigger '%s' successfully created in namespace '%s'.\n", args[0], namespace)
return nil
},
}
commands.AddNamespaceFlags(cmd.Flags(), false)
triggerUpdateFlags.Add(cmd)
sinkFlags.Add(cmd)
cmd.MarkFlagRequired("schedule")

return cmd
}

// constructTrigger is to create an instance of v1alpha1.Trigger
func constructTrigger(name string, namespace string, flags TriggerUpdateFlags) *v1alpha1.Trigger {

trigger := v1alpha1.Trigger{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: namespace,
},
Spec: v1alpha1.TriggerSpec{
Broker: flags.Broker,
},
}

filters := flags.GetFilter()
if filters != nil {
triggerFilterAttributes := v1alpha1.TriggerFilterAttributes(filters)
trigger.Spec.Filter = &v1alpha1.TriggerFilter{
Attributes: &triggerFilterAttributes,
}
}

return &trigger
}
178 changes: 178 additions & 0 deletions pkg/kn/commands/trigger/create_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
// Copyright © 2019 The Knative 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 trigger

import (
"errors"
"fmt"
"testing"

"gotest.tools/assert"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
client_testing "k8s.io/client-go/testing"
"knative.dev/client/pkg/kn/commands"
"knative.dev/client/pkg/util"
"knative.dev/eventing/pkg/apis/eventing/v1alpha1"
duckv1 "knative.dev/pkg/apis/duck/v1"
)

var (
triggerName = "foo"
)

func fakeTriggerCreate(args []string) (
action client_testing.Action,
tr *v1alpha1.Trigger,
output string,
err error) {
knParams := &commands.KnParams{}
cmd, fakeClient, buf := commands.CreateEventingTestKnCommand(NewTriggerCommand(knParams), knParams)
fakeClient.AddReactor("create", "triggers",
func(a client_testing.Action) (bool, runtime.Object, error) {
createAction, ok := a.(client_testing.CreateAction)
action = createAction
if !ok {
return true, nil, fmt.Errorf("wrong kind of action %v", a)
}
tr, ok = createAction.GetObject().(*v1alpha1.Trigger)
if !ok {
return true, nil, errors.New("was passed the wrong object")
}
return true, tr, nil
})
cmd.SetArgs(args)
err = cmd.Execute()
if err != nil {
output = err.Error()
return
}
output = buf.String()
return
}

func TestTriggerCreate(t *testing.T) {
action, created, output, err := fakeTriggerCreate([]string{
"trigger", "create", triggerName, "--broker", "mybroker",
"--filter", "type=dev.knative.foo", "--sink", "svc:mysvc"})
if err != nil {
t.Fatal(err)
} else if !action.Matches("create", "triggers") {
t.Fatalf("Bad action %v", action)
}

//construct a wanted instance
wanted := &v1alpha1.Trigger{
ObjectMeta: metav1.ObjectMeta{
Name: triggerName,
Namespace: commands.FakeNamespace,
},
Spec: v1alpha1.TriggerSpec{
Broker: "mybroker",
Filter: &v1alpha1.TriggerFilter{
Attributes: &v1alpha1.TriggerFilterAttributes{
"type": "dev.knative.foo",
},
},
Subscriber: &duckv1.Destination{
Ref: &corev1.ObjectReference{
Kind: "Service",
APIVersion: "serving.knative.dev/v1alpha1",
},
},
},
}

//assert equal
assert.DeepEqual(t, wanted, created)
assert.Check(t, util.ContainsAll(output, "Trigger", triggerName, "created", "namespace", commands.FakeNamespace))
}

func TestTriggerCreateWithoutBroker(t *testing.T) {
action, created, output, err := fakeTriggerCreate([]string{
"trigger", "create", triggerName,
"--filter", "type=dev.knative.foo", "--sink", "svc:mysvc"})
if err != nil {
t.Fatal(err)
} else if !action.Matches("create", "triggers") {
t.Fatalf("Bad action %v", action)
}

//construct a wanted instance
wanted := &v1alpha1.Trigger{
ObjectMeta: metav1.ObjectMeta{
Name: triggerName,
Namespace: commands.FakeNamespace,
},
Spec: v1alpha1.TriggerSpec{
Broker: "default",
Filter: &v1alpha1.TriggerFilter{
Attributes: &v1alpha1.TriggerFilterAttributes{
"type": "dev.knative.foo",
},
},
Subscriber: &duckv1.Destination{
Ref: &corev1.ObjectReference{
Kind: "Service",
APIVersion: "serving.knative.dev/v1alpha1",
},
},
},
}

//assert equal
assert.DeepEqual(t, wanted, created)
assert.Check(t, util.ContainsAll(output, "Trigger", triggerName, "created", "namespace", commands.FakeNamespace))
}

func TestTriggerCreateMultipleFilter(t *testing.T) {
action, created, output, err := fakeTriggerCreate([]string{
"trigger", "create", triggerName,
"--filter", "type=dev.knative.foo", "--filter", "source=event.host",
"--sink", "svc:mysvc"})
if err != nil {
t.Fatal(err)
} else if !action.Matches("create", "triggers") {
t.Fatalf("Bad action %v", action)
}

//construct a wanted instance
wanted := &v1alpha1.Trigger{
ObjectMeta: metav1.ObjectMeta{
Name: triggerName,
Namespace: commands.FakeNamespace,
},
Spec: v1alpha1.TriggerSpec{
Broker: "default",
Filter: &v1alpha1.TriggerFilter{
Attributes: &v1alpha1.TriggerFilterAttributes{
"type": "dev.knative.foo",
"source": "event.host",
},
},
Subscriber: &duckv1.Destination{
Ref: &corev1.ObjectReference{
Kind: "Service",
APIVersion: "serving.knative.dev/v1alpha1",
},
},
},
}

//assert equal
assert.DeepEqual(t, wanted, created)
assert.Check(t, util.ContainsAll(output, "Trigger", triggerName, "created", "namespace", commands.FakeNamespace))
}
Loading

0 comments on commit 88367ed

Please sign in to comment.