From e2513545b85110dd247253f40607347a815a7824 Mon Sep 17 00:00:00 2001 From: David Simansky Date: Wed, 19 Apr 2023 10:54:38 +0200 Subject: [PATCH] feat: Add experimental filters to trigger describe cmd (#1794) * feat: Add cesql filter field to trigger describe cmd * Refactor trigger describe based on defined fields in filter * Fix comment typo * Refactor without reflection --- pkg/kn/commands/trigger/describe.go | 62 ++++++++- pkg/kn/commands/trigger/describe_test.go | 159 +++++++++++++++++++++++ 2 files changed, 220 insertions(+), 1 deletion(-) diff --git a/pkg/kn/commands/trigger/describe.go b/pkg/kn/commands/trigger/describe.go index 5ca33a7ab..278c67499 100644 --- a/pkg/kn/commands/trigger/describe.go +++ b/pkg/kn/commands/trigger/describe.go @@ -19,7 +19,6 @@ import ( "github.com/spf13/cobra" "k8s.io/cli-runtime/pkg/genericclioptions" - "knative.dev/client/lib/printing" "knative.dev/client/pkg/kn/commands" "knative.dev/client/pkg/printers" @@ -123,4 +122,65 @@ func writeTrigger(dw printers.PrefixWriter, trigger *v1beta1.Trigger, printDetai subWriter.WriteAttribute(key, value) } } + if len(trigger.Spec.Filters) > 0 { + // Split 'Filter' and 'Filters (experimental)' with new line + dw.WriteLine() + subWriter := dw.WriteAttribute("Filters (experimental)", "") + for _, filter := range trigger.Spec.Filters { + writeNestedFilters(subWriter, filter) + } + } +} + +// writeNestedFilters goes through SubscriptionsAPIFilter and writes its content accordingly +func writeNestedFilters(dw printers.PrefixWriter, filter v1beta1.SubscriptionsAPIFilter) { + // All []SubscriptionsAPIFilter + if len(filter.All) > 0 { + // create new indentation after name + subWriter := dw.WriteAttribute("all", "") + for _, nestedFilter := range filter.All { + writeNestedFilters(subWriter, nestedFilter) + } + } + // Any []SubscriptionsAPIFilter + if len(filter.Any) > 0 { + // create new indentation after name + subWriter := dw.WriteAttribute("any", "") + for _, nestedFilter := range filter.Any { + writeNestedFilters(subWriter, nestedFilter) + } + } + // Not *SubscriptionsAPIFilter + if filter.Not != nil { + subWriter := dw.WriteAttribute("not", "") + writeNestedFilters(subWriter, *filter.Not) + } + // Exact map[string]string + if len(filter.Exact) > 0 { + // create new indentation after name + subWriter := dw.WriteAttribute("exact", "") + for k, v := range filter.Exact { + subWriter.WriteAttribute(k, v) + } + } + // Prefix map[string]string + if len(filter.Prefix) > 0 { + // create new indentation after name + subWriter := dw.WriteAttribute("prefix", "") + for k, v := range filter.Prefix { + subWriter.WriteAttribute(k, v) + } + } + // Suffix map[string]string + if len(filter.Suffix) > 0 { + // create new indentation after name + subWriter := dw.WriteAttribute("suffix", "") + for k, v := range filter.Suffix { + subWriter.WriteAttribute(k, v) + } + } + // CESQL string + if filter.CESQL != "" { + dw.WriteAttribute("cesql", filter.CESQL) + } } diff --git a/pkg/kn/commands/trigger/describe_test.go b/pkg/kn/commands/trigger/describe_test.go index c96a940fd..4d5188965 100644 --- a/pkg/kn/commands/trigger/describe_test.go +++ b/pkg/kn/commands/trigger/describe_test.go @@ -15,10 +15,13 @@ package trigger import ( + "bytes" "encoding/json" "errors" "testing" + "knative.dev/client/pkg/printers" + "gotest.tools/v3/assert" "gotest.tools/v3/assert/cmp" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -48,6 +51,7 @@ func TestSimpleDescribe(t *testing.T) { 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, "Filters", "experimental", "cesql", "LOWER", "type")) assert.Assert(t, util.ContainsAll(out, "Sink:", "Service", "myservicenamespace", "mysvc")) }) @@ -112,6 +116,158 @@ func TestDescribeTriggerMachineReadable(t *testing.T) { recorder.Validate() } +func TestWriteNestedFilters(t *testing.T) { + testCases := []struct { + name string + filter v1beta1.SubscriptionsAPIFilter + expectedOutput string + }{ + { + name: "Exact filter", + filter: v1beta1.SubscriptionsAPIFilter{ + Exact: map[string]string{ + "type": "example"}}, + expectedOutput: "exact: \n" + + " type: example\n", + }, + { + name: "Prefix filter", + filter: v1beta1.SubscriptionsAPIFilter{ + Prefix: map[string]string{ + "type": "foo.bar"}}, + expectedOutput: "" + + "prefix: \n" + + " type: foo.bar\n", + }, + { + name: "Suffix filter", + filter: v1beta1.SubscriptionsAPIFilter{ + Suffix: map[string]string{ + "type": "foo.bar"}}, + expectedOutput: "" + + "suffix: \n" + + " type: foo.bar\n", + }, + { + name: "All filter", + filter: v1beta1.SubscriptionsAPIFilter{ + All: []v1beta1.SubscriptionsAPIFilter{ + {Exact: map[string]string{ + "type": "foo.bar"}}, + {Prefix: map[string]string{ + "source": "foo"}}, + {Suffix: map[string]string{ + "subject": "test"}}}}, + expectedOutput: "" + + "all: \n" + + " exact: \n" + + " type: foo.bar\n" + + " prefix: \n" + + " source: foo\n" + + " suffix: \n" + + " subject: test\n", + }, + { + name: "Any filter", + filter: v1beta1.SubscriptionsAPIFilter{ + Any: []v1beta1.SubscriptionsAPIFilter{ + {Exact: map[string]string{ + "type": "foo.bar"}}, + {Prefix: map[string]string{ + "source": "foo"}}, + {Suffix: map[string]string{ + "subject": "test"}}}, + }, + expectedOutput: "" + + "any: \n" + + " exact: \n" + + " type: foo.bar\n" + + " prefix: \n" + + " source: foo\n" + + " suffix: \n" + + " subject: test\n", + }, + { + name: "Nested All filter", + filter: v1beta1.SubscriptionsAPIFilter{ + All: []v1beta1.SubscriptionsAPIFilter{ + {Exact: map[string]string{ + "type": "foo.bar"}}, + {All: []v1beta1.SubscriptionsAPIFilter{ + {Prefix: map[string]string{ + "source": "foo"}}, + {Suffix: map[string]string{ + "subject": "test"}}}}}}, + expectedOutput: "" + + "all: \n" + + " exact: \n" + + " type: foo.bar\n" + + " all: \n" + + " prefix: \n" + + " source: foo\n" + + " suffix: \n" + + " subject: test\n", + }, + { + name: "Nested Any filter", + filter: v1beta1.SubscriptionsAPIFilter{ + Any: []v1beta1.SubscriptionsAPIFilter{ + {Exact: map[string]string{ + "type": "foo.bar"}}, + {Any: []v1beta1.SubscriptionsAPIFilter{ + {Prefix: map[string]string{ + "source": "foo"}}, + {Suffix: map[string]string{ + "subject": "test"}}}}}}, + expectedOutput: "" + + "any: \n" + + " exact: \n" + + " type: foo.bar\n" + + " any: \n" + + " prefix: \n" + + " source: foo\n" + + " suffix: \n" + + " subject: test\n", + }, + { + name: "Nested Not filter", + filter: v1beta1.SubscriptionsAPIFilter{ + Not: &v1beta1.SubscriptionsAPIFilter{ + Exact: map[string]string{ + "type": "foo.bar", + }, + Prefix: map[string]string{ + "type": "bar", + }, + CESQL: "select bar", + Not: &v1beta1.SubscriptionsAPIFilter{ + Suffix: map[string]string{ + "source": "foo"}}}}, + expectedOutput: "" + + "not: \n" + + " not: \n" + + " suffix: \n" + + " source: foo\n" + + " exact: \n" + + " type: foo.bar\n" + + " prefix: \n" + + " type: bar\n" + + " cesql: select bar\n", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + buf := &bytes.Buffer{} + dw := printers.NewPrefixWriter(buf) + writeNestedFilters(dw, tc.filter) + err := dw.Flush() + assert.NilError(t, err) + assert.Equal(t, tc.expectedOutput, buf.String()) + }) + } +} + func getTriggerSinkRef() *v1beta1.Trigger { return &v1beta1.Trigger{ TypeMeta: v1.TypeMeta{ @@ -130,6 +286,9 @@ func getTriggerSinkRef() *v1beta1.Trigger { "source": "src.eventing.knative", }, }, + Filters: []v1beta1.SubscriptionsAPIFilter{ + {CESQL: "LOWER(type) = 'my-event-type'"}, + }, Subscriber: duckv1.Destination{ Ref: &duckv1.KReference{ Kind: "Service",