Repository: knative/client
Pull request #894 (2020-06-19 09:16:32)

Add broker create, delete and list cmds
## Description

Since the Eventing `0.15` multitenant broker is the new default. MT Broker is easier to manage from user's namespace because there're no more requirements for additional permission as majority of broker deployment is installed in `knative-eventing` namespace. This PR adds commands to manage broker CR. 

## Changes

<!-- Please add list of more detailed changes. These changes should be reflected also in the commit messages -->

* Add `broker create`, `broker delete`, `broker list` commands


Note 1: E2E are missing right now, I'm currently working on them.

Note 2: I haven't added `update` operation since the current impl only creates Broker CR with a name without additional specs.

## Reference

<!-- Please add the corresponding issue number which this pull request is about to fix -->
Fixes #

<!--
Please add an entrty to CHANGELOG.adoc file, too, as part of your Pull Request.

In the following cases, add a short description of PR to the unreleased section in CHANGELOG.adoc:

- 🎁 New feature
- 🐛 Bug fix
- ✨ Feature Update
- 🐣 Refactoring
- 🗑️ Remove feature or internal logic

See other entries in CHANGELOG.adoc as an example for how to add the entry, including a reference to the corresponding issue/PR

PLEASE DON'T ADD THAT LINE HERE IN THE PULL-REQUEST DESCRIPTION BUT DIRECTLY IN CHANGELOG.ADOC AND ADD CHANGELOG.ADOC AS PART OF YOUR PULL-REQUEST.
-->

<!--
To automatically lint go code in this pull request uncomment the line below. You get feedback as comments on your pull request then -->

<!--
/lint
-->


knative-prow-robot: [APPROVALNOTIFIER] This PR is **NOT APPROVED**

This pull-request has been approved by: *<a href="https://github.com/knative/client/pull/894#" title="Author self-approved">dsimansk</a>*
To complete the [pull request process](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process), please assign **cppforlife**
You can assign the PR to them by writing `/assign @cppforlife` in a comment when ready.

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=knative%2Fclient).

<details open>
Needs approval from an approver in each of these files:

- **[OWNERS](https://github.com/knative/client/blob/master/OWNERS)**

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":["cppforlife"]} -->
knative-metrics-robot: The following is the coverage report on the affected files.
Say `/test pull-knative-client-go-coverage` to re-run this coverage report

File | Old Coverage | New Coverage | Delta
---- |:------------:|:------------:|:-----:
[pkg/eventing/v1beta1/client.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_client/894/pull-knative-client-go-coverage/1273907643445940227/artifacts/line-cov.html#file0) | 83.1% | 83.7% | 0.7
[pkg/eventing/v1beta1/client_mock.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_client/894/pull-knative-client-go-coverage/1273907643445940227/artifacts/line-cov.html#file1) | 90.9% | 93.5% | 2.6
[pkg/kn/commands/broker/broker.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_client/894/pull-knative-client-go-coverage/1273907643445940227/artifacts/line-cov.html#file2) | Do not exist | 100.0% | 
[pkg/kn/commands/broker/create.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_client/894/pull-knative-client-go-coverage/1273907643445940227/artifacts/line-cov.html#file3) | Do not exist | 83.3% | 
[pkg/kn/commands/broker/delete.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_client/894/pull-knative-client-go-coverage/1273907643445940227/artifacts/line-cov.html#file4) | Do not exist | 82.4% | 
[pkg/kn/commands/broker/list.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_client/894/pull-knative-client-go-coverage/1273907643445940227/artifacts/line-cov.html#file5) | Do not exist | 88.6% | 

knative-prow-robot: @dsimansk: The following test **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-knative-client-build-tests | 22e92745837e5fd41fb23a7c69fcf26679b1ad2a | [link](https://prow.knative.dev/view/gcs/knative-prow/pr-logs/pull/knative_client/894/pull-knative-client-build-tests/1273907643445940226) | `/test pull-knative-client-build-tests`

[Full PR test history](https://gubernator.knative.dev/pr/knative_client/894). [Your PR dashboard](https://gubernator.knative.dev/pr/dsimansk).

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
knative-metrics-robot: The following is the coverage report on the affected files.
Say `/test pull-knative-client-go-coverage` to re-run this coverage report

File | Old Coverage | New Coverage | Delta
---- |:------------:|:------------:|:-----:
[pkg/eventing/v1beta1/client.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_client/894/pull-knative-client-go-coverage/1273910033985310721/artifacts/line-cov.html#file0) | 83.1% | 83.7% | 0.7
[pkg/eventing/v1beta1/client_mock.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_client/894/pull-knative-client-go-coverage/1273910033985310721/artifacts/line-cov.html#file1) | 90.9% | 93.5% | 2.6
[pkg/kn/commands/broker/broker.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_client/894/pull-knative-client-go-coverage/1273910033985310721/artifacts/line-cov.html#file2) | Do not exist | 100.0% | 
[pkg/kn/commands/broker/create.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_client/894/pull-knative-client-go-coverage/1273910033985310721/artifacts/line-cov.html#file3) | Do not exist | 83.3% | 
[pkg/kn/commands/broker/delete.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_client/894/pull-knative-client-go-coverage/1273910033985310721/artifacts/line-cov.html#file4) | Do not exist | 82.4% | 
[pkg/kn/commands/broker/list.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_client/894/pull-knative-client-go-coverage/1273910033985310721/artifacts/line-cov.html#file5) | Do not exist | 88.6% | 

knative-metrics-robot: The following is the coverage report on the affected files.
Say `/test pull-knative-client-go-coverage` to re-run this coverage report

File | Old Coverage | New Coverage | Delta
---- |:------------:|:------------:|:-----:
[pkg/eventing/v1beta1/client.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_client/894/pull-knative-client-go-coverage/1273912549850484736/artifacts/line-cov.html#file0) | 83.1% | 83.7% | 0.7
[pkg/eventing/v1beta1/client_mock.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_client/894/pull-knative-client-go-coverage/1273912549850484736/artifacts/line-cov.html#file1) | 90.9% | 93.5% | 2.6
[pkg/kn/commands/broker/broker.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_client/894/pull-knative-client-go-coverage/1273912549850484736/artifacts/line-cov.html#file2) | Do not exist | 100.0% | 
[pkg/kn/commands/broker/create.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_client/894/pull-knative-client-go-coverage/1273912549850484736/artifacts/line-cov.html#file3) | Do not exist | 83.3% | 
[pkg/kn/commands/broker/delete.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_client/894/pull-knative-client-go-coverage/1273912549850484736/artifacts/line-cov.html#file4) | Do not exist | 82.4% | 
[pkg/kn/commands/broker/list.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_client/894/pull-knative-client-go-coverage/1273912549850484736/artifacts/line-cov.html#file5) | Do not exist | 88.6% | 

knative-prow-robot: @dsimansk: The following test **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-knative-client-build-tests | db5a42a4be4e0b3a403ace68ffd07386214234d0 | [link](https://prow.knative.dev/view/gcs/knative-prow/pr-logs/pull/knative_client/894/pull-knative-client-build-tests/1273920225380667396) | `/test pull-knative-client-build-tests`

[Full PR test history](https://gubernator.knative.dev/pr/knative_client/894). [Your PR dashboard](https://gubernator.knative.dev/pr/dsimansk).

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
knative-metrics-robot: The following is the coverage report on the affected files.
Say `/test pull-knative-client-go-coverage` to re-run this coverage report

File | Old Coverage | New Coverage | Delta
---- |:------------:|:------------:|:-----:
[pkg/eventing/v1beta1/client.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_client/894/pull-knative-client-go-coverage/1273920225380667395/artifacts/line-cov.html#file0) | 83.1% | 83.7% | 0.7
[pkg/eventing/v1beta1/client_mock.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_client/894/pull-knative-client-go-coverage/1273920225380667395/artifacts/line-cov.html#file1) | 90.9% | 93.5% | 2.6
[pkg/kn/commands/broker/broker.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_client/894/pull-knative-client-go-coverage/1273920225380667395/artifacts/line-cov.html#file2) | Do not exist | 100.0% | 
[pkg/kn/commands/broker/create.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_client/894/pull-knative-client-go-coverage/1273920225380667395/artifacts/line-cov.html#file3) | Do not exist | 83.3% | 
[pkg/kn/commands/broker/delete.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_client/894/pull-knative-client-go-coverage/1273920225380667395/artifacts/line-cov.html#file4) | Do not exist | 82.4% | 
[pkg/kn/commands/broker/list.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_client/894/pull-knative-client-go-coverage/1273920225380667395/artifacts/line-cov.html#file5) | Do not exist | 88.6% | 


Patch:
diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc
index d893f27f..649c2c16 100644
--- a/CHANGELOG.adoc
+++ b/CHANGELOG.adoc
@@ -12,19 +12,40 @@
 | https://github.com/knative/client/pull/[#]
 ////
 
+## Unreleased
+
 [cols="1,10,3", options="header", width="100%"]
 |===
 | | Description | PR
 
 | 🐛
-| Return error message from using `--untag` with nonexistent tag
-| https://github.com/knative/client/pull/880[#880]
+| Fix Panic for `kn trigger describe` with Sink URI
+| https://github.com/knative/client/pull/900[#900]
 
 | 🎁
 | Group commands in usage output with `kn --help`
 | https://github.com/knative/client/pull/887[#887]
 |===
 
+## v0.15.2 (2020-06-16)
+
+[cols="1,10,3", options="header", width="100%"]
+|===
+| | Description | PR
+
+| 🐛
+| Fix build.sh for macOS users
+| https://github.com/knative/client/pull/883[#883]
+
+| 🐛
+| Return error message when using --untag with nonexistent tag
+| https://github.com/knative/client/pull/880[#880]
+
+| ✨
+| Update go.mod to specify the module is go1.14
+| https://github.com/knative/client/pull/866[#866]
+|===
+
 ## v0.15.1 (2020-06-03)
 
 [cols="1,10,3", options="header", width="100%"]
diff --git a/docs/cmd/kn.md b/docs/cmd/kn.md
index 60ec6e8c..27698194 100644
--- a/docs/cmd/kn.md
+++ b/docs/cmd/kn.md
@@ -19,6 +19,7 @@ kn is the command line interface for managing Knative Serving and Eventing resou
 
 ### SEE ALSO
 
+* [kn broker](kn_broker.md)	 - Manage message broker
 * [kn completion](kn_completion.md)	 - Output shell completion code
 * [kn options](kn_options.md)	 - Print the list of flags inherited by all commands
 * [kn plugin](kn_plugin.md)	 - Manage kn plugins
diff --git a/docs/cmd/kn_broker.md b/docs/cmd/kn_broker.md
new file mode 100644
index 00000000..104788db
--- /dev/null
+++ b/docs/cmd/kn_broker.md
@@ -0,0 +1,34 @@
+## kn broker
+
+Manage message broker
+
+### Synopsis
+
+Manage message broker
+
+```
+kn broker
+```
+
+### Options
+
+```
+  -h, --help   help for broker
+```
+
+### Options inherited from parent commands
+
+```
+      --config string       kn configuration file (default: ~/.config/kn/config.yaml)
+      --kubeconfig string   kubectl configuration file (default: ~/.kube/config)
+      --log-http            log http traffic
+```
+
+### SEE ALSO
+
+* [kn](kn.md)	 - kn manages Knative Serving and Eventing resources
+* [kn broker create](kn_broker_create.md)	 - Create a broker
+* [kn broker delete](kn_broker_delete.md)	 - Delete a broker
+* [kn broker describe](kn_broker_describe.md)	 - Describe broker
+* [kn broker list](kn_broker_list.md)	 - List brokers
+
diff --git a/docs/cmd/kn_broker_create.md b/docs/cmd/kn_broker_create.md
new file mode 100644
index 00000000..fdee69d1
--- /dev/null
+++ b/docs/cmd/kn_broker_create.md
@@ -0,0 +1,42 @@
+## kn broker create
+
+Create a broker
+
+### Synopsis
+
+Create a broker
+
+```
+kn broker create NAME
+```
+
+### Examples
+
+```
+
+  # Create a broker 'mybroker' in the current namespace
+  kn broker create mybroker
+
+  # Create a broker 'mybroker' in the 'myproject' namespace
+  kn broker create mybroker --namespace myproject
+```
+
+### Options
+
+```
+  -h, --help               help for create
+  -n, --namespace string   Specify the namespace to operate in.
+```
+
+### Options inherited from parent commands
+
+```
+      --config string       kn configuration file (default: ~/.config/kn/config.yaml)
+      --kubeconfig string   kubectl configuration file (default: ~/.kube/config)
+      --log-http            log http traffic
+```
+
+### SEE ALSO
+
+* [kn broker](kn_broker.md)	 - Manage message broker
+
diff --git a/docs/cmd/kn_broker_delete.md b/docs/cmd/kn_broker_delete.md
new file mode 100644
index 00000000..67b1c7f6
--- /dev/null
+++ b/docs/cmd/kn_broker_delete.md
@@ -0,0 +1,46 @@
+## kn broker delete
+
+Delete a broker
+
+### Synopsis
+
+Delete a broker
+
+```
+kn broker delete NAME
+```
+
+### Examples
+
+```
+
+  # Delete a broker 'mybroker' in the current namespace
+  kn broker create mybroker
+
+  # Delete a broker 'mybroker' in the 'myproject' namespace
+  kn broker create mybroker --namespace myproject
+```
+
+### Options
+
+```
+      --async              DEPRECATED: please use --no-wait instead. Do not wait for 'broker delete' operation to be completed. (default true)
+  -h, --help               help for delete
+  -n, --namespace string   Specify the namespace to operate in.
+      --no-wait            Do not wait for 'broker delete' operation to be completed. (default true)
+      --wait               Wait for 'broker delete' operation to be completed.
+      --wait-timeout int   Seconds to wait before giving up on waiting for broker to be deleted. (default 600)
+```
+
+### Options inherited from parent commands
+
+```
+      --config string       kn configuration file (default: ~/.config/kn/config.yaml)
+      --kubeconfig string   kubectl configuration file (default: ~/.kube/config)
+      --log-http            log http traffic
+```
+
+### SEE ALSO
+
+* [kn broker](kn_broker.md)	 - Manage message broker
+
diff --git a/docs/cmd/kn_broker_describe.md b/docs/cmd/kn_broker_describe.md
new file mode 100644
index 00000000..808bcf00
--- /dev/null
+++ b/docs/cmd/kn_broker_describe.md
@@ -0,0 +1,42 @@
+## kn broker describe
+
+Describe broker
+
+### Synopsis
+
+Describe broker
+
+```
+kn broker describe NAME
+```
+
+### Examples
+
+```
+
+  # Describe broker 'mybroker' in the current namespace
+  kn broker describe mybroker
+
+  # Describe broker 'mybroker' in the 'myproject' namespace
+  kn broker describe mybroker --namespace myproject
+```
+
+### Options
+
+```
+  -h, --help               help for describe
+  -n, --namespace string   Specify the namespace to operate in.
+```
+
+### Options inherited from parent commands
+
+```
+      --config string       kn configuration file (default: ~/.config/kn/config.yaml)
+      --kubeconfig string   kubectl configuration file (default: ~/.kube/config)
+      --log-http            log http traffic
+```
+
+### SEE ALSO
+
+* [kn broker](kn_broker.md)	 - Manage message broker
+
diff --git a/docs/cmd/kn_broker_list.md b/docs/cmd/kn_broker_list.md
new file mode 100644
index 00000000..506de7ee
--- /dev/null
+++ b/docs/cmd/kn_broker_list.md
@@ -0,0 +1,47 @@
+## kn broker list
+
+List brokers
+
+### Synopsis
+
+List brokers
+
+```
+kn broker list
+```
+
+### Examples
+
+```
+
+  # List all brokers
+  kn broker list
+
+  # List all brokers in JSON output format
+  kn broker list -o json
+```
+
+### Options
+
+```
+  -A, --all-namespaces                If present, list the requested object(s) across all namespaces. Namespace in current context is ignored even if specified with --namespace.
+      --allow-missing-template-keys   If true, ignore any errors in templates when a field or map key is missing in the template. Only applies to golang and jsonpath output formats. (default true)
+  -h, --help                          help for list
+  -n, --namespace string              Specify the namespace to operate in.
+      --no-headers                    When using the default output format, don't print headers (default: print headers).
+  -o, --output string                 Output format. One of: json|yaml|name|go-template|go-template-file|template|templatefile|jsonpath|jsonpath-file.
+      --template string               Template string or path to template file to use when -o=go-template, -o=go-template-file. The template format is golang templates [http://golang.org/pkg/text/template/#pkg-overview].
+```
+
+### Options inherited from parent commands
+
+```
+      --config string       kn configuration file (default: ~/.config/kn/config.yaml)
+      --kubeconfig string   kubectl configuration file (default: ~/.kube/config)
+      --log-http            log http traffic
+```
+
+### SEE ALSO
+
+* [kn broker](kn_broker.md)	 - Manage message broker
+
diff --git a/docs/cmd/kn_source_ping_create.md b/docs/cmd/kn_source_ping_create.md
index 8c26e709..f2271191 100644
--- a/docs/cmd/kn_source_ping_create.md
+++ b/docs/cmd/kn_source_ping_create.md
@@ -7,7 +7,7 @@ Create a ping source
 Create a ping source
 
 ```
-kn source ping create NAME
+kn source ping create NAME --sink SINK
 ```
 
 ### Examples
diff --git a/pkg/dynamic/fake/fake.go b/pkg/dynamic/fake/fake.go
index be89639c..c4c29568 100644
--- a/pkg/dynamic/fake/fake.go
+++ b/pkg/dynamic/fake/fake.go
@@ -29,7 +29,7 @@ import (
 func CreateFakeKnDynamicClient(testNamespace string, objects ...runtime.Object) dynamic.KnDynamicClient {
 	scheme := runtime.NewScheme()
 	scheme.AddKnownTypeWithName(schema.GroupVersionKind{Group: "serving.knative.dev", Version: "v1", Kind: "Service"}, &servingv1.Service{})
-	scheme.AddKnownTypeWithName(schema.GroupVersionKind{Group: "eventing.knative.dev", Version: "v1alpha1", Kind: "Broker"}, &eventingv1beta1.Broker{})
+	scheme.AddKnownTypeWithName(schema.GroupVersionKind{Group: "eventing.knative.dev", Version: "v1beta1", Kind: "Broker"}, &eventingv1beta1.Broker{})
 	client := dynamicfake.NewSimpleDynamicClient(scheme, objects...)
 	return dynamic.NewKnDynamicClient(client, testNamespace)
 }
diff --git a/pkg/eventing/v1beta1/client.go b/pkg/eventing/v1beta1/client.go
index 9fb2ee3f..df1b4404 100644
--- a/pkg/eventing/v1beta1/client.go
+++ b/pkg/eventing/v1beta1/client.go
@@ -15,9 +15,12 @@
 package v1beta1
 
 import (
+	"time"
+
 	apis_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/runtime"
+	"k8s.io/apimachinery/pkg/watch"
 	v1beta1 "knative.dev/eventing/pkg/apis/eventing/v1beta1"
 	"knative.dev/eventing/pkg/client/clientset/versioned/scheme"
 	client_v1beta1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/eventing/v1beta1"
@@ -25,6 +28,7 @@ import (
 
 	kn_errors "knative.dev/client/pkg/errors"
 	"knative.dev/client/pkg/util"
+	"knative.dev/client/pkg/wait"
 )
 
 // KnEventingClient to Eventing Sources. All methods are relative to the
@@ -42,6 +46,14 @@ type KnEventingClient interface {
 	ListTriggers() (*v1beta1.TriggerList, error)
 	// UpdateTrigger is used to update an instance of trigger
 	UpdateTrigger(trigger *v1beta1.Trigger) error
+	// CreateBroker is used to create an instance of broker
+	CreateBroker(broker *v1beta1.Broker) error
+	// GetBroker is used to get an instance of broker
+	GetBroker(name string) (*v1beta1.Broker, error)
+	// DeleteBroker is used to delete an instance of broker
+	DeleteBroker(name string, timeout time.Duration) error
+	// ListBroker returns list of broker CRDs
+	ListBrokers() (*v1beta1.BrokerList, error)
 }
 
 // KnEventingClient is a combination of Sources client interface and namespace
@@ -93,7 +105,7 @@ func (c *knEventingClient) ListTriggers() (*v1beta1.TriggerList, error) {
 		return nil, kn_errors.GetError(err)
 	}
 	triggerListNew := triggerList.DeepCopy()
-	err = updateTriggerGvk(triggerListNew)
+	err = updateEventingGVK(triggerListNew)
 	if err != nil {
 		return nil, err
 	}
@@ -101,7 +113,7 @@ func (c *knEventingClient) ListTriggers() (*v1beta1.TriggerList, error) {
 	triggerListNew.Items = make([]v1beta1.Trigger, len(triggerList.Items))
 	for idx, trigger := range triggerList.Items {
 		triggerClone := trigger.DeepCopy()
-		err := updateTriggerGvk(triggerClone)
+		err := updateEventingGVK(triggerClone)
 		if err != nil {
 			return nil, err
 		}
@@ -125,7 +137,7 @@ func (c *knEventingClient) Namespace() string {
 }
 
 // update with the v1beta1 group + version
-func updateTriggerGvk(obj runtime.Object) error {
+func updateEventingGVK(obj runtime.Object) error {
 	return util.UpdateGroupVersionKindWithScheme(obj, v1beta1.SchemeGroupVersion, scheme.Scheme)
 }
 
@@ -200,3 +212,104 @@ func (b *TriggerBuilder) Filters(filters map[string]string) *TriggerBuilder {
 func (b *TriggerBuilder) Build() *v1beta1.Trigger {
 	return b.trigger
 }
+
+// CreateBroker is used to create an instance of broker
+func (c *knEventingClient) CreateBroker(broker *v1beta1.Broker) error {
+	_, err := c.client.Brokers(c.namespace).Create(broker)
+	if err != nil {
+		return kn_errors.GetError(err)
+	}
+	return nil
+}
+
+// GetBroker is used to get an instance of broker
+func (c *knEventingClient) GetBroker(name string) (*v1beta1.Broker, error) {
+	trigger, err := c.client.Brokers(c.namespace).Get(name, apis_v1.GetOptions{})
+	if err != nil {
+		return nil, kn_errors.GetError(err)
+	}
+	return trigger, nil
+}
+
+// WatchBroker is used to create watcher object
+func (c *knEventingClient) WatchBroker(name string, timeout time.Duration) (watch.Interface, error) {
+	return wait.NewWatcher(c.client.Brokers(c.namespace).Watch,
+		c.client.RESTClient(), c.namespace, "brokers", name, timeout)
+}
+
+// DeleteBroker is used to delete an instance of broker and wait for completion until given timeout
+// For `timeout == 0` delete is performed async without any wait
+func (c *knEventingClient) DeleteBroker(name string, timeout time.Duration) error {
+	if timeout == 0 {
+		return c.deleteBroker(name, apis_v1.DeletePropagationBackground)
+	}
+	waitC := make(chan error)
+	go func() {
+		waitForEvent := wait.NewWaitForEvent("broker", c.WatchBroker, func(evt *watch.Event) bool { return evt.Type == watch.Deleted })
+		err, _ := waitForEvent.Wait(name, wait.Options{Timeout: &timeout}, wait.NoopMessageCallback())
+		waitC <- err
+	}()
+	err := c.deleteBroker(name, apis_v1.DeletePropagationForeground)
+	if err != nil {
+		return err
+	}
+	return <-waitC
+}
+
+// deleteBroker is used to delete an instance of broker
+func (c *knEventingClient) deleteBroker(name string, propagationPolicy apis_v1.DeletionPropagation) error {
+	err := c.client.Brokers(c.namespace).Delete(name, &apis_v1.DeleteOptions{PropagationPolicy: &propagationPolicy})
+	if err != nil {
+		return kn_errors.GetError(err)
+	}
+	return nil
+}
+
+// ListBrokers is used to retrieve the list of broker instances
+func (c *knEventingClient) ListBrokers() (*v1beta1.BrokerList, error) {
+	brokerList, err := c.client.Brokers(c.namespace).List(apis_v1.ListOptions{})
+	if err != nil {
+		return nil, kn_errors.GetError(err)
+	}
+	brokerListNew := brokerList.DeepCopy()
+	err = updateEventingGVK(brokerListNew)
+	if err != nil {
+		return nil, err
+	}
+
+	brokerListNew.Items = make([]v1beta1.Broker, len(brokerList.Items))
+	for idx, trigger := range brokerList.Items {
+		triggerClone := trigger.DeepCopy()
+		err := updateEventingGVK(triggerClone)
+		if err != nil {
+			return nil, err
+		}
+		brokerListNew.Items[idx] = *triggerClone
+	}
+	return brokerListNew, nil
+}
+
+// BrokerBuilder is for building the broker
+type BrokerBuilder struct {
+	broker *v1beta1.Broker
+}
+
+// NewBrokerBuilder for building broker object
+func NewBrokerBuilder(name string) *BrokerBuilder {
+	return &BrokerBuilder{broker: &v1beta1.Broker{
+		ObjectMeta: meta_v1.ObjectMeta{
+			Name: name,
+		},
+	}}
+}
+
+// Namespace for broker builder
+func (b *BrokerBuilder) Namespace(ns string) *BrokerBuilder {
+	b.broker.Namespace = ns
+	return b
+}
+
+// Build to return an instance of broker object
+func (b *BrokerBuilder) Build() *v1beta1.Broker {
+	return b.broker
+}
diff --git a/pkg/eventing/v1beta1/client_mock.go b/pkg/eventing/v1beta1/client_mock.go
index f93c800f..c0cabd78 100644
--- a/pkg/eventing/v1beta1/client_mock.go
+++ b/pkg/eventing/v1beta1/client_mock.go
@@ -16,6 +16,7 @@ package v1beta1
 
 import (
 	"testing"
+	"time"
 
 	v1beta1 "knative.dev/eventing/pkg/apis/eventing/v1beta1"
 
@@ -114,6 +115,50 @@ func (c *MockKnEventingClient) UpdateTrigger(trigger *v1beta1.Trigger) error {
 	return mock.ErrorOrNil(call.Result[0])
 }
 
+// CreateBroker records a call for CreateBroker with the expected error
+func (sr *EventingRecorder) CreateBroker(broker interface{}, err error) {
+	sr.r.Add("CreateBroker", []interface{}{broker}, []interface{}{err})
+}
+
+// CreateBroker performs a previously recorded action
+func (c *MockKnEventingClient) CreateBroker(broker *v1beta1.Broker) error {
+	call := c.recorder.r.VerifyCall("CreateBroker", broker)
+	return mock.ErrorOrNil(call.Result[0])
+}
+
+// GetBroker records a call for GetBroker with the expected object or error. Either trigger or err should be nil
+func (sr *EventingRecorder) GetBroker(name interface{}, broker *v1beta1.Broker, err error) {
+	sr.r.Add("GetBroker", []interface{}{name}, []interface{}{broker, err})
+}
+
+// GetBroker performs a previously recorded action
+func (c *MockKnEventingClient) GetBroker(name string) (*v1beta1.Broker, error) {
+	call := c.recorder.r.VerifyCall("GetBroker", name)
+	return call.Result[0].(*v1beta1.Broker), mock.ErrorOrNil(call.Result[1])
+}
+
+// DeleteBroker records a call for DeleteBroker with the expected error (nil if none)
+func (sr *EventingRecorder) DeleteBroker(name, timeout interface{}, err error) {
+	sr.r.Add("DeleteBroker", []interface{}{name, timeout}, []interface{}{err})
+}
+
+// DeleteBroker performs a previously recorded action, failing if non has been registered
+func (c *MockKnEventingClient) DeleteBroker(name string, timeout time.Duration) error {
+	call := c.recorder.r.VerifyCall("DeleteBroker", name, timeout)
+	return mock.ErrorOrNil(call.Result[0])
+}
+
+// ListBrokers records a call for ListBrokers with the expected result and error (nil if none)
+func (sr *EventingRecorder) ListBrokers(brokerList *v1beta1.BrokerList, err error) {
+	sr.r.Add("ListBrokers", nil, []interface{}{brokerList, err})
+}
+
+// ListBrokers performs a previously recorded action
+func (c *MockKnEventingClient) ListBrokers() (*v1beta1.BrokerList, error) {
+	call := c.recorder.r.VerifyCall("ListBrokers")
+	return call.Result[0].(*v1beta1.BrokerList), mock.ErrorOrNil(call.Result[1])
+}
+
 // Validate validates whether every recorded action has been called
 func (sr *EventingRecorder) Validate() {
 	sr.r.CheckThatAllRecordedMethodsHaveBeenCalled()
diff --git a/pkg/kn/commands/broker/broker.go b/pkg/kn/commands/broker/broker.go
new file mode 100644
index 00000000..bbb93349
--- /dev/null
+++ b/pkg/kn/commands/broker/broker.go
@@ -0,0 +1,36 @@
+/*
+Copyright 2020 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 broker
+
+import (
+	"github.com/spf13/cobra"
+
+	"knative.dev/client/pkg/kn/commands"
+)
+
+// NewBrokerCommand represents broker management commands
+func NewBrokerCommand(p *commands.KnParams) *cobra.Command {
+	brokerCmd := &cobra.Command{
+		Use:   "broker",
+		Short: "Manage message broker",
+	}
+	brokerCmd.AddCommand(NewBrokerCreateCommand(p))
+	brokerCmd.AddCommand(NewBrokerDescribeCommand(p))
+	brokerCmd.AddCommand(NewBrokerDeleteCommand(p))
+	brokerCmd.AddCommand(NewBrokerListCommand(p))
+	return brokerCmd
+}
diff --git a/pkg/kn/commands/broker/create.go b/pkg/kn/commands/broker/create.go
new file mode 100644
index 00000000..81940e6d
--- /dev/null
+++ b/pkg/kn/commands/broker/create.go
@@ -0,0 +1,75 @@
+/*
+Copyright 2020 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 broker
+
+import (
+	"errors"
+	"fmt"
+
+	"github.com/spf13/cobra"
+
+	clientv1beta1 "knative.dev/client/pkg/eventing/v1beta1"
+	"knative.dev/client/pkg/kn/commands"
+)
+
+var createExample = `
+  # Create a broker 'mybroker' in the current namespace
+  kn broker create mybroker
+
+  # Create a broker 'mybroker' in the 'myproject' namespace
+  kn broker create mybroker --namespace myproject`
+
+// NewBrokerCreateCommand represents command to create new broker instance
+func NewBrokerCreateCommand(p *commands.KnParams) *cobra.Command {
+
+	cmd := &cobra.Command{
+		Use:     "create NAME",
+		Short:   "Create a broker",
+		Example: createExample,
+		RunE: func(cmd *cobra.Command, args []string) (err error) {
+			if len(args) != 1 {
+				return errors.New("'broker create' requires the broker name given as single argument")
+			}
+			name := args[0]
+
+			namespace, err := p.GetNamespace(cmd)
+			if err != nil {
+				return err
+			}
+
+			eventingClient, err := p.NewEventingClient(namespace)
+			if err != nil {
+				return err
+			}
+
+			brokerBuilder := clientv1beta1.
+				NewBrokerBuilder(name).
+				Namespace(namespace)
+
+			err = eventingClient.CreateBroker(brokerBuilder.Build())
+			if err != nil {
+				return fmt.Errorf(
+					"cannot create broker '%s' in namespace '%s' "+
+						"because: %s", name, namespace, err)
+			}
+			fmt.Fprintf(cmd.OutOrStdout(), "Broker '%s' successfully created in namespace '%s'.\n", args[0], namespace)
+			return nil
+		},
+	}
+	commands.AddNamespaceFlags(cmd.Flags(), false)
+	return cmd
+}
diff --git a/pkg/kn/commands/broker/delete.go b/pkg/kn/commands/broker/delete.go
new file mode 100644
index 00000000..1af0f8a1
--- /dev/null
+++ b/pkg/kn/commands/broker/delete.go
@@ -0,0 +1,77 @@
+/*
+Copyright 2020 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 broker
+
+import (
+	"errors"
+	"fmt"
+	"time"
+
+	"github.com/spf13/cobra"
+
+	"knative.dev/client/pkg/kn/commands"
+)
+
+var deleteExample = `
+  # Delete a broker 'mybroker' in the current namespace
+  kn broker create mybroker
+
+  # Delete a broker 'mybroker' in the 'myproject' namespace
+  kn broker create mybroker --namespace myproject`
+
+// NewBrokerDeleteCommand represents command to existing delete broker
+func NewBrokerDeleteCommand(p *commands.KnParams) *cobra.Command {
+	var waitFlags commands.WaitFlags
+
+	cmd := &cobra.Command{
+		Use:     "delete NAME",
+		Short:   "Delete a broker",
+		Example: deleteExample,
+		RunE: func(cmd *cobra.Command, args []string) (err error) {
+			if len(args) != 1 {
+				return errors.New("'broker delete' requires the broker name given as single argument")
+			}
+			name := args[0]
+
+			namespace, err := p.GetNamespace(cmd)
+			if err != nil {
+				return err
+			}
+
+			eventingClient, err := p.NewEventingClient(namespace)
+			if err != nil {
+				return err
+			}
+
+			timeout := time.Duration(0)
+			if waitFlags.Wait {
+				timeout = time.Duration(waitFlags.TimeoutInSeconds) * time.Second
+			}
+			err = eventingClient.DeleteBroker(name, timeout)
+			if err != nil {
+				return fmt.Errorf(
+					"cannot delete broker '%s' in namespace '%s' "+
+						"because: %s", name, namespace, err)
+			}
+			fmt.Fprintf(cmd.OutOrStdout(), "Broker '%s' successfully deleted in namespace '%s'.\n", args[0], namespace)
+			return nil
+		},
+	}
+	commands.AddNamespaceFlags(cmd.Flags(), false)
+	waitFlags.AddConditionWaitFlags(cmd, commands.WaitDefaultTimeout, "delete", "broker", "deleted")
+	return cmd
+}
diff --git a/pkg/kn/commands/broker/describe.go b/pkg/kn/commands/broker/describe.go
new file mode 100644
index 00000000..f18c9d46
--- /dev/null
+++ b/pkg/kn/commands/broker/describe.go
@@ -0,0 +1,84 @@
+/*
+Copyright 2020 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 broker
+
+import (
+	"errors"
+	"io"
+
+	"github.com/spf13/cobra"
+
+	v1beta1 "knative.dev/eventing/pkg/apis/eventing/v1beta1"
+
+	"knative.dev/client/pkg/kn/commands"
+	"knative.dev/client/pkg/printers"
+)
+
+var describeExample = `
+  # Describe broker 'mybroker' in the current namespace
+  kn broker describe mybroker
+
+  # Describe broker 'mybroker' in the 'myproject' namespace
+  kn broker describe mybroker --namespace myproject`
+
+// NewBrokerDescribeCommand represents command to describe details of broker instance
+func NewBrokerDescribeCommand(p *commands.KnParams) *cobra.Command {
+
+	cmd := &cobra.Command{
+		Use:     "describe NAME",
+		Short:   "Describe broker",
+		Example: describeExample,
+		RunE: func(cmd *cobra.Command, args []string) (err error) {
+			if len(args) != 1 {
+				return errors.New("'broker describe' requires the broker name given as single argument")
+			}
+			name := args[0]
+
+			namespace, err := p.GetNamespace(cmd)
+			if err != nil {
+				return err
+			}
+
+			eventingClient, err := p.NewEventingClient(namespace)
+			if err != nil {
+				return err
+			}
+
+			broker, err := eventingClient.GetBroker(name)
+			if err != nil {
+				return err
+			}
+			return describeBroker(cmd.OutOrStdout(), broker, false)
+		},
+	}
+	commands.AddNamespaceFlags(cmd.Flags(), false)
+	return cmd
+}
+
+// describeBroker print broker details to the provided output writer
+func describeBroker(out io.Writer, broker *v1beta1.Broker, printDetails bool) error {
+	dw := printers.NewPrefixWriter(out)
+	commands.WriteMetadata(dw, &broker.ObjectMeta, printDetails)
+	dw.WriteLine()
+	dw.WriteAttribute("Address", "").WriteAttribute("URL", broker.Status.Address.URL.String())
+	dw.WriteLine()
+	commands.WriteConditions(dw, broker.Status.Conditions, printDetails)
+	if err := dw.Flush(); err != nil {
+		return err
+	}
+	return nil
+}
diff --git a/pkg/kn/commands/broker/list.go b/pkg/kn/commands/broker/list.go
new file mode 100644
index 00000000..a4418187
--- /dev/null
+++ b/pkg/kn/commands/broker/list.go
@@ -0,0 +1,139 @@
+/*
+Copyright 2020 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 broker
+
+import (
+	"fmt"
+
+	"github.com/spf13/cobra"
+
+	metav1beta1 "k8s.io/apimachinery/pkg/apis/meta/v1beta1"
+	"k8s.io/apimachinery/pkg/runtime"
+
+	"knative.dev/client/pkg/kn/commands"
+	"knative.dev/client/pkg/kn/commands/flags"
+	hprinters "knative.dev/client/pkg/printers"
+	"knative.dev/eventing/pkg/apis/eventing/v1beta1"
+)
+
+var listExample = `
+  # List all brokers
+  kn broker list
+
+  # List all brokers in JSON output format
+  kn broker list -o json`
+
+// NewBrokerListCommand represents command to list all brokers
+func NewBrokerListCommand(p *commands.KnParams) *cobra.Command {
+	brokerListFlags := flags.NewListPrintFlags(ListHandlers)
+
+	cmd := &cobra.Command{
+		Use:     "list",
+		Short:   "List brokers",
+		Example: listExample,
+		RunE: func(cmd *cobra.Command, args []string) (err error) {
+			namespace, err := p.GetNamespace(cmd)
+			if err != nil {
+				return err
+			}
+
+			eventingClient, err := p.NewEventingClient(namespace)
+			if err != nil {
+				return err
+			}
+
+			brokerList, err := eventingClient.ListBrokers()
+			if err != nil {
+				return err
+			}
+			if len(brokerList.Items) == 0 {
+				fmt.Fprintf(cmd.OutOrStdout(), "No brokers found.\n")
+				return nil
+			}
+
+			// empty namespace indicates all-namespaces flag is specified
+			if namespace == "" {
+				brokerListFlags.EnsureWithNamespace()
+			}
+
+			err = brokerListFlags.Print(brokerList, cmd.OutOrStdout())
+			if err != nil {
+				return err
+			}
+			return nil
+		},
+	}
+	commands.AddNamespaceFlags(cmd.Flags(), true)
+	brokerListFlags.AddFlags(cmd)
+	return cmd
+}
+
+// ListHandlers handles printing human readable table for `kn broker list` command's output
+func ListHandlers(h hprinters.PrintHandler) {
+	brokerColumnDefinitions := []metav1beta1.TableColumnDefinition{
+		{Name: "Namespace", Type: "string", Description: "Namespace of the Broker instance", Priority: 0},
+		{Name: "Name", Type: "string", Description: "Name of the Broker instance", Priority: 1},
+		{Name: "URL", Type: "string", Description: "URL of the Broker instance", Priority: 1},
+		{Name: "Age", Type: "string", Description: "Age of the Broker instance", Priority: 1},
+		{Name: "Conditions", Type: "string", Description: "Ready state conditions", Priority: 1},
+		{Name: "Ready", Type: "string", Description: "Ready state of the Broker instance", Priority: 1},
+		{Name: "Reason", Type: "string", Description: "Reason if state is not Ready", Priority: 1},
+	}
+	h.TableHandler(brokerColumnDefinitions, printBroker)
+	h.TableHandler(brokerColumnDefinitions, printBrokerList)
+}
+
+// printBrokerList populates the broker list table rows
+func printBrokerList(kServiceList *v1beta1.BrokerList, options hprinters.PrintOptions) ([]metav1beta1.TableRow, error) {
+	rows := make([]metav1beta1.TableRow, 0, len(kServiceList.Items))
+
+	for _, ksvc := range kServiceList.Items {
+		r, err := printBroker(&ksvc, options)
+		if err != nil {
+			return nil, err
+		}
+		rows = append(rows, r...)
+	}
+	return rows, nil
+}
+
+// printBroker populates the broker table rows
+func printBroker(broker *v1beta1.Broker, options hprinters.PrintOptions) ([]metav1beta1.TableRow, error) {
+	name := broker.Name
+	url := broker.Status.Address.URL
+	age := commands.TranslateTimestampSince(broker.CreationTimestamp)
+	conditions := commands.ConditionsValue(broker.Status.Conditions)
+	ready := commands.ReadyCondition(broker.Status.Conditions)
+	reason := commands.NonReadyConditionReason(broker.Status.Conditions)
+
+	row := metav1beta1.TableRow{
+		Object: runtime.RawExtension{Object: broker},
+	}
+
+	if options.AllNamespaces {
+		row.Cells = append(row.Cells, broker.Namespace)
+	}
+
+	row.Cells = append(row.Cells,
+		name,
+		url,
+		age,
+		conditions,
+		ready,
+		reason)
+	return []metav1beta1.TableRow{row}, nil
+}
diff --git a/pkg/kn/commands/flags/sink.go b/pkg/kn/commands/flags/sink.go
index d8732b8b..0ef554ad 100644
--- a/pkg/kn/commands/flags/sink.go
+++ b/pkg/kn/commands/flags/sink.go
@@ -50,7 +50,7 @@ var sinkMappings = map[string]schema.GroupVersionResource{
 	"broker": {
 		Resource: "brokers",
 		Group:    "eventing.knative.dev",
-		Version:  "v1alpha1",
+		Version:  "v1beta1",
 	},
 	"service": {
 		Resource: "services",
diff --git a/pkg/kn/commands/source/ping/create.go b/pkg/kn/commands/source/ping/create.go
index b667d0d8..eca52966 100644
--- a/pkg/kn/commands/source/ping/create.go
+++ b/pkg/kn/commands/source/ping/create.go
@@ -32,7 +32,7 @@ func NewPingCreateCommand(p *commands.KnParams) *cobra.Command {
 	var sinkFlags flags.SinkFlags
 
 	cmd := &cobra.Command{
-		Use:   "create NAME",
+		Use:   "create NAME --sink SINK",
 		Short: "Create a ping source",
 		Example: `
   # Create a Ping source 'my-ping' which fires every two minutes and sends '{ value: "hello" }' to service 'mysvc' as a cloudevent
diff --git a/pkg/kn/commands/trigger/describe.go b/pkg/kn/commands/trigger/describe.go
index 331b7508..4cae159f 100644
--- a/pkg/kn/commands/trigger/describe.go
+++ b/pkg/kn/commands/trigger/describe.go
@@ -98,10 +98,10 @@ func NewTriggerDescribeCommand(p *commands.KnParams) *cobra.Command {
 
 func writeSink(dw printers.PrefixWriter, sink *duckv1.Destination) {
 	subWriter := dw.WriteAttribute("Sink", "")
-	subWriter.WriteAttribute("Name", sink.Ref.Name)
-	subWriter.WriteAttribute("Namespace", sink.Ref.Namespace)
 	ref := sink.Ref
 	if ref != nil {
+		subWriter.WriteAttribute("Name", sink.Ref.Name)
+		subWriter.WriteAttribute("Namespace", sink.Ref.Namespace)
 		subWriter.WriteAttribute("Resource", fmt.Sprintf("%s (%s)", sink.Ref.Kind, sink.Ref.APIVersion))
 	}
 	uri := sink.URI
diff --git a/pkg/kn/root/root.go b/pkg/kn/root/root.go
index d738fb2b..17a77528 100644
--- a/pkg/kn/root/root.go
+++ b/pkg/kn/root/root.go
@@ -25,6 +25,7 @@ import (
 	_ "k8s.io/client-go/plugin/pkg/client/auth/oidc"
 
 	"knative.dev/client/pkg/kn/commands"
+	"knative.dev/client/pkg/kn/commands/broker"
 	"knative.dev/client/pkg/kn/commands/completion"
 	"knative.dev/client/pkg/kn/commands/options"
 	"knative.dev/client/pkg/kn/commands/plugin"
@@ -89,6 +90,7 @@ func NewRootCommand() (*cobra.Command, error) {
 			Header: "Eventing Commands:",
 			Commands: []*cobra.Command{
 				source.NewSourceCommand(p),
+				broker.NewBrokerCommand(p),
 				trigger.NewTriggerCommand(p),
 			},
 		},


Test patch:
diff --git a/lib/test/broker.go b/lib/test/broker.go
new file mode 100644
index 00000000..99dcb953
--- /dev/null
+++ b/lib/test/broker.go
@@ -0,0 +1,48 @@
+// Copyright 2020 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 im
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package test
+
+import (
+	"strings"
+	"time"
+
+	"k8s.io/apimachinery/pkg/util/wait"
+)
+
+// LabelNamespaceForDefaultBroker adds label 'knative-eventing-injection=enabled' to the configured namespace
+func LabelNamespaceForDefaultBroker(r *KnRunResultCollector) error {
+	_, err := Kubectl{}.Run("label", "namespace", r.KnTest().Kn().Namespace(), "knative-eventing-injection=enabled")
+
+	if err != nil {
+		r.T().Fatalf("Error executing 'kubectl label namespace %s knative-eventing-injection=enabled'. Error: %s", r.KnTest().Kn().Namespace(), err.Error())
+	}
+
+	return wait.PollImmediate(10*time.Second, 5*time.Minute, func() (bool, error) {
+		out, err := NewKubectl(r.KnTest().Kn().Namespace()).Run("get", "broker", "-o=jsonpath='{.items[0].status.conditions[?(@.type==\"Ready\")].status}'")
+		if err != nil {
+			return false, nil
+		}
+
+		return strings.Contains(out, "True"), nil
+	})
+}
+
+// UnlabelNamespaceForDefaultBroker removes label 'knative-eventing-injection=enabled' from the configured namespace
+func UnlabelNamespaceForDefaultBroker(r *KnRunResultCollector) {
+	_, err := Kubectl{}.Run("label", "namespace", r.KnTest().Kn().Namespace(), "knative-eventing-injection-")
+	if err != nil {
+		r.T().Fatalf("Error executing 'kubectl label namespace %s knative-eventing-injection-'. Error: %s", r.KnTest().Kn().Namespace(), err.Error())
+	}
+}
diff --git a/pkg/eventing/v1beta1/client_mock_test.go b/pkg/eventing/v1beta1/client_mock_test.go
index 5062310c..38dc2610 100644
--- a/pkg/eventing/v1beta1/client_mock_test.go
+++ b/pkg/eventing/v1beta1/client_mock_test.go
@@ -16,6 +16,7 @@ package v1beta1
 
 import (
 	"testing"
+	"time"
 
 	v1beta1 "knative.dev/eventing/pkg/apis/eventing/v1beta1"
 )
@@ -33,6 +34,11 @@ func TestMockKnClient(t *testing.T) {
 	recorder.ListTriggers(nil, nil)
 	recorder.UpdateTrigger(&v1beta1.Trigger{}, nil)
 
+	recorder.CreateBroker(&v1beta1.Broker{}, nil)
+	recorder.GetBroker("foo", nil, nil)
+	recorder.DeleteBroker("foo", time.Duration(10)*time.Second, nil)
+	recorder.ListBrokers(nil, nil)
+
 	// Call all service
 	client.GetTrigger("hello")
 	client.CreateTrigger(&v1beta1.Trigger{})
@@ -40,6 +46,11 @@ func TestMockKnClient(t *testing.T) {
 	client.ListTriggers()
 	client.UpdateTrigger(&v1beta1.Trigger{})
 
+	client.CreateBroker(&v1beta1.Broker{})
+	client.GetBroker("foo")
+	client.DeleteBroker("foo", time.Duration(10)*time.Second)
+	client.ListBrokers()
+
 	// Validate
 	recorder.Validate()
 }
diff --git a/pkg/eventing/v1beta1/client_test.go b/pkg/eventing/v1beta1/client_test.go
index 57e5a86e..73832cad 100644
--- a/pkg/eventing/v1beta1/client_test.go
+++ b/pkg/eventing/v1beta1/client_test.go
@@ -17,14 +17,21 @@ package v1beta1
 import (
 	"fmt"
 	"testing"
+	"time"
 
 	"gotest.tools/assert"
+	"k8s.io/apimachinery/pkg/api/errors"
 	"k8s.io/apimachinery/pkg/runtime"
+	"k8s.io/apimachinery/pkg/watch"
 
+	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	client_testing "k8s.io/client-go/testing"
+	"knative.dev/client/pkg/wait"
 	v1beta1 "knative.dev/eventing/pkg/apis/eventing/v1beta1"
 	"knative.dev/eventing/pkg/client/clientset/versioned/typed/eventing/v1beta1/fake"
+	"knative.dev/pkg/apis"
+	duckv1 "knative.dev/pkg/apis/duck/v1"
 )
 
 var testNamespace = "test-ns"
@@ -184,6 +191,128 @@ func TestTriggerBuilder(t *testing.T) {
 
 }
 
+func TestBrokerCreate(t *testing.T) {
+	var name = "broker"
+	server, client := setup()
+
+	objNew := newBroker(name)
+
+	server.AddReactor("create", "brokers",
+		func(a client_testing.Action) (bool, runtime.Object, error) {
+			assert.Equal(t, testNamespace, a.GetNamespace())
+			name := a.(client_testing.CreateAction).GetObject().(metav1.Object).GetName()
+			if name == objNew.Name {
+				objNew.Generation = 2
+				return true, objNew, nil
+			}
+			return true, nil, fmt.Errorf("error while creating broker %s", name)
+		})
+
+	t.Run("create broker without error", func(t *testing.T) {
+		err := client.CreateBroker(objNew)
+		assert.NilError(t, err)
+	})
+
+	t.Run("create broker with an error returns an error object", func(t *testing.T) {
+		err := client.CreateBroker(newBroker("unknown"))
+		assert.ErrorContains(t, err, "unknown")
+	})
+}
+
+func TestBrokerGet(t *testing.T) {
+	var name = "foo"
+	server, client := setup()
+
+	server.AddReactor("get", "brokers",
+		func(a client_testing.Action) (bool, runtime.Object, error) {
+			name := a.(client_testing.GetAction).GetName()
+			if name == "errorBroker" {
+				return true, nil, fmt.Errorf("error while getting broker %s", name)
+			}
+			return true, newBroker(name), nil
+		})
+
+	broker, err := client.GetBroker(name)
+	assert.NilError(t, err)
+	assert.Equal(t, broker.Name, name)
+
+	_, err = client.GetBroker("errorBroker")
+	assert.ErrorContains(t, err, "errorBroker")
+}
+
+func TestBrokerDelete(t *testing.T) {
+	var name = "fooBroker"
+	server, client := setup()
+
+	server.AddReactor("delete", "brokers",
+		func(a client_testing.Action) (bool, runtime.Object, error) {
+			name := a.(client_testing.DeleteAction).GetName()
+			if name == "errorBroker" {
+				return true, nil, fmt.Errorf("error while deleting broker %s", name)
+			}
+			return true, nil, nil
+		})
+
+	err := client.DeleteBroker(name, 0)
+	assert.NilError(t, err)
+
+	err = client.DeleteBroker("errorBroker", 0)
+	assert.ErrorContains(t, err, "errorBroker", 0)
+}
+
+func TestBrokerDeleteWithWait(t *testing.T) {
+	var name = "fooBroker"
+	server, client := setup()
+
+	server.AddReactor("delete", "brokers",
+		func(a client_testing.Action) (bool, runtime.Object, error) {
+			name := a.(client_testing.DeleteAction).GetName()
+			if name == "errorBroker" {
+				return true, nil, fmt.Errorf("error while deleting broker %s", name)
+			}
+			return true, nil, nil
+		})
+
+	server.AddWatchReactor("brokers",
+		func(a client_testing.Action) (bool, watch.Interface, error) {
+			watchAction := a.(client_testing.WatchAction)
+			name, found := watchAction.GetWatchRestrictions().Fields.RequiresExactMatch("metadata.name")
+			if !found {
+				return true, nil, errors.NewNotFound(v1beta1.Resource("broker"), name)
+			}
+			w := wait.NewFakeWatch(getBrokerDeleteEvents("fooBroker"))
+			w.Start()
+			return true, w, nil
+		})
+
+	err := client.DeleteBroker(name, time.Duration(10)*time.Second)
+	assert.NilError(t, err)
+
+	err = client.DeleteBroker("errorBroker", time.Duration(10)*time.Second)
+	assert.ErrorContains(t, err, "errorBroker", time.Duration(10)*time.Second)
+}
+
+func TestBrokerList(t *testing.T) {
+	serving, client := setup()
+
+	t.Run("broker list returns a list of brokers", func(t *testing.T) {
+		broker1 := newBroker("foo1")
+		broker2 := newBroker("foo2")
+
+		serving.AddReactor("list", "brokers",
+			func(a client_testing.Action) (bool, runtime.Object, error) {
+				assert.Equal(t, testNamespace, a.GetNamespace())
+				return true, &v1beta1.BrokerList{Items: []v1beta1.Broker{*broker1, *broker2}}, nil
+			})
+
+		brokerList, err := client.ListBrokers()
+		assert.NilError(t, err)
+		assert.Assert(t, len(brokerList.Items) == 2)
+		assert.Equal(t, brokerList.Items[0].Name, "foo1")
+		assert.Equal(t, brokerList.Items[1].Name, "foo2")
+	})
+}
+
 func newTrigger(name string) *v1beta1.Trigger {
 	return NewTriggerBuilder(name).
 		Namespace(testNamespace).
@@ -191,3 +320,27 @@ func newTrigger(name string) *v1beta1.Trigger {
 		Filters(map[string]string{"type": "foo"}).
 		Build()
 }
+
+func newBroker(name string) *v1beta1.Broker {
+	return NewBrokerBuilder(name).
+		Namespace(testNamespace).
+		Build()
+}
+
+func getBrokerDeleteEvents(name string) []watch.Event {
+	return []watch.Event{
+		{watch.Added, createBrokerWithConditions(name, corev1.ConditionUnknown, corev1.ConditionUnknown, "", "msg1")},
+		{watch.Modified, createBrokerWithConditions(name, corev1.ConditionUnknown, corev1.ConditionTrue, "", "msg2")},
+		{watch.Deleted, createBrokerWithConditions(name, corev1.ConditionTrue, corev1.ConditionTrue, "", "")},
+	}
+}
+
+func createBrokerWithConditions(name string, readyStatus corev1.ConditionStatus, otherReadyStatus corev1.ConditionStatus, reason string, message string) runtime.Object {
+	broker := newBroker(name)
+	broker.Status.Conditions = duckv1.Conditions([]apis.Condition{
+		{Type: "ChannelServiceReady", Status: otherReadyStatus},
+		{Type: apis.ConditionReady, Status: readyStatus, Reason: reason, Message: message},
+		{Type: "Addressable", Status: otherReadyStatus},
+	})
+	return broker
+}
diff --git a/pkg/kn/commands/broker/broker_test.go b/pkg/kn/commands/broker/broker_test.go
new file mode 100644
index 00000000..e2460656
--- /dev/null
+++ b/pkg/kn/commands/broker/broker_test.go
@@ -0,0 +1,79 @@
+/*
+Copyright 2020 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 broker
+
+import (
+	"bytes"
+
+	"k8s.io/client-go/tools/clientcmd"
+
+	clientv1beta1 "knative.dev/client/pkg/eventing/v1beta1"
+	"knative.dev/client/pkg/kn/commands"
+	v1beta1 "knative.dev/eventing/pkg/apis/eventing/v1beta1"
+)
+
+// Helper methods
+var blankConfig clientcmd.ClientConfig
+
+func init() {
+	var err error
+	blankConfig, err = clientcmd.NewClientConfigFromBytes([]byte(`kind: Config
+version: v1
+users:
+- name: u
+clusters:
+- name: c
+  cluster:
+    server: example.com
+contexts:
+- name: x
+  context:
+    user: u
+    cluster: c
+current-context: x
+`))
+	if err != nil {
+		panic(err)
+	}
+}
+
+func executeBrokerCommand(brokerClient clientv1beta1.KnEventingClient, args ...string) (string, error) {
+	knParams := &commands.KnParams{}
+	knParams.ClientConfig = blankConfig
+
+	output := new(bytes.Buffer)
+	knParams.Output = output
+
+	knParams.NewEventingClient = func(namespace string) (clientv1beta1.KnEventingClient, error) {
+		return brokerClient, nil
+	}
+
+	cmd := NewBrokerCommand(knParams)
+	cmd.SetArgs(args)
+	cmd.SetOutput(output)
+
+	err := cmd.Execute()
+
+	return output.String(), err
+}
+
+func createBroker(brokerName string) *v1beta1.Broker {
+	return clientv1beta1.NewBrokerBuilder(brokerName).Namespace("default").Build()
+}
+
+func createBrokerWithNamespace(brokerName, namespace string) *v1beta1.Broker {
+	return clientv1beta1.NewBrokerBuilder(brokerName).Namespace(namespace).Build()
+}
diff --git a/pkg/kn/commands/broker/create_test.go b/pkg/kn/commands/broker/create_test.go
new file mode 100644
index 00000000..a45fdd5b
--- /dev/null
+++ b/pkg/kn/commands/broker/create_test.go
@@ -0,0 +1,51 @@
+/*
+Copyright 2020 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 broker
+
+import (
+	"testing"
+
+	"gotest.tools/assert"
+
+	clienteventingv1beta1 "knative.dev/client/pkg/eventing/v1beta1"
+	"knative.dev/client/pkg/util"
+)
+
+var (
+	brokerName = "foo"
+)
+
+func TestBrokerCreate(t *testing.T) {
+	eventingClient := clienteventingv1beta1.NewMockKnEventingClient(t)
+
+	eventingRecorder := eventingClient.Recorder()
+	eventingRecorder.CreateBroker(createBroker(brokerName), nil)
+
+	out, err := executeBrokerCommand(eventingClient, "create", brokerName)
+	assert.NilError(t, err, "Broker should be created")
+	util.ContainsAll(out, "Broker", brokerName, "created", "namespace", "default")
+
+	eventingRecorder.Validate()
+}
+
+func TestBrokerCreateWithError(t *testing.T) {
+	eventingClient := clienteventingv1beta1.NewMockKnEventingClient(t)
+
+	_, err := executeBrokerCommand(eventingClient, "create")
+	assert.ErrorContains(t, err, "broker create")
+	util.ContainsAll(err.Error(), "broker create", "requires", "name", "argument")
+}
diff --git a/pkg/kn/commands/broker/delete_test.go b/pkg/kn/commands/broker/delete_test.go
new file mode 100644
index 00000000..a3ffc401
--- /dev/null
+++ b/pkg/kn/commands/broker/delete_test.go
@@ -0,0 +1,56 @@
+/*
+Copyright 2020 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 broker
+
+import (
+	"fmt"
+	"testing"
+
+	"gotest.tools/assert"
+
+	clienteventingv1beta1 "knative.dev/client/pkg/eventing/v1beta1"
+	"knative.dev/client/pkg/util"
+	"knative.dev/client/pkg/util/mock"
+)
+
+func TestBrokerDelete(t *testing.T) {
+	brokerName := "foo"
+	eventingClient := clienteventingv1beta1.NewMockKnEventingClient(t)
+
+	eventingRecorder := eventingClient.Recorder()
+	eventingRecorder.DeleteBroker(brokerName, mock.Any(), nil)
+
+	out, err := executeBrokerCommand(eventingClient, "delete", brokerName)
+	assert.NilError(t, err, "Broker should be deleted")
+	util.ContainsAll(out, "Broker", brokerName, "deleted", "namespace", "default")
+
+	eventingRecorder.Validate()
+}
+
+func TestBrokerWithDelete(t *testing.T) {
+	brokerName := "foo"
+	eventingClient := clienteventingv1beta1.NewMockKnEventingClient(t)
+
+	eventingRecorder := eventingClient.Recorder()
+	eventingRecorder.DeleteBroker(brokerName, mock.Any(), fmt.Errorf("broker %s not found", brokerName))
+
+	out, err := executeBrokerCommand(eventingClient, "delete", brokerName)
+	assert.ErrorContains(t, err, brokerName)
+	util.ContainsAll(out, "broker", brokerName, "not found")
+
+	eventingRecorder.Validate()
+}
diff --git a/pkg/kn/commands/broker/describe_test.go b/pkg/kn/commands/broker/describe_test.go
new file mode 100644
index 00000000..b37760f1
--- /dev/null
+++ b/pkg/kn/commands/broker/describe_test.go
@@ -0,0 +1,97 @@
+/*
+Copyright 2020 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 broker
+
+import (
+	"errors"
+	"strings"
+	"testing"
+
+	"gotest.tools/assert"
+	"gotest.tools/assert/cmp"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	v1beta1 "knative.dev/eventing/pkg/apis/eventing/v1beta1"
+	"knative.dev/pkg/apis"
+	duckv1 "knative.dev/pkg/apis/duck/v1"
+
+	clientv1beta1 "knative.dev/client/pkg/eventing/v1beta1"
+	"knative.dev/client/pkg/util"
+)
+
+func TestBrokerDescribe(t *testing.T) {
+	client := clientv1beta1.NewMockKnEventingClient(t, "mynamespace")
+
+	recorder := client.Recorder()
+	recorder.GetBroker("foo", getBroker(), nil)
+
+	out, err := executeBrokerCommand(client, "describe", "foo")
+	assert.NilError(t, err)
+
+	assert.Assert(t, cmp.Regexp("Name:\\s+foo", out))
+	assert.Assert(t, cmp.Regexp("Namespace:\\s+default", out))
+
+	assert.Assert(t, util.ContainsAll(out, "Address:", "URL:", "http://foo-broker.test"))
+	assert.Assert(t, util.ContainsAll(out, "Conditions:", "Ready"))
+
+	// There're 2 empty lines used in the "describe" formatting
+	lineCounter := 0
+	for _, line := range strings.Split(strings.TrimSpace(out), "\n") {
+		if line == "" {
+			lineCounter++
+		}
+	}
+	assert.Equal(t, lineCounter, 2)
+
+	// Validate that all recorded API methods have been called
+	recorder.Validate()
+}
+
+func TestDescribeError(t *testing.T) {
+	client := clientv1beta1.NewMockKnEventingClient(t, "mynamespace")
+
+	recorder := client.Recorder()
+	recorder.GetBroker("foo", nil, errors.New("brokers.eventing.knative.dev 'foo' not found"))
+
+	_, err := executeBrokerCommand(client, "describe", "foo")
+	assert.ErrorContains(t, err, "foo", "not found")
+
+	recorder.Validate()
+}
+
+func getBroker() *v1beta1.Broker {
+	return &v1beta1.Broker{
+		TypeMeta: v1.TypeMeta{},
+		ObjectMeta: metav1.ObjectMeta{
+			Name:      "foo",
+			Namespace: "default",
+		},
+		Status: v1beta1.BrokerStatus{
+			Address: duckv1.Addressable{
+				URL: &apis.URL{Scheme: "http", Host: "foo-broker.test"},
+			},
+			Status: duckv1.Status{
+				Conditions: duckv1.Conditions{
+					apis.Condition{
+						Type:   "Ready",
+						Status: "True",
+					},
+				},
+			},
+		},
+	}
+}
diff --git a/pkg/kn/commands/broker/list_test.go b/pkg/kn/commands/broker/list_test.go
new file mode 100644
index 00000000..4a439cd4
--- /dev/null
+++ b/pkg/kn/commands/broker/list_test.go
@@ -0,0 +1,84 @@
+/*
+Copyright 2020 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 broker
+
+import (
+	"strings"
+	"testing"
+
+	"gotest.tools/assert"
+
+	clienteventingv1beta1 "knative.dev/client/pkg/eventing/v1beta1"
+	"knative.dev/client/pkg/util"
+	v1beta1 "knative.dev/eventing/pkg/apis/eventing/v1beta1"
+)
+
+func TestBrokerList(t *testing.T) {
+	eventingClient := clienteventingv1beta1.NewMockKnEventingClient(t)
+	eventingRecorder := eventingClient.Recorder()
+
+	broker1 := createBroker("foo1")
+	broker2 := createBroker("foo2")
+	broker3 := createBroker("foo3")
+	brokerList := &v1beta1.BrokerList{Items: []v1beta1.Broker{*broker1, *broker2, *broker3}}
+	eventingRecorder.ListBrokers(brokerList, nil)
+
+	output, err := executeBrokerCommand(eventingClient, "list")
+	assert.NilError(t, err)
+
+	outputLines := strings.Split(output, "\n")
+	assert.Check(t, util.ContainsAll(outputLines[0], "NAME", "URL", "AGE", "CONDITIONS", "READY", "REASON"))
+	assert.Check(t, util.ContainsAll(outputLines[1], "foo1"))
+	assert.Check(t, util.ContainsAll(outputLines[2], "foo2"))
+	assert.Check(t, util.ContainsAll(outputLines[3], "foo3"))
+
+	eventingRecorder.Validate()
+}
+
+func TestBrokerListEmpty(t *testing.T) {
+	eventingClient := clienteventingv1beta1.NewMockKnEventingClient(t)
+	eventingRecorder := eventingClient.Recorder()
+
+	eventingRecorder.ListBrokers(&v1beta1.BrokerList{}, nil)
+	output, err := executeBrokerCommand(eventingClient, "list")
+	assert.NilError(t, err)
+	assert.Assert(t, util.ContainsAll(output, "No", "brokers", "found"))
+
+	eventingRecorder.Validate()
+}
+
+func TestTriggerListAllNamespace(t *testing.T) {
+	eventingClient := clienteventingv1beta1.NewMockKnEventingClient(t)
+	eventingRecorder := eventingClient.Recorder()
+
+	broker1 := createBrokerWithNamespace("foo1", "default1")
+	broker2 := createBrokerWithNamespace("foo2", "default2")
+	broker3 := createBrokerWithNamespace("foo3", "default3")
+	brokerList := &v1beta1.BrokerList{Items: []v1beta1.Broker{*broker1, *broker2, *broker3}}
+	eventingRecorder.ListBrokers(brokerList, nil)
+
+	output, err := executeBrokerCommand(eventingClient, "list", "--all-namespaces")
+	assert.NilError(t, err)
+
+	outputLines := strings.Split(output, "\n")
+	assert.Check(t, util.ContainsAll(outputLines[0], "NAMESPACE", "NAME", "AGE", "CONDITIONS", "READY", "REASON"))
+	assert.Check(t, util.ContainsAll(outputLines[1], "default1", "foo1"))
+	assert.Check(t, util.ContainsAll(outputLines[2], "default2", "foo2"))
+	assert.Check(t, util.ContainsAll(outputLines[3], "default3", "foo3"))
+
+	eventingRecorder.Validate()
+}
diff --git a/pkg/kn/commands/flags/sink_test.go b/pkg/kn/commands/flags/sink_test.go
index f3b72147..aa8d09ab 100644
--- a/pkg/kn/commands/flags/sink_test.go
+++ b/pkg/kn/commands/flags/sink_test.go
@@ -40,7 +40,7 @@ func TestResolve(t *testing.T) {
 		ObjectMeta: metav1.ObjectMeta{Name: "mysvc", Namespace: "default"},
 	}
 	defaultBroker := &eventingv1beta1.Broker{
-		TypeMeta:   metav1.TypeMeta{Kind: "Broker", APIVersion: "eventing.knative.dev/v1alpha1"},
+		TypeMeta:   metav1.TypeMeta{Kind: "Broker", APIVersion: "eventing.knative.dev/v1beta1"},
 		ObjectMeta: metav1.ObjectMeta{Name: "default", Namespace: "default"},
 	}
 
@@ -59,7 +59,7 @@ func TestResolve(t *testing.T) {
 		{"svc:absent", nil, "\"absent\" not found"},
 		{"broker:default", &duckv1.Destination{
 			Ref: &duckv1.KReference{Kind: "Broker",
-				APIVersion: "eventing.knative.dev/v1alpha1",
+				APIVersion: "eventing.knative.dev/v1beta1",
 				Namespace:  "default",
 				Name:       "default"}}, ""},
 		{"http://target.example.com", &duckv1.Destination{
diff --git a/pkg/kn/commands/trigger/describe_test.go b/pkg/kn/commands/trigger/describe_test.go
index 15285592..6e70afea 100644
--- a/pkg/kn/commands/trigger/describe_test.go
+++ b/pkg/kn/commands/trigger/describe_test.go
@@ -23,6 +23,7 @@ import (
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	v1beta1 "knative.dev/eventing/pkg/apis/eventing/v1beta1"
+	"knative.dev/pkg/apis"
 	duckv1 "knative.dev/pkg/apis/duck/v1"
 
 	clientv1beta1 "knative.dev/client/pkg/eventing/v1beta1"
@@ -33,7 +34,7 @@ func TestSimpleDescribe(t *testing.T) {
 	client := clientv1beta1.NewMockKnEventingClient(t, "mynamespace")
 
 	recorder := client.Recorder()
-	recorder.GetTrigger("testtrigger", getTrigger(), nil)
+	recorder.GetTrigger("testtrigger", getTriggerSinkRef(), nil)
 
 	out, err := executeTriggerCommand(client, nil, "describe", "testtrigger")
 	assert.NilError(t, err)
@@ -60,8 +61,27 @@ func TestDescribeError(t *testing.T) {
 
 	recorder.Validate()
 }
+func TestDescribeTriggerWithSinkURI(t *testing.T) {
+	client := clientv1beta1.NewMockKnEventingClient(t, "mynamespace")
+
+	recorder := client.Recorder()
+	recorder.GetTrigger("testtrigger", getTriggerSinkURI(), nil)
+
+	out, err := executeTriggerCommand(client, nil, "describe", "testtrigger")
+	assert.NilError(t, err)
 
-func getTrigger() *v1beta1.Trigger {
+	assert.Assert(t, cmp.Regexp("Name:\\s+testtrigger", out))
+	assert.Assert(t, cmp.Regexp("Namespace:\\s+default", out))
+
+	assert.Assert(t, util.ContainsAll(out, "Broker:", "mybroker"))
+	assert.Assert(t, util.ContainsAll(out, "Filter:", "type", "foo.type.knative", "source", "src.eventing.knative"))
+	assert.Assert(t, util.ContainsAll(out, "Sink:", "URI", "https", "foo"))
+
+	// Validate that all recorded API methods have been called
+	recorder.Validate()
+}
+
+func getTriggerSinkRef() *v1beta1.Trigger {
 	return &v1beta1.Trigger{
 		TypeMeta: v1.TypeMeta{},
 		ObjectMeta: metav1.ObjectMeta{
@@ -87,3 +107,29 @@ func getTrigger() *v1beta1.Trigger {
 		Status: v1beta1.TriggerStatus{},
 	}
 }
+
+func getTriggerSinkURI() *v1beta1.Trigger {
+	return &v1beta1.Trigger{
+		TypeMeta: v1.TypeMeta{},
+		ObjectMeta: metav1.ObjectMeta{
+			Name:      "testtrigger",
+			Namespace: "default",
+		},
+		Spec: v1beta1.TriggerSpec{
+			Broker: "mybroker",
+			Filter: &v1beta1.TriggerFilter{
+				Attributes: v1beta1.TriggerFilterAttributes{
+					"type":   "foo.type.knative",
+					"source": "src.eventing.knative",
+				},
+			},
+			Subscriber: duckv1.Destination{
+				URI: &apis.URL{
+					Scheme: "https",
+					Host:   "foo",
+				},
+			},
+		},
+		Status: v1beta1.TriggerStatus{},
+	}
+}
diff --git a/test/e2e/broker_test.go b/test/e2e/broker_test.go
new file mode 100644
index 00000000..525efb16
--- /dev/null
+++ b/test/e2e/broker_test.go
@@ -0,0 +1,104 @@
+// Copyright 2020 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.
+
+// +build e2e
+// +build !serving
+
+package e2e
+
+import (
+	"testing"
+
+	"gotest.tools/assert"
+
+	"knative.dev/client/lib/test"
+	"knative.dev/client/pkg/util"
+)
+
+func TestBroker(t *testing.T) {
+	t.Parallel()
+	it, err := test.NewKnTest()
+	assert.NilError(t, err)
+	defer func() {
+		assert.NilError(t, it.Teardown())
+	}()
+
+	r := test.NewKnRunResultCollector(t, it)
+	defer r.DumpIfFailed()
+
+	t.Log("create broker, list and describe it")
+	brokerCreate(r, "foo1")
+	verifyBrokerList(r, "foo1")
+	verifyBrokerListOutputName(r, "foo1")
+	verifyBrokerDescribe(r, "foo1")
+	brokerDelete(r, "foo1", false)
+
+	t.Log("create broker and delete it")
+	brokerCreate(r, "foo2")
+	verifyBrokerList(r, "foo2")
+	brokerDelete(r, "foo2", true)
+	verifyBrokerNotfound(r, "foo2")
+
+	t.Log("create multiple brokers and list them")
+	brokerCreate(r, "foo3")
+	brokerCreate(r, "foo4")
+	verifyBrokerList(r, "foo3", "foo4")
+	verifyBrokerListOutputName(r, "foo3", "foo4")
+	brokerDelete(r, "foo3", true)
+	brokerDelete(r, "foo4", true)
+	verifyBrokerNotfound(r, "foo3")
+	verifyBrokerNotfound(r, "foo4")
+}
+
+// Private functions
+
+func brokerCreate(r *test.KnRunResultCollector, name string) {
+	out := r.KnTest().Kn().Run("broker", "create", name)
+	r.AssertNoError(out)
+	assert.Check(r.T(), util.ContainsAllIgnoreCase(out.Stdout, "Broker", name, "created", "namespace", r.KnTest().Kn().Namespace()))
+}
+
+func brokerDelete(r *test.KnRunResultCollector, name string, wait bool) {
+	args := []string{"broker", "delete", name}
+	if wait {
+		args = append(args, "--wait")
+	}
+	out := r.KnTest().Kn().Run(args...)
+	r.AssertNoError(out)
+	assert.Check(r.T(), util.ContainsAllIgnoreCase(out.Stdout, "Broker", name, "deleted", "namespace", r.KnTest().Kn().Namespace()))
+}
+
+func verifyBrokerList(r *test.KnRunResultCollector, brokers ...string) {
+	out := r.KnTest().Kn().Run("broker", "list")
+	r.AssertNoError(out)
+	assert.Check(r.T(), util.ContainsAllIgnoreCase(out.Stdout, brokers...))
+}
+
+func verifyBrokerListOutputName(r *test.KnRunResultCollector, broker ...string) {
+	out := r.KnTest().Kn().Run("broker", "list", "--output", "name")
+	r.AssertNoError(out)
+	assert.Check(r.T(), util.ContainsAllIgnoreCase(out.Stdout, broker...))
+}
+
+func verifyBrokerDescribe(r *test.KnRunResultCollector, name string) {
+	out := r.KnTest().Kn().Run("broker", "describe", name)
+	r.AssertNoError(out)
+	assert.Check(r.T(), util.ContainsAllIgnoreCase(out.Stdout, name, "Address:", "URL:", "Conditions:"))
+}
+
+func verifyBrokerNotfound(r *test.KnRunResultCollector, name string) {
+	out := r.KnTest().Kn().Run("broker", "describe", name)
+	r.AssertError(out)
+	assert.Check(r.T(), util.ContainsAll(out.Stderr, name, "not found"))
+}
diff --git a/test/e2e/sink_test.go b/test/e2e/sink_test.go
new file mode 100644
index 00000000..82b0227a
--- /dev/null
+++ b/test/e2e/sink_test.go
@@ -0,0 +1,54 @@
+// Copyright 2020 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 im
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// +build e2e
+// +build !serving
+
+package e2e
+
+import (
+	"testing"
+
+	"gotest.tools/assert"
+
+	"knative.dev/client/lib/test"
+)
+
+func TestSink(t *testing.T) {
+	t.Parallel()
+	it, err := test.NewKnTest()
+	assert.NilError(t, err)
+	defer func() {
+		assert.NilError(t, it.Teardown())
+	}()
+
+	r := test.NewKnRunResultCollector(t, it)
+	defer r.DumpIfFailed()
+
+	// create broker
+	err = test.LabelNamespaceForDefaultBroker(r)
+	assert.NilError(t, err)
+	defer test.UnlabelNamespaceForDefaultBroker(r)
+
+	t.Log("Create Ping source with a sink to the default broker")
+	pingSourceCreate(r, "testpingsource0", "* * * * */1", "ping", "broker:default")
+
+	jpSinkRefNameInSpec := "jsonpath={.spec.sink.ref.name}"
+	out, err := test.GetResourceFieldsWithJSONPath(t, it, "pingsource", "testpingsource0", jpSinkRefNameInSpec)
+	assert.NilError(t, err)
+	assert.Equal(t, out, "default")
+
+	t.Log("delete Ping sources")
+	pingSourceDelete(r, "testpingsource0")
+}
diff --git a/test/e2e/trigger_test.go b/test/e2e/trigger_test.go
index 34757136..fde09f1b 100644
--- a/test/e2e/trigger_test.go
+++ b/test/e2e/trigger_test.go
@@ -18,12 +18,9 @@
 package e2e
 
 import (
-	"strings"
 	"testing"
-	"time"
 
 	"gotest.tools/assert"
-	"k8s.io/apimachinery/pkg/util/wait"
 
 	"knative.dev/client/lib/test"
 	"knative.dev/client/pkg/util"
@@ -40,9 +37,9 @@ func TestBrokerTrigger(t *testing.T) {
 	r := test.NewKnRunResultCollector(t, it)
 	defer r.DumpIfFailed()
 
-	err = lableNamespaceForDefaultBroker(t, it)
+	err = test.LabelNamespaceForDefaultBroker(r)
 	assert.NilError(t, err)
-	defer unlableNamespaceForDefaultBroker(t, it)
+	defer test.UnlabelNamespaceForDefaultBroker(r)
 
 	test.ServiceCreate(r, "sinksvc0")
 	test.ServiceCreate(r, "sinksvc1")
@@ -82,30 +79,6 @@ func TestBrokerTrigger(t *testing.T) {
 
 // Private functions
 
-func unlableNamespaceForDefaultBroker(t *testing.T, it *test.KnTest) {
-	_, err := test.Kubectl{}.Run("label", "namespace", it.Kn().Namespace(), "knative-eventing-injection-")
-	if err != nil {
-		t.Fatalf("Error executing 'kubectl label namespace %s knative-eventing-injection-'. Error: %s", it.Kn().Namespace(), err.Error())
-	}
-}
-
-func lableNamespaceForDefaultBroker(t *testing.T, it *test.KnTest) error {
-	_, err := test.Kubectl{}.Run("label", "namespace", it.Kn().Namespace(), "knative-eventing-injection=enabled")
-
-	if err != nil {
-		t.Fatalf("Error executing 'kubectl label namespace %s knative-eventing-injection=enabled'. Error: %s", it.Kn().Namespace(), err.Error())
-	}
-
-	return wait.PollImmediate(10*time.Second, 5*time.Minute, func() (bool, error) {
-		out, err := test.NewKubectl(it.Kn().Namespace()).Run("get", "broker", "-o=jsonpath='{.items[0].status.conditions[?(@.type==\"Ready\")].status}'")
-		if err != nil {
-			return false, nil
-		} else {
-			return strings.Contains(out, "True"), nil
-		}
-	})
-}
-
 func triggerCreate(r *test.KnRunResultCollector, name string, sinksvc string, filters []string) {
 	args := []string{"trigger", "create", name, "--broker", "default", "--sink", "svc:" + sinksvc}
 	if len(filters) > 0 {