Repository: knative/client
Pull request #559 (2019-12-17 09:16:10)

Add cronjob and apiserver source list commands
/lint

## Proposed Changes
- [x] - Add kn source cronjob list
- [x] - Tests for kn source cronjob list
- [x] - Add kn source apiserver list
- [x] - Tests for kn source apiserver list

```
kn source cronjob list
NAME              SCHEDULE      SINK        CONDITIONS   READY   REASON
my-cron-trigger   * * * * */1   svc:mysvc   6 OK / 6     True    
```

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

This pull-request has been approved by: *<a href="https://github.com/knative/client/pull/559#" title="Author self-approved">navidshaikh</a>*

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

The pull request process is described [here](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process)

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

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

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":[]} -->
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/sources/v1alpha1/cronjob_client.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_client/559/pull-knative-client-go-coverage/1206865729068994562/artifacts/line-cov.html#file0) | 100.0% | 95.0% | -5.0
[pkg/eventing/sources/v1alpha1/cronjob_client_mock.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_client/559/pull-knative-client-go-coverage/1206865729068994562/artifacts/line-cov.html#file1) | 89.5% | 77.3% | -12.2
[pkg/kn/commands/source/cronjob/cronjob.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_client/559/pull-knative-client-go-coverage/1206865729068994562/artifacts/line-cov.html#file2) | 57.1% | 59.1% | 1.9
[pkg/kn/commands/source/cronjob/flags.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_client/559/pull-knative-client-go-coverage/1206865729068994562/artifacts/line-cov.html#file3) | 100.0% | 12.5% | -87.5
[pkg/kn/commands/source/cronjob/list.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_client/559/pull-knative-client-go-coverage/1206865729068994562/artifacts/line-cov.html#file4) | Do not exist | 23.8% | 

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

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-knative-client-go-coverage | f1e54eae8e4cd64f1b665b180503aff1a6f11a51 | [link](https://prow.knative.dev/view/gcs/knative-prow/pr-logs/pull/knative_client/559/pull-knative-client-go-coverage/1206865729068994562) | `/test pull-knative-client-go-coverage`

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

<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/sources/v1alpha1/apiserver_client.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_client/559/pull-knative-client-go-coverage/1206965138289070082/artifacts/line-cov.html#file0) | 100.0% | 93.0% | -7.0
[pkg/eventing/sources/v1alpha1/apiserver_client_mock.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_client/559/pull-knative-client-go-coverage/1206965138289070082/artifacts/line-cov.html#file1) | 89.5% | 77.3% | -12.2
[pkg/eventing/sources/v1alpha1/cronjob_client.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_client/559/pull-knative-client-go-coverage/1206965138289070082/artifacts/line-cov.html#file2) | 100.0% | 91.7% | -8.3
[pkg/eventing/sources/v1alpha1/cronjob_client_mock.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_client/559/pull-knative-client-go-coverage/1206965138289070082/artifacts/line-cov.html#file3) | 89.5% | 77.3% | -12.2
[pkg/kn/commands/source/apiserver/apiserver.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_client/559/pull-knative-client-go-coverage/1206965138289070082/artifacts/line-cov.html#file4) | 57.1% | 59.1% | 1.9
[pkg/kn/commands/source/apiserver/flags.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_client/559/pull-knative-client-go-coverage/1206965138289070082/artifacts/line-cov.html#file5) | 95.2% | 68.1% | -27.1
[pkg/kn/commands/source/apiserver/list.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_client/559/pull-knative-client-go-coverage/1206965138289070082/artifacts/line-cov.html#file6) | Do not exist | 78.3% | 
[pkg/kn/commands/source/cronjob/cronjob.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_client/559/pull-knative-client-go-coverage/1206965138289070082/artifacts/line-cov.html#file7) | 57.1% | 59.1% | 1.9
[pkg/kn/commands/source/cronjob/flags.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_client/559/pull-knative-client-go-coverage/1206965138289070082/artifacts/line-cov.html#file8) | 100.0% | 56.2% | -43.8
[pkg/kn/commands/source/cronjob/list.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_client/559/pull-knative-client-go-coverage/1206965138289070082/artifacts/line-cov.html#file9) | Do not exist | 78.3% | 

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

This pull-request has been approved by: *<a href="https://github.com/knative/client/pull/559#" title="Author self-approved">navidshaikh</a>*, *<a href="https://github.com/knative/client/pull/559#pullrequestreview-333408463" title="LGTM">rhuss</a>*

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

The pull request process is described [here](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process)

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

- ~~[OWNERS](https://github.com/knative/client/blob/master/OWNERS)~~ [navidshaikh,rhuss]

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":[]} -->

Patch:
diff --git a/docs/cmd/kn_source_apiserver.md b/docs/cmd/kn_source_apiserver.md
index 29c9fba7..34a65d24 100644
--- a/docs/cmd/kn_source_apiserver.md
+++ b/docs/cmd/kn_source_apiserver.md
@@ -30,5 +30,6 @@ kn source apiserver [flags]
 * [kn source apiserver create](kn_source_apiserver_create.md)	 - Create an ApiServer source.
 * [kn source apiserver delete](kn_source_apiserver_delete.md)	 - Delete an ApiServer source.
 * [kn source apiserver describe](kn_source_apiserver_describe.md)	 - Describe an ApiServer source.
+* [kn source apiserver list](kn_source_apiserver_list.md)	 - List ApiServer sources.
 * [kn source apiserver update](kn_source_apiserver_update.md)	 - Update an ApiServer source.
 
diff --git a/docs/cmd/kn_source_apiserver_create.md b/docs/cmd/kn_source_apiserver_create.md
index ec3efddf..d142ef5a 100644
--- a/docs/cmd/kn_source_apiserver_create.md
+++ b/docs/cmd/kn_source_apiserver_create.md
@@ -22,8 +22,8 @@ kn source apiserver create NAME --resource RESOURCE --service-account ACCOUNTNAM
 
 ```
   -h, --help                     help for create
-      --mode string              The mode the receive adapter controller runs under:, 
-                                 "Ref" sends only the reference to the resource, 
+      --mode string              The mode the receive adapter controller runs under:,
+                                 "Ref" sends only the reference to the resource,
                                  "Resource" send the full resource. (default "Ref")
   -n, --namespace string         Specify the namespace to operate in.
       --resource strings         Comma seperate Kind:APIVersion:isController list, e.g. Event:v1:true.
diff --git a/docs/cmd/kn_source_apiserver_list.md b/docs/cmd/kn_source_apiserver_list.md
new file mode 100644
index 00000000..e90bd299
--- /dev/null
+++ b/docs/cmd/kn_source_apiserver_list.md
@@ -0,0 +1,44 @@
+## kn source apiserver list
+
+List ApiServer sources.
+
+### Synopsis
+
+List ApiServer sources.
+
+```
+kn source apiserver list [flags]
+```
+
+### Examples
+
+```
+
+  # List all ApiServer sources in YAML format
+  kn source apiserver list -o yaml
+```
+
+### 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 config file (default is $HOME/.kn/config.yaml)
+      --kubeconfig string   kubectl config file (default is $HOME/.kube/config)
+      --log-http            log http traffic
+```
+
+### SEE ALSO
+
+* [kn source apiserver](kn_source_apiserver.md)	 - Kubernetes API Server Event Source command group
+
diff --git a/docs/cmd/kn_source_apiserver_update.md b/docs/cmd/kn_source_apiserver_update.md
index 8b7747a3..168f86f2 100644
--- a/docs/cmd/kn_source_apiserver_update.md
+++ b/docs/cmd/kn_source_apiserver_update.md
@@ -22,8 +22,8 @@ kn source apiserver update NAME --resource RESOURCE --service-account ACCOUNTNAM
 
 ```
   -h, --help                     help for update
-      --mode string              The mode the receive adapter controller runs under:, 
-                                 "Ref" sends only the reference to the resource, 
+      --mode string              The mode the receive adapter controller runs under:,
+                                 "Ref" sends only the reference to the resource,
                                  "Resource" send the full resource. (default "Ref")
   -n, --namespace string         Specify the namespace to operate in.
       --resource strings         Comma seperate Kind:APIVersion:isController list, e.g. Event:v1:true.
diff --git a/docs/cmd/kn_source_cronjob.md b/docs/cmd/kn_source_cronjob.md
index db6d84f8..28d297f1 100644
--- a/docs/cmd/kn_source_cronjob.md
+++ b/docs/cmd/kn_source_cronjob.md
@@ -30,5 +30,6 @@ kn source cronjob [flags]
 * [kn source cronjob create](kn_source_cronjob_create.md)	 - Create a CronJob source.
 * [kn source cronjob delete](kn_source_cronjob_delete.md)	 - Delete a CronJob source.
 * [kn source cronjob describe](kn_source_cronjob_describe.md)	 - Describe a CronJob source.
+* [kn source cronjob list](kn_source_cronjob_list.md)	 - List CronJob sources.
 * [kn source cronjob update](kn_source_cronjob_update.md)	 - Update a CronJob source.
 
diff --git a/docs/cmd/kn_source_cronjob_list.md b/docs/cmd/kn_source_cronjob_list.md
new file mode 100644
index 00000000..a0fe1ab6
--- /dev/null
+++ b/docs/cmd/kn_source_cronjob_list.md
@@ -0,0 +1,44 @@
+## kn source cronjob list
+
+List CronJob sources.
+
+### Synopsis
+
+List CronJob sources.
+
+```
+kn source cronjob list [flags]
+```
+
+### Examples
+
+```
+
+  # List all CronJob sources in YAML format
+  kn source cronjob list -o yaml
+```
+
+### 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 config file (default is $HOME/.kn/config.yaml)
+      --kubeconfig string   kubectl config file (default is $HOME/.kube/config)
+      --log-http            log http traffic
+```
+
+### SEE ALSO
+
+* [kn source cronjob](kn_source_cronjob.md)	 - CronJob source command group
+
diff --git a/pkg/eventing/sources/v1alpha1/apiserver_client.go b/pkg/eventing/sources/v1alpha1/apiserver_client.go
index 0551690a..3a29ffd2 100644
--- a/pkg/eventing/sources/v1alpha1/apiserver_client.go
+++ b/pkg/eventing/sources/v1alpha1/apiserver_client.go
@@ -37,6 +37,10 @@ type KnAPIServerSourcesClient interface {
 	// Delete an ApiServerSource by name
 	DeleteAPIServerSource(name string) error
 
+	// List ApiServerSource
+	// TODO: Support list configs like in service list
+	ListAPIServerSource() (*v1alpha1.ApiServerSourceList, error)
+
 	// Get namespace for this client
 	Namespace() string
 }
@@ -98,6 +102,35 @@ func (c *apiServerSourcesClient) Namespace() string {
 	return c.namespace
 }
 
+// ListAPIServerSource returns the available ApiServer type sources
+func (c *apiServerSourcesClient) ListAPIServerSource() (*v1alpha1.ApiServerSourceList, error) {
+	sourceList, err := c.client.List(metav1.ListOptions{})
+	if err != nil {
+		return nil, err
+	}
+
+	return updateAPIServerSourceListGVK(sourceList)
+}
+
+func updateAPIServerSourceListGVK(sourceList *v1alpha1.ApiServerSourceList) (*v1alpha1.ApiServerSourceList, error) {
+	sourceListNew := sourceList.DeepCopy()
+	err := updateSourceGVK(sourceListNew)
+	if err != nil {
+		return nil, err
+	}
+
+	sourceListNew.Items = make([]v1alpha1.ApiServerSource, len(sourceList.Items))
+	for idx, source := range sourceList.Items {
+		sourceClone := source.DeepCopy()
+		err := updateSourceGVK(sourceClone)
+		if err != nil {
+			return nil, err
+		}
+		sourceListNew.Items[idx] = *sourceClone
+	}
+	return sourceListNew, nil
+}
+
 // APIServerSourceBuilder is for building the source
 type APIServerSourceBuilder struct {
 	apiServerSource *v1alpha1.ApiServerSource
diff --git a/pkg/eventing/sources/v1alpha1/apiserver_client_mock.go b/pkg/eventing/sources/v1alpha1/apiserver_client_mock.go
index 4ef573e0..21f02131 100644
--- a/pkg/eventing/sources/v1alpha1/apiserver_client_mock.go
+++ b/pkg/eventing/sources/v1alpha1/apiserver_client_mock.go
@@ -103,6 +103,17 @@ func (c *MockKnAPIServerSourceClient) DeleteAPIServerSource(name string) error {
 	return mock.ErrorOrNil(call.Result[0])
 }
 
+// ListAPIServerSource records a call for ListAPIServerSource with the expected error (nil if none)
+func (sr *APIServerSourcesRecorder) ListAPIServerSource(apiJobSourceList *v1alpha1.ApiServerSourceList, err error) {
+	sr.r.Add("ListAPIServerSource", []interface{}{}, []interface{}{apiJobSourceList, err})
+}
+
+// ListAPIServerSource performs a previously recorded action, failing if non has been registered
+func (c *MockKnAPIServerSourceClient) ListAPIServerSource() (*v1alpha1.ApiServerSourceList, error) {
+	call := c.recorder.r.VerifyCall("ListAPIServerSource")
+	return call.Result[0].(*v1alpha1.ApiServerSourceList), mock.ErrorOrNil(call.Result[1])
+}
+
 // Validate validates whether every recorded action has been called
 func (sr *APIServerSourcesRecorder) Validate() {
 	sr.r.CheckThatAllRecordedMethodsHaveBeenCalled()
diff --git a/pkg/eventing/sources/v1alpha1/cronjob_client.go b/pkg/eventing/sources/v1alpha1/cronjob_client.go
index ad32d448..a37aad4d 100644
--- a/pkg/eventing/sources/v1alpha1/cronjob_client.go
+++ b/pkg/eventing/sources/v1alpha1/cronjob_client.go
@@ -17,8 +17,12 @@ package v1alpha1
 import (
 	"fmt"
 
-	meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/runtime"
 	"knative.dev/eventing/pkg/apis/sources/v1alpha1"
+
+	"knative.dev/client/pkg/util"
+	"knative.dev/eventing/pkg/client/clientset/versioned/scheme"
 	client_v1alpha1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/sources/v1alpha1"
 	duckv1beta1 "knative.dev/pkg/apis/duck/v1beta1"
 )
@@ -38,6 +42,10 @@ type KnCronJobSourcesClient interface {
 	// Delete a cronjob source by name
 	DeleteCronJobSource(name string) error
 
+	// List CronJob sources
+	// TODO: Support list configs like in service list
+	ListCronJobSource() (*v1alpha1.CronJobSourceList, error)
+
 	// Get namespace for this source
 	Namespace() string
 }
@@ -77,11 +85,44 @@ func (c *cronJobSourcesClient) UpdateCronJobSource(cronjobSource *v1alpha1.CronJ
 }
 
 func (c *cronJobSourcesClient) DeleteCronJobSource(name string) error {
-	return c.client.Delete(name, &meta_v1.DeleteOptions{})
+	return c.client.Delete(name, &metav1.DeleteOptions{})
 }
 
 func (c *cronJobSourcesClient) GetCronJobSource(name string) (*v1alpha1.CronJobSource, error) {
-	return c.client.Get(name, meta_v1.GetOptions{})
+	return c.client.Get(name, metav1.GetOptions{})
+}
+
+// ListCronJobSource returns the available CronJob type sources
+func (c *cronJobSourcesClient) ListCronJobSource() (*v1alpha1.CronJobSourceList, error) {
+	sourceList, err := c.client.List(metav1.ListOptions{})
+	if err != nil {
+		return nil, err
+	}
+
+	return updateCronJobSourceListGVK(sourceList)
+}
+
+func updateCronJobSourceListGVK(sourceList *v1alpha1.CronJobSourceList) (*v1alpha1.CronJobSourceList, error) {
+	sourceListNew := sourceList.DeepCopy()
+	err := updateSourceGVK(sourceListNew)
+	if err != nil {
+		return nil, err
+	}
+
+	sourceListNew.Items = make([]v1alpha1.CronJobSource, len(sourceList.Items))
+	for idx, source := range sourceList.Items {
+		sourceClone := source.DeepCopy()
+		err := updateSourceGVK(sourceClone)
+		if err != nil {
+			return nil, err
+		}
+		sourceListNew.Items[idx] = *sourceClone
+	}
+	return sourceListNew, nil
+}
+
+func updateSourceGVK(obj runtime.Object) error {
+	return util.UpdateGroupVersionKindWithScheme(obj, v1alpha1.SchemeGroupVersion, scheme.Scheme)
 }
 
 // Builder for building up cronjob sources
@@ -92,7 +133,7 @@ type CronJobSourceBuilder struct {
 
 func NewCronJobSourceBuilder(name string) *CronJobSourceBuilder {
 	return &CronJobSourceBuilder{cronjobSource: &v1alpha1.CronJobSource{
-		ObjectMeta: meta_v1.ObjectMeta{
+		ObjectMeta: metav1.ObjectMeta{
 			Name: name,
 		},
 	}}
diff --git a/pkg/eventing/sources/v1alpha1/cronjob_client_mock.go b/pkg/eventing/sources/v1alpha1/cronjob_client_mock.go
index 94610456..74df71ad 100644
--- a/pkg/eventing/sources/v1alpha1/cronjob_client_mock.go
+++ b/pkg/eventing/sources/v1alpha1/cronjob_client_mock.go
@@ -102,6 +102,17 @@ func (c *MockKnCronJobSourceClient) DeleteCronJobSource(name string) error {
 	return mock.ErrorOrNil(call.Result[0])
 }
 
+// ListCronJobSource records a call for ListCronJobSource with the expected error (nil if none)
+func (sr *CronJobSourcesRecorder) ListCronJobSource(cronJobSourceList *v1alpha1.CronJobSourceList, err error) {
+	sr.r.Add("ListCronJobSource", []interface{}{}, []interface{}{cronJobSourceList, err})
+}
+
+// ListCronJobSource performs a previously recorded action, failing if non has been registered
+func (c *MockKnCronJobSourceClient) ListCronJobSource() (*v1alpha1.CronJobSourceList, error) {
+	call := c.recorder.r.VerifyCall("ListCronJobSource")
+	return call.Result[0].(*v1alpha1.CronJobSourceList), mock.ErrorOrNil(call.Result[1])
+}
+
 // Validates validates whether every recorded action has been called
 func (sr *CronJobSourcesRecorder) Validate() {
 	sr.r.CheckThatAllRecordedMethodsHaveBeenCalled()
diff --git a/pkg/kn/commands/source/apiserver/apiserver.go b/pkg/kn/commands/source/apiserver/apiserver.go
index 54b9f931..b1a10ee3 100644
--- a/pkg/kn/commands/source/apiserver/apiserver.go
+++ b/pkg/kn/commands/source/apiserver/apiserver.go
@@ -34,6 +34,7 @@ func NewAPIServerCommand(p *commands.KnParams) *cobra.Command {
 	apiServerSourceCmd.AddCommand(NewAPIServerUpdateCommand(p))
 	apiServerSourceCmd.AddCommand(NewAPIServerDescribeCommand(p))
 	apiServerSourceCmd.AddCommand(NewAPIServerDeleteCommand(p))
+	apiServerSourceCmd.AddCommand(NewAPIServerListCommand(p))
 	return apiServerSourceCmd
 }
 
diff --git a/pkg/kn/commands/source/apiserver/flags.go b/pkg/kn/commands/source/apiserver/flags.go
index 4617c2ce..cbc95fc1 100644
--- a/pkg/kn/commands/source/apiserver/flags.go
+++ b/pkg/kn/commands/source/apiserver/flags.go
@@ -15,11 +15,18 @@
 package apiserver
 
 import (
+	"fmt"
+	"sort"
 	"strconv"
 	"strings"
 
 	"github.com/spf13/cobra"
+	"k8s.io/apimachinery/pkg/runtime"
+	"knative.dev/client/pkg/kn/commands"
 	"knative.dev/eventing/pkg/apis/sources/v1alpha1"
+
+	metav1beta1 "k8s.io/apimachinery/pkg/apis/meta/v1beta1"
+	hprinters "knative.dev/client/pkg/printers"
 )
 
 const (
@@ -77,8 +84,8 @@ func (f *APIServerSourceUpdateFlags) Add(cmd *cobra.Command) {
 	cmd.Flags().StringVar(&f.Mode,
 		"mode",
 		"Ref",
-		`The mode the receive adapter controller runs under:, 
-"Ref" sends only the reference to the resource, 
+		`The mode the receive adapter controller runs under:,
+"Ref" sends only the reference to the resource,
 "Resource" send the full resource.`)
 	cmd.Flags().StringSliceVar(&f.Resources,
 		"resource",
@@ -87,3 +94,108 @@ func (f *APIServerSourceUpdateFlags) Add(cmd *cobra.Command) {
 "APIVersion" and "isControler" can be omitted.
 "APIVersion" is "v1" by default, "isController" is "false" by default.`)
 }
+
+// APIServerSourceListHandlers handles printing human readable table for `kn source apiserver list` command's output
+func APIServerSourceListHandlers(h hprinters.PrintHandler) {
+	sourceColumnDefinitions := []metav1beta1.TableColumnDefinition{
+		{Name: "Namespace", Type: "string", Description: "Namespace of the ApiServer source", Priority: 0},
+		{Name: "Name", Type: "string", Description: "Name of the ApiServer source", Priority: 1},
+		{Name: "Resources", Type: "string", Description: "Event resources configured for the ApiServer source", Priority: 1},
+		{Name: "Sink", Type: "string", Description: "Sink of the ApiServer source", Priority: 1},
+		{Name: "Conditions", Type: "string", Description: "Ready state conditions", Priority: 1},
+		{Name: "Ready", Type: "string", Description: "Ready state of the ApiServer source", Priority: 1},
+		{Name: "Reason", Type: "string", Description: "Reason if state is not Ready", Priority: 1},
+	}
+	h.TableHandler(sourceColumnDefinitions, printSource)
+	h.TableHandler(sourceColumnDefinitions, printSourceList)
+}
+
+// printSource populates a single row of source apiserver list table
+func printSource(source *v1alpha1.ApiServerSource, options hprinters.PrintOptions) ([]metav1beta1.TableRow, error) {
+	row := metav1beta1.TableRow{
+		Object: runtime.RawExtension{Object: source},
+	}
+
+	name := source.Name
+	conditions := commands.ConditionsValue(source.Status.Conditions)
+	ready := commands.ReadyCondition(source.Status.Conditions)
+	reason := strings.TrimSpace(commands.NonReadyConditionReason(source.Status.Conditions))
+	var resources []string
+	for _, resource := range source.Spec.Resources {
+		resources = append(resources, fmt.Sprintf("%s:%s:%s", resource.Kind, resource.APIVersion, strconv.FormatBool(resource.Controller)))
+	}
+
+	var sink string
+	if source.Spec.Sink != nil {
+		if source.Spec.Sink.Ref != nil {
+			if source.Spec.Sink.Ref.Kind == "Service" {
+				sink = fmt.Sprintf("svc:%s", source.Spec.Sink.Ref.Name)
+			} else {
+				sink = fmt.Sprintf("%s:%s", source.Spec.Sink.Ref.Kind, source.Spec.Sink.Ref.Name)
+			}
+		}
+	}
+
+	if options.AllNamespaces {
+		row.Cells = append(row.Cells, source.Namespace)
+	}
+
+	row.Cells = append(row.Cells, name, strings.Join(resources[:], ","), sink, conditions, ready, reason)
+	return []metav1beta1.TableRow{row}, nil
+}
+
+// printSourceList populates the source apiserver list table rows
+func printSourceList(sourceList *v1alpha1.ApiServerSourceList, options hprinters.PrintOptions) ([]metav1beta1.TableRow, error) {
+	if options.AllNamespaces {
+		return printSourceListWithNamespace(sourceList, options)
+	}
+
+	rows := make([]metav1beta1.TableRow, 0, len(sourceList.Items))
+
+	sort.SliceStable(sourceList.Items, func(i, j int) bool {
+		return sourceList.Items[i].GetName() < sourceList.Items[j].GetName()
+	})
+
+	for _, item := range sourceList.Items {
+		row, err := printSource(&item, options)
+		if err != nil {
+			return nil, err
+		}
+
+		rows = append(rows, row...)
+	}
+	return rows, nil
+}
+
+// printSourceListWithNamespace populates the knative service table rows with namespace column
+func printSourceListWithNamespace(sourceList *v1alpha1.ApiServerSourceList, options hprinters.PrintOptions) ([]metav1beta1.TableRow, error) {
+	rows := make([]metav1beta1.TableRow, 0, len(sourceList.Items))
+
+	// temporary slice for sorting services in non-default namespace
+	others := []metav1beta1.TableRow{}
+
+	for _, source := range sourceList.Items {
+		// Fill in with services in `default` namespace at first
+		if source.Namespace == "default" {
+			r, err := printSource(&source, options)
+			if err != nil {
+				return nil, err
+			}
+			rows = append(rows, r...)
+			continue
+		}
+		// put other services in temporary slice
+		r, err := printSource(&source, options)
+		if err != nil {
+			return nil, err
+		}
+		others = append(others, r...)
+	}
+
+	// sort other services list alphabetically by namespace
+	sort.SliceStable(others, func(i, j int) bool {
+		return others[i].Cells[0].(string) < others[j].Cells[0].(string)
+	})
+
+	return append(rows, others...), nil
+}
diff --git a/pkg/kn/commands/source/apiserver/list.go b/pkg/kn/commands/source/apiserver/list.go
new file mode 100644
index 00000000..5bdc81c5
--- /dev/null
+++ b/pkg/kn/commands/source/apiserver/list.go
@@ -0,0 +1,74 @@
+// 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 apiserver
+
+import (
+	"fmt"
+
+	"github.com/spf13/cobra"
+	"knative.dev/client/pkg/kn/commands"
+	"knative.dev/client/pkg/kn/commands/flags"
+)
+
+// NewAPIServerListCommand is for listing ApiServer source COs
+func NewAPIServerListCommand(p *commands.KnParams) *cobra.Command {
+	listFlags := flags.NewListFlags(APIServerSourceListHandlers)
+
+	listCommand := &cobra.Command{
+		Use:   "list",
+		Short: "List ApiServer sources.",
+		Example: `
+  # List all ApiServer sources in YAML format
+  kn source apiserver list -o yaml`,
+
+		RunE: func(cmd *cobra.Command, args []string) (err error) {
+			// TODO: filter list by given source name
+
+			apiSourceClient, err := newAPIServerSourceClient(p, cmd)
+			if err != nil {
+				return err
+			}
+
+			sourceList, err := apiSourceClient.ListAPIServerSource()
+			if err != nil {
+				return err
+			}
+
+			if len(sourceList.Items) == 0 {
+				fmt.Fprintf(cmd.OutOrStdout(), "No ApiServer source found.\n")
+				return nil
+			}
+
+			if apiSourceClient.Namespace() == "" {
+				listFlags.EnsureWithNamespace()
+			}
+
+			printer, err := listFlags.ToPrinter()
+			if err != nil {
+				return nil
+			}
+
+			err = printer.PrintObj(sourceList, cmd.OutOrStdout())
+			if err != nil {
+				return err
+			}
+
+			return nil
+		},
+	}
+	commands.AddNamespaceFlags(listCommand.Flags(), true)
+	listFlags.AddFlags(listCommand)
+	return listCommand
+}
diff --git a/pkg/kn/commands/source/cronjob/cronjob.go b/pkg/kn/commands/source/cronjob/cronjob.go
index 530935fe..0805557c 100644
--- a/pkg/kn/commands/source/cronjob/cronjob.go
+++ b/pkg/kn/commands/source/cronjob/cronjob.go
@@ -33,6 +33,7 @@ func NewCronJobCommand(p *commands.KnParams) *cobra.Command {
 	cronImporterCmd.AddCommand(NewCronJobDeleteCommand(p))
 	cronImporterCmd.AddCommand(NewCronJobDescribeCommand(p))
 	cronImporterCmd.AddCommand(NewCronJobUpdateCommand(p))
+	cronImporterCmd.AddCommand(NewCronJobListCommand(p))
 	return cronImporterCmd
 }
 
diff --git a/pkg/kn/commands/source/cronjob/flags.go b/pkg/kn/commands/source/cronjob/flags.go
index 5ea210a1..0970c1ee 100644
--- a/pkg/kn/commands/source/cronjob/flags.go
+++ b/pkg/kn/commands/source/cronjob/flags.go
@@ -14,7 +14,19 @@
 
 package cronjob
 
-import "github.com/spf13/cobra"
+import (
+	"fmt"
+	"sort"
+
+	"github.com/spf13/cobra"
+	metav1beta1 "k8s.io/apimachinery/pkg/apis/meta/v1beta1"
+	"k8s.io/apimachinery/pkg/runtime"
+
+	"knative.dev/client/pkg/kn/commands"
+	hprinters "knative.dev/client/pkg/printers"
+
+	"knative.dev/eventing/pkg/apis/sources/v1alpha1"
+)
 
 type cronJobUpdateFlags struct {
 	schedule string
@@ -25,3 +37,105 @@ func (c *cronJobUpdateFlags) addCronJobFlags(cmd *cobra.Command) {
 	cmd.Flags().StringVar(&c.schedule, "schedule", "", "Schedule specification in crontab format (e.g. '* * * * */2' for every two minutes")
 	cmd.Flags().StringVarP(&c.data, "data", "d", "", "String data to send")
 }
+
+// CronJobListHandlers handles printing human readable table for `kn source cronjob list` command's output
+func CronJobSourceListHandlers(h hprinters.PrintHandler) {
+	sourceColumnDefinitions := []metav1beta1.TableColumnDefinition{
+		{Name: "Namespace", Type: "string", Description: "Namespace of the CronJob source", Priority: 0},
+		{Name: "Name", Type: "string", Description: "Name of the CronJob source", Priority: 1},
+		{Name: "Schedule", Type: "string", Description: "Schedule of the CronJob source", Priority: 1},
+		{Name: "Sink", Type: "string", Description: "Sink of the CronJob source", Priority: 1},
+		{Name: "Conditions", Type: "string", Description: "Ready state conditions", Priority: 1},
+		{Name: "Ready", Type: "string", Description: "Ready state of the CronJob source", Priority: 1},
+		{Name: "Reason", Type: "string", Description: "Reason if state is not Ready", Priority: 1},
+	}
+	h.TableHandler(sourceColumnDefinitions, printSource)
+	h.TableHandler(sourceColumnDefinitions, printSourceList)
+}
+
+// printSource populates a single row of source cronjob list table
+func printSource(source *v1alpha1.CronJobSource, options hprinters.PrintOptions) ([]metav1beta1.TableRow, error) {
+	row := metav1beta1.TableRow{
+		Object: runtime.RawExtension{Object: source},
+	}
+
+	name := source.Name
+	schedule := source.Spec.Schedule
+	conditions := commands.ConditionsValue(source.Status.Conditions)
+	ready := commands.ReadyCondition(source.Status.Conditions)
+	reason := commands.NonReadyConditionReason(source.Status.Conditions)
+
+	var sink string
+	if source.Spec.Sink != nil {
+		if source.Spec.Sink.Ref != nil {
+			if source.Spec.Sink.Ref.Kind == "Service" {
+				sink = fmt.Sprintf("svc:%s", source.Spec.Sink.Ref.Name)
+			} else {
+				sink = fmt.Sprintf("%s:%s", source.Spec.Sink.Ref.Kind, source.Spec.Sink.Ref.Name)
+			}
+		}
+	}
+
+	if options.AllNamespaces {
+		row.Cells = append(row.Cells, source.Namespace)
+	}
+
+	row.Cells = append(row.Cells, name, schedule, sink, conditions, ready, reason)
+	return []metav1beta1.TableRow{row}, nil
+}
+
+// printSourceList populates the source cronjob list table rows
+func printSourceList(sourceList *v1alpha1.CronJobSourceList, options hprinters.PrintOptions) ([]metav1beta1.TableRow, error) {
+	if options.AllNamespaces {
+		return printSourceListWithNamespace(sourceList, options)
+	}
+
+	rows := make([]metav1beta1.TableRow, 0, len(sourceList.Items))
+
+	sort.SliceStable(sourceList.Items, func(i, j int) bool {
+		return sourceList.Items[i].GetName() < sourceList.Items[j].GetName()
+	})
+
+	for _, item := range sourceList.Items {
+		row, err := printSource(&item, options)
+		if err != nil {
+			return nil, err
+		}
+
+		rows = append(rows, row...)
+	}
+	return rows, nil
+}
+
+// printSourceListWithNamespace populates the knative service table rows with namespace column
+func printSourceListWithNamespace(sourceList *v1alpha1.CronJobSourceList, options hprinters.PrintOptions) ([]metav1beta1.TableRow, error) {
+	rows := make([]metav1beta1.TableRow, 0, len(sourceList.Items))
+
+	// temporary slice for sorting services in non-default namespace
+	others := []metav1beta1.TableRow{}
+
+	for _, source := range sourceList.Items {
+		// Fill in with services in `default` namespace at first
+		if source.Namespace == "default" {
+			r, err := printSource(&source, options)
+			if err != nil {
+				return nil, err
+			}
+			rows = append(rows, r...)
+			continue
+		}
+		// put other services in temporary slice
+		r, err := printSource(&source, options)
+		if err != nil {
+			return nil, err
+		}
+		others = append(others, r...)
+	}
+
+	// sort other services list alphabetically by namespace
+	sort.SliceStable(others, func(i, j int) bool {
+		return others[i].Cells[0].(string) < others[j].Cells[0].(string)
+	})
+
+	return append(rows, others...), nil
+}
diff --git a/pkg/kn/commands/source/cronjob/list.go b/pkg/kn/commands/source/cronjob/list.go
new file mode 100644
index 00000000..d6e0f063
--- /dev/null
+++ b/pkg/kn/commands/source/cronjob/list.go
@@ -0,0 +1,74 @@
+// 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 cronjob
+
+import (
+	"fmt"
+
+	"github.com/spf13/cobra"
+	"knative.dev/client/pkg/kn/commands"
+	"knative.dev/client/pkg/kn/commands/flags"
+)
+
+// NewCronJobListCommand is for listing CronJob source COs
+func NewCronJobListCommand(p *commands.KnParams) *cobra.Command {
+	listFlags := flags.NewListFlags(CronJobSourceListHandlers)
+
+	listCommand := &cobra.Command{
+		Use:   "list",
+		Short: "List CronJob sources.",
+		Example: `
+  # List all CronJob sources in YAML format
+  kn source cronjob list -o yaml`,
+
+		RunE: func(cmd *cobra.Command, args []string) (err error) {
+			// TODO: filter list by given source name
+
+			cronSourceClient, err := newCronJobSourceClient(p, cmd)
+			if err != nil {
+				return err
+			}
+
+			sourceList, err := cronSourceClient.ListCronJobSource()
+			if err != nil {
+				return err
+			}
+
+			if len(sourceList.Items) == 0 {
+				fmt.Fprintf(cmd.OutOrStdout(), "No CronJob source found.\n")
+				return nil
+			}
+
+			if cronSourceClient.Namespace() == "" {
+				listFlags.EnsureWithNamespace()
+			}
+
+			printer, err := listFlags.ToPrinter()
+			if err != nil {
+				return nil
+			}
+
+			err = printer.PrintObj(sourceList, cmd.OutOrStdout())
+			if err != nil {
+				return err
+			}
+
+			return nil
+		},
+	}
+	commands.AddNamespaceFlags(listCommand.Flags(), true)
+	listFlags.AddFlags(listCommand)
+	return listCommand
+}


Test patch:
diff --git a/pkg/eventing/sources/v1alpha1/apiserver_client_test.go b/pkg/eventing/sources/v1alpha1/apiserver_client_test.go
index fd149d6b..54bb1fa4 100644
--- a/pkg/eventing/sources/v1alpha1/apiserver_client_test.go
+++ b/pkg/eventing/sources/v1alpha1/apiserver_client_test.go
@@ -116,6 +116,20 @@ func TestUpdateApiServerSource(t *testing.T) {
 	assert.ErrorContains(t, err, "errorSource")
 }
 
+func TestListAPIServerSource(t *testing.T) {
+	sourcesServer, client := setupAPIServerSourcesClient(t)
+
+	sourcesServer.AddReactor("list", "apiserversources",
+		func(a client_testing.Action) (bool, runtime.Object, error) {
+			cJSource := newAPIServerSource("testsource", "Event")
+			return true, &v1alpha1.ApiServerSourceList{Items: []v1alpha1.ApiServerSource{*cJSource}}, nil
+		})
+
+	sourceList, err := client.ListAPIServerSource()
+	assert.NilError(t, err)
+	assert.Equal(t, len(sourceList.Items), 1)
+}
+
 func newAPIServerSource(name, resource string) *v1alpha1.ApiServerSource {
 	b := NewAPIServerSourceBuilder(name).ServiceAccount("testsa").Mode("Ref")
 	b.Sink(&v1beta1.Destination{
diff --git a/pkg/eventing/sources/v1alpha1/cronjob_client_test.go b/pkg/eventing/sources/v1alpha1/cronjob_client_test.go
index 6653f3ed..8cd732a3 100644
--- a/pkg/eventing/sources/v1alpha1/cronjob_client_test.go
+++ b/pkg/eventing/sources/v1alpha1/cronjob_client_test.go
@@ -119,6 +119,20 @@ func TestGetCronJobSource(t *testing.T) {
 	assert.ErrorContains(t, err, "errorSource")
 }
 
+func TestListCronJobSource(t *testing.T) {
+	sourcesServer, client := setupCronJobSourcesClient(t)
+
+	sourcesServer.AddReactor("list", "cronjobsources",
+		func(a client_testing.Action) (bool, runtime.Object, error) {
+			cJSource := newCronJobSource("testsource", "mysvc")
+			return true, &v1alpha1.CronJobSourceList{Items: []v1alpha1.CronJobSource{*cJSource}}, nil
+		})
+
+	sourceList, err := client.ListCronJobSource()
+	assert.NilError(t, err)
+	assert.Equal(t, len(sourceList.Items), 1)
+}
+
 func newCronJobSource(name string, sink string) *v1alpha1.CronJobSource {
 	b := NewCronJobSourceBuilder(name).
 		Schedule("* * * * *").
diff --git a/pkg/kn/commands/source/apiserver/list_test.go b/pkg/kn/commands/source/apiserver/list_test.go
new file mode 100644
index 00000000..93e68f7d
--- /dev/null
+++ b/pkg/kn/commands/source/apiserver/list_test.go
@@ -0,0 +1,59 @@
+// 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 apiserver
+
+import (
+	"testing"
+
+	"gotest.tools/assert"
+
+	knsource_v1alpha1 "knative.dev/client/pkg/eventing/sources/v1alpha1"
+	"knative.dev/client/pkg/util"
+	"knative.dev/eventing/pkg/apis/sources/v1alpha1"
+)
+
+func TestListAPIServerSource(t *testing.T) {
+	apiServerClient := knsource_v1alpha1.NewMockKnAPIServerSourceClient(t)
+
+	apiServerRecorder := apiServerClient.Recorder()
+	sampleSource := createAPIServerSource("testsource", "Event", "v1", "testsa", "Ref", "testsvc", false)
+	sampleSourceList := v1alpha1.ApiServerSourceList{}
+	sampleSourceList.Items = []v1alpha1.ApiServerSource{*sampleSource}
+
+	apiServerRecorder.ListAPIServerSource(&sampleSourceList, nil)
+
+	out, err := executeAPIServerSourceCommand(apiServerClient, nil, "list")
+	assert.NilError(t, err, "sources should be listed")
+	util.ContainsAll(out, "NAME", "RESOURCES", "SINK", "CONDITIONS", "READY", "REASON")
+	util.ContainsAll(out, "testsource", "Eventing:v1:false", "mysvc")
+
+	apiServerRecorder.Validate()
+}
+
+func TestListAPIServerSourceEmpty(t *testing.T) {
+	apiServerClient := knsource_v1alpha1.NewMockKnAPIServerSourceClient(t)
+
+	apiServerRecorder := apiServerClient.Recorder()
+	sampleSourceList := v1alpha1.ApiServerSourceList{}
+
+	apiServerRecorder.ListAPIServerSource(&sampleSourceList, nil)
+
+	out, err := executeAPIServerSourceCommand(apiServerClient, nil, "list")
+	assert.NilError(t, err, "Sources should be listed")
+	util.ContainsNone(out, "NAME", "RESOURCES", "SINK", "CONDITIONS", "READY", "REASON")
+	util.ContainsAll(out, "No", "ApiServer", "source", "found")
+
+	apiServerRecorder.Validate()
+}
diff --git a/pkg/kn/commands/source/cronjob/list_test.go b/pkg/kn/commands/source/cronjob/list_test.go
new file mode 100644
index 00000000..86c65d8c
--- /dev/null
+++ b/pkg/kn/commands/source/cronjob/list_test.go
@@ -0,0 +1,59 @@
+// 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 cronjob
+
+import (
+	"testing"
+
+	"gotest.tools/assert"
+
+	knsource_v1alpha1 "knative.dev/client/pkg/eventing/sources/v1alpha1"
+	"knative.dev/client/pkg/util"
+	"knative.dev/eventing/pkg/apis/sources/v1alpha1"
+)
+
+func TestListCronJobSource(t *testing.T) {
+	cronjobClient := knsource_v1alpha1.NewMockKnCronJobSourceClient(t)
+
+	cronJobRecorder := cronjobClient.Recorder()
+	cJSource := createCronJobSource("testsource", "* * * * */2", "maxwell", "mysvc")
+	cJSourceList := v1alpha1.CronJobSourceList{}
+	cJSourceList.Items = []v1alpha1.CronJobSource{*cJSource}
+
+	cronJobRecorder.ListCronJobSource(&cJSourceList, nil)
+
+	out, err := executeCronJobSourceCommand(cronjobClient, nil, "list")
+	assert.NilError(t, err, "Sources should be listed")
+	util.ContainsAll(out, "NAME", "SCHEDULE", "SINK", "CONDITIONS", "READY", "REASON")
+	util.ContainsAll(out, "testsource", "* * * * */2", "mysvc")
+
+	cronJobRecorder.Validate()
+}
+
+func TestListCronJobSourceEmpty(t *testing.T) {
+	cronjobClient := knsource_v1alpha1.NewMockKnCronJobSourceClient(t)
+
+	cronJobRecorder := cronjobClient.Recorder()
+	cJSourceList := v1alpha1.CronJobSourceList{}
+
+	cronJobRecorder.ListCronJobSource(&cJSourceList, nil)
+
+	out, err := executeCronJobSourceCommand(cronjobClient, nil, "list")
+	assert.NilError(t, err, "Sources should be listed")
+	util.ContainsNone(out, "NAME", "SCHEDULE", "SINK", "CONDITIONS", "READY", "REASON")
+	util.ContainsAll(out, "No", "CronJob", "source", "found")
+
+	cronJobRecorder.Validate()
+}