Skip to content

Commit

Permalink
feat: resource regex (#4480)
Browse files Browse the repository at this point in the history
* feat: name regex for trigger selectors

* fix: dep update

* fix: regex test

* doc: add example for regex

* fix: select tests and test suites for name reg ex

* fix: dep update
  • Loading branch information
vsukhin authored Oct 20, 2023
1 parent 57eb58a commit 4d73579
Show file tree
Hide file tree
Showing 11 changed files with 122 additions and 3 deletions.
4 changes: 4 additions & 0 deletions api/v1/testkube.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5473,6 +5473,10 @@ components:
type: string
description: kubernetes resource name selector
example: nginx
nameRegex:
type: string
description: kubernetes resource name regex
example: nginx.*
namespace:
type: string
description: resource namespace
Expand Down
1 change: 1 addition & 0 deletions docs/docs/articles/test-triggers.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ Name selectors are used when we want to select a specific resource in a specific
```yaml
selector:
name: Kubernetes object name
nameRegex: Kubernetes object name regex (for example, "test.*")
namespace: Kubernetes object namespace (default is **testkube**)
```
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ require (
github.com/gorilla/websocket v1.5.0
github.com/joshdk/go-junit v1.0.0
github.com/kelseyhightower/envconfig v1.4.0
github.com/kubeshop/testkube-operator v1.10.8-0.20231005124234-aa5afde3a8f8
github.com/kubeshop/testkube-operator v1.10.8-0.20231020122730-3ec11798a62f
github.com/minio/minio-go/v7 v7.0.47
github.com/montanaflynn/stats v0.6.6
github.com/moogar0880/problems v0.1.1
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -240,8 +240,8 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kubeshop/testkube-operator v1.10.8-0.20231005124234-aa5afde3a8f8 h1:dDhvegOPuvkvRsSEH8H7t3puBRFXSTsS6RYR/kmeShg=
github.com/kubeshop/testkube-operator v1.10.8-0.20231005124234-aa5afde3a8f8/go.mod h1:iwzgZriFxOzstinAqWB32g9iAMSORiQvGYWzX0FWbQk=
github.com/kubeshop/testkube-operator v1.10.8-0.20231020122730-3ec11798a62f h1:ce4ifn6U9c442YSdkoDLcqwCNS6c84gLj/Pbl8mEygY=
github.com/kubeshop/testkube-operator v1.10.8-0.20231020122730-3ec11798a62f/go.mod h1:iwzgZriFxOzstinAqWB32g9iAMSORiQvGYWzX0FWbQk=
github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w=
github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
github.com/lithammer/fuzzysearch v1.1.8 h1:/HIuJnjHuXS8bKaiTMeeDlW2/AyIWk2brx1V8LFgLN4=
Expand Down
2 changes: 2 additions & 0 deletions pkg/api/v1/testkube/model_test_trigger_selector.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ package testkube
type TestTriggerSelector struct {
// kubernetes resource name selector
Name string `json:"name,omitempty"`
// kubernetes resource name regex
NameRegex string `json:"nameRegex,omitempty"`
// resource namespace
Namespace string `json:"namespace,omitempty"`
LabelSelector *IoK8sApimachineryPkgApisMetaV1LabelSelector `json:"labelSelector,omitempty"`
Expand Down
6 changes: 6 additions & 0 deletions pkg/crd/templates/testtrigger.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ spec:
{{- if .ResourceSelector.Name }}
name: {{ .ResourceSelector.Name }}
{{- end }}
{{- if .ResourceSelector.NameRegex }}
nameRegex: {{ .ResourceSelector.NameRegex }}
{{- end }}
{{- if .ResourceSelector.Namespace }}
namespace: {{ .ResourceSelector.Namespace }}
{{- end }}
Expand Down Expand Up @@ -111,6 +114,9 @@ spec:
{{- if .TestSelector.Name }}
name: {{ .TestSelector.Name }}
{{- end }}
{{- if .TestSelector.NameRegex }}
nameRegex: {{ .TestSelector.NameRegex }}
{{- end }}
{{- if .TestSelector.Namespace }}
namespace: {{ .TestSelector.Namespace }}
{{- end }}
Expand Down
1 change: 1 addition & 0 deletions pkg/mapper/testtriggers/kube_openapi.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ func mapSelectorFromCRD(selector testsv1.TestTriggerSelector) *testkube.TestTrig
}
return &testkube.TestTriggerSelector{
Name: selector.Name,
NameRegex: selector.NameRegex,
Namespace: selector.Namespace,
LabelSelector: labelSelector,
}
Expand Down
1 change: 1 addition & 0 deletions pkg/mapper/testtriggers/openapi_kube.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ func mapSelectorToCRD(selector *testkube.TestTriggerSelector) testsv1.TestTrigge
}
return testsv1.TestTriggerSelector{
Name: selector.Name,
NameRegex: selector.NameRegex,
Namespace: selector.Namespace,
LabelSelector: labelSelector,
}
Expand Down
41 changes: 41 additions & 0 deletions pkg/triggers/executor.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package triggers

import (
"context"
"regexp"
"time"

"github.com/pkg/errors"
Expand Down Expand Up @@ -118,6 +119,26 @@ func (s *Service) getTests(t *testtriggersv1.TestTrigger) ([]testsv3.Test, error
}
tests = append(tests, *test)
}

if t.Spec.TestSelector.NameRegex != "" {
s.logger.Debugf("trigger service: executor component: fetching testsv3.Test with name regex %s", t.Spec.TestSelector.NameRegex)
testList, err := s.testsClient.List("")
if err != nil {
return nil, err
}

re, err := regexp.Compile(t.Spec.TestSelector.NameRegex)
if err != nil {
return nil, err
}

for i := range testList.Items {
if re.MatchString(testList.Items[i].Name) {
tests = append(tests, testList.Items[i])
}
}
}

if t.Spec.TestSelector.LabelSelector != nil {
selector, err := metav1.LabelSelectorAsSelector(t.Spec.TestSelector.LabelSelector)
if err != nil {
Expand All @@ -144,6 +165,26 @@ func (s *Service) getTestSuites(t *testtriggersv1.TestTrigger) ([]testsuitesv3.T
}
testSuites = append(testSuites, *testSuite)
}

if t.Spec.TestSelector.NameRegex != "" {
s.logger.Debugf("trigger service: executor component: fetching testsuitesv3.TestSuite with name regex %s", t.Spec.TestSelector.NameRegex)
testSuitesList, err := s.testSuitesClient.List("")
if err != nil {
return nil, err
}

re, err := regexp.Compile(t.Spec.TestSelector.NameRegex)
if err != nil {
return nil, err
}

for i := range testSuitesList.Items {
if re.MatchString(testSuitesList.Items[i].Name) {
testSuites = append(testSuites, testSuitesList.Items[i])
}
}
}

if t.Spec.TestSelector.LabelSelector != nil {
selector, err := metav1.LabelSelectorAsSelector(t.Spec.TestSelector.LabelSelector)
if err != nil {
Expand Down
13 changes: 13 additions & 0 deletions pkg/triggers/matcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"net/http"
"net/url"
"regexp"
"sync"
"time"

Expand Down Expand Up @@ -112,6 +113,18 @@ func matchSelector(selector *testtriggersv1.TestTriggerSelector, namespace strin
isSameTestTriggerNamespace := selector.Namespace == "" && namespace == event.namespace
return isSameName && (isSameNamespace || isSameTestTriggerNamespace)
}
if selector.NameRegex != "" {
re, err := regexp.Compile(selector.NameRegex)
if err != nil {
logger.Errorf("error compiling %v name regex: %v", selector.NameRegex, err)
return false
}

isSameName := re.MatchString(event.name)
isSameNamespace := selector.Namespace == event.namespace
isSameTestTriggerNamespace := selector.Namespace == "" && namespace == event.namespace
return isSameName && (isSameNamespace || isSameTestTriggerNamespace)
}
if selector.LabelSelector != nil && len(event.labels) > 0 {
k8sSelector, err := v1.LabelSelectorAsSelector(selector.LabelSelector)
if err != nil {
Expand Down
50 changes: 50 additions & 0 deletions pkg/triggers/matcher_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,56 @@ func TestService_match(t *testing.T) {
assert.NoError(t, err)
}

func TestService_matchRegex(t *testing.T) {
t.Parallel()

e := &watcherEvent{
resource: "deployment",
name: "test-deployment",
namespace: "testkube",
labels: nil,
object: nil,
eventType: "modified",
causes: nil,
}

srv1 := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
}))
defer srv1.Close()

testTrigger1 := &testtriggersv1.TestTrigger{
ObjectMeta: metav1.ObjectMeta{Namespace: "testkube", Name: "test-trigger-1"},
Spec: testtriggersv1.TestTriggerSpec{
Resource: "deployment",
ResourceSelector: testtriggersv1.TestTriggerSelector{NameRegex: "test.*"},
Event: "modified",
Action: "run",
Execution: "test",
ConcurrencyPolicy: "allow",
TestSelector: testtriggersv1.TestTriggerSelector{NameRegex: "some.*"},
},
}
statusKey1 := newStatusKey(testTrigger1.Namespace, testTrigger1.Name)
triggerStatus1 := &triggerStatus{testTrigger: testTrigger1}
s := &Service{
defaultConditionsCheckBackoff: defaultConditionsCheckBackoff,
defaultConditionsCheckTimeout: defaultConditionsCheckTimeout,
defaultProbesCheckBackoff: defaultProbesCheckBackoff,
defaultProbesCheckTimeout: defaultProbesCheckTimeout,
triggerExecutor: func(ctx context.Context, trigger *testtriggersv1.TestTrigger) error {
assert.Equal(t, "testkube", trigger.Namespace)
assert.Equal(t, "test-trigger-1", trigger.Name)
return nil
},
triggerStatus: map[statusKey]*triggerStatus{statusKey1: triggerStatus1},
logger: log.DefaultLogger,
httpClient: http.DefaultClient,
}

err := s.match(context.Background(), e)
assert.NoError(t, err)
}

func TestService_noMatch(t *testing.T) {
t.Parallel()

Expand Down

0 comments on commit 4d73579

Please sign in to comment.