Skip to content

Commit

Permalink
feat: [TKC-2551] add support for advanced label filtering (#5853)
Browse files Browse the repository at this point in the history
  • Loading branch information
povilasv authored Sep 19, 2024
1 parent 5f8949a commit 27f690e
Show file tree
Hide file tree
Showing 4 changed files with 173 additions and 10 deletions.
30 changes: 20 additions & 10 deletions pkg/repository/testworkflow/filter.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,17 @@ import (
)

type FilterImpl struct {
FName string
FLastNDays int
FStartDate *time.Time
FEndDate *time.Time
FStatuses []testkube.TestWorkflowStatus
FPage int
FPageSize int
FTextSearch string
FSelector string
FTagSelector string
FName string
FLastNDays int
FStartDate *time.Time
FEndDate *time.Time
FStatuses []testkube.TestWorkflowStatus
FPage int
FPageSize int
FTextSearch string
FSelector string
FTagSelector string
FLabelSelector *LabelSelector
}

func NewExecutionsFilter() *FilterImpl {
Expand Down Expand Up @@ -77,6 +78,11 @@ func (f *FilterImpl) WithTagSelector(tagSelector string) *FilterImpl {
return f
}

func (f *FilterImpl) WithLabelSelector(selector *LabelSelector) *FilterImpl {
f.FLabelSelector = selector
return f
}

func (f FilterImpl) Name() string {
return f.FName
}
Expand Down Expand Up @@ -140,3 +146,7 @@ func (f FilterImpl) Selector() string {
func (f FilterImpl) TagSelector() string {
return f.FTagSelector
}

func (f FilterImpl) LabelSelector() *LabelSelector {
return f.FLabelSelector
}
12 changes: 12 additions & 0 deletions pkg/repository/testworkflow/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,17 @@ import (
"github.com/kubeshop/testkube/pkg/api/v1/testkube"
)

type Label struct {
Key string
Value *string
// If value is nil, we check if key exists / not exists
Exists *bool
}

type LabelSelector struct {
Or []Label
}

const PageDefaultLimit int = 100

type Filter interface {
Expand All @@ -27,6 +38,7 @@ type Filter interface {
TextSearch() string
Selector() string
TagSelector() string
LabelSelector() *LabelSelector
}

//go:generate mockgen -destination=./mock_repository.go -package=testworkflow "github.com/kubeshop/testkube/pkg/repository/testworkflow" Repository
Expand Down
14 changes: 14 additions & 0 deletions pkg/repository/testworkflow/mongo.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"time"

"github.com/kubeshop/testkube/pkg/repository/common"
"github.com/kubeshop/testkube/pkg/utils"

"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
Expand Down Expand Up @@ -372,6 +373,19 @@ func composeQueryAndOpts(filter Filter) (bson.M, *options.FindOptions) {
}
}

if filter.LabelSelector() != nil && len(filter.LabelSelector().Or) > 0 {
subquery := bson.A{}
for _, label := range filter.LabelSelector().Or {
if label.Value != nil {
subquery = append(subquery, bson.M{"workflow.labels." + utils.EscapeDots(label.Key): *label.Value})
} else if label.Exists != nil {
subquery = append(subquery,
bson.M{"workflow.labels." + utils.EscapeDots(label.Key): bson.M{"$exists": *label.Exists}})
}
}
query["$or"] = subquery
}

opts.SetSkip(int64(filter.Page() * filter.PageSize()))
opts.SetLimit(int64(filter.PageSize()))
opts.SetSort(bson.D{{Key: "scheduledat", Value: -1}})
Expand Down
127 changes: 127 additions & 0 deletions pkg/repository/testworkflow/mongo_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,3 +86,130 @@ func TestNewMongoRepository_UpdateReport_Integration(t *testing.T) {
assert.Equal(t, *report1, fresh.Reports[0])
assert.Equal(t, *report2, fresh.Reports[1])
}

func TestNewMongoRepository_Executions_Integration(t *testing.T) {
test.IntegrationTest(t)

ctx := context.Background()

client, err := mongo.Connect(ctx, options.Client().ApplyURI(cfg.APIMongoDSN))
if err != nil {
t.Fatalf("error connecting to mongo: %v", err)
}
db := client.Database("testworkflow-executions-mongo-repository-test")
t.Cleanup(func() {
db.Drop(ctx)
})

repo := NewMongoRepository(db, false)

execution := testkube.TestWorkflowExecution{
Id: "test-id",
Name: "test-name",
Workflow: &testkube.TestWorkflow{
Name: "test-name",
Labels: map[string]string{
"workflow.labels.testkube.io/group": "grp1",
},
Spec: &testkube.TestWorkflowSpec{},
},
}
if err := repo.Insert(ctx, execution); err != nil {
t.Fatalf("error inserting execution: %v", err)
}

execution = testkube.TestWorkflowExecution{
Id: "test-no-group",
Name: "test-no-group-name",
Workflow: &testkube.TestWorkflow{
Name: "test-no-group-name",
Labels: map[string]string{},
Spec: &testkube.TestWorkflowSpec{},
},
}
if err := repo.Insert(ctx, execution); err != nil {
t.Fatalf("error inserting execution: %v", err)
}
execution = testkube.TestWorkflowExecution{
Id: "test-group2-id",
Name: "test-group2-name",
Workflow: &testkube.TestWorkflow{
Name: "test-group2-name",
Labels: map[string]string{
"workflow.labels.testkube.io/group": "grp2",
},
Spec: &testkube.TestWorkflowSpec{},
},
}
if err := repo.Insert(ctx, execution); err != nil {
t.Fatalf("error inserting execution: %v", err)
}

res, err := repo.GetExecutions(ctx, NewExecutionsFilter())
if err != nil {
t.Fatalf("error getting executions: %v", err)
}

assert.Len(t, res, 3)

labelSelector := LabelSelector{
Or: []Label{
{Key: "workflow.labels.testkube.io/group", Value: strPtr("grp2")},
},
}
res, err = repo.GetExecutions(ctx, NewExecutionsFilter().WithLabelSelector(&labelSelector))
if err != nil {
t.Fatalf("error getting executions: %v", err)
}

assert.Len(t, res, 1)
assert.Equal(t, "test-group2-name", res[0].Name)

labelSelector = LabelSelector{
Or: []Label{
{Key: "workflow.labels.testkube.io/group", Exists: boolPtr(false)},
},
}
res, err = repo.GetExecutions(ctx, NewExecutionsFilter().WithLabelSelector(&labelSelector))
if err != nil {
t.Fatalf("error getting executions: %v", err)
}

assert.Len(t, res, 1)
assert.Equal(t, "test-no-group-name", res[0].Name)

labelSelector = LabelSelector{
Or: []Label{
{Key: "workflow.labels.testkube.io/group", Exists: boolPtr(false)},
{Key: "workflow.labels.testkube.io/group", Value: strPtr("grp2")},
},
}
res, err = repo.GetExecutions(ctx, NewExecutionsFilter().WithLabelSelector(&labelSelector))
if err != nil {
t.Fatalf("error getting executions: %v", err)
}

assert.Len(t, res, 2)

labelSelector = LabelSelector{
Or: []Label{
{Key: "workflow.labels.testkube.io/group", Exists: boolPtr(false)},
{Key: "workflow.labels.testkube.io/group", Value: strPtr("grp1")},
{Key: "workflow.labels.testkube.io/group", Value: strPtr("grp2")},
},
}
res, err = repo.GetExecutions(ctx, NewExecutionsFilter().WithLabelSelector(&labelSelector))
if err != nil {
t.Fatalf("error getting executions: %v", err)
}

assert.Len(t, res, 3)
}

func strPtr(s string) *string {
return &s
}

func boolPtr(b bool) *bool {
return &b
}

0 comments on commit 27f690e

Please sign in to comment.