Skip to content

Commit

Permalink
fix: add actor filters
Browse files Browse the repository at this point in the history
Signed-off-by: Vladislav Sukhin <[email protected]>
  • Loading branch information
vsukhin committed Oct 23, 2024
1 parent 07cad5d commit 8cd4890
Show file tree
Hide file tree
Showing 12 changed files with 231 additions and 15 deletions.
19 changes: 18 additions & 1 deletion api/v1/testkube.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3806,6 +3806,8 @@ paths:
parameters:
- $ref: "#/components/parameters/ID"
- $ref: "#/components/parameters/TagSelector"
- $ref: "#/components/parameters/ActorName"
- $ref: "#/components/parameters/ActorType"
summary: List test workflow executions
description: List test workflow executions
operationId: listTestWorkflowExecutionsByTestWorkflow
Expand Down Expand Up @@ -4071,6 +4073,8 @@ paths:
parameters:
- $ref: "#/components/parameters/ID"
- $ref: "#/components/parameters/TagSelector"
- $ref: "#/components/parameters/ActorName"
- $ref: "#/components/parameters/ActorType"
summary: List test workflow executions
description: List test workflow executions
operationId: listTestWorkflowExecutions
Expand Down Expand Up @@ -7223,7 +7227,7 @@ components:
type: string
enum:
- cron
- testrigger
- testtrigger
- user
- testworkflow
- testworkflowexecution
Expand Down Expand Up @@ -10753,6 +10757,19 @@ components:
schema:
type: string
description: Test workflow execution tags
ActorName:
in: query
name: actorName
schema:
type: string
description: Test workflow running conntext actor name
ActorType:
in: query
name: actorType
schema:
type: string
description: Test workflow running conntext actor type

requestBodies:
UploadsBody:
description: "Upload files request body data"
Expand Down
47 changes: 40 additions & 7 deletions cmd/kubectl-testkube/commands/testworkflows/executions.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package testworkflows

import (
"fmt"
"os"
"strings"

Expand All @@ -9,17 +10,18 @@ import (
"github.com/kubeshop/testkube/cmd/kubectl-testkube/commands/common"
"github.com/kubeshop/testkube/cmd/kubectl-testkube/commands/common/render"
"github.com/kubeshop/testkube/cmd/kubectl-testkube/commands/testworkflows/renderer"
tc "github.com/kubeshop/testkube/pkg/api/v1/client"
"github.com/kubeshop/testkube/pkg/api/v1/testkube"
"github.com/kubeshop/testkube/pkg/ui"
)

func NewGetTestWorkflowExecutionsCmd() *cobra.Command {
var (
limit int
selectors []string
testWorkflowName string
logsOnly bool
tags []string
limit int
selectors []string
testWorkflowName, actorName, actorType string
logsOnly bool
tags []string
)

cmd := &cobra.Command{
Expand All @@ -41,12 +43,20 @@ func NewGetTestWorkflowExecutionsCmd() *cobra.Command {
client, _, err := common.GetClient(cmd)
ui.ExitOnError("getting client", err)

err = validateActorType(testkube.TestWorkflowRunningContextActorType(actorType))
ui.ExitOnError("validatig actor type", err)

if len(args) == 0 {
client, _, err := common.GetClient(cmd)
ui.ExitOnError("getting client", err)

executions, err := client.ListTestWorkflowExecutions(testWorkflowName, limit,
strings.Join(selectors, ","), strings.Join(tags, ","))
options := tc.FilterTestWorkflowExecutionOptions{
Selector: strings.Join(selectors, ","),
TagSelector: strings.Join(tags, ","),
ActorName: actorName,
ActorType: testkube.TestWorkflowRunningContextActorType(actorType),
}
executions, err := client.ListTestWorkflowExecutions(testWorkflowName, limit, options)
ui.ExitOnError("getting test workflow executions list", err)
err = render.List(cmd, testkube.TestWorkflowExecutionSummaries(executions.Results), os.Stdout)
ui.ExitOnError("rendering list", err)
Expand Down Expand Up @@ -87,6 +97,29 @@ func NewGetTestWorkflowExecutionsCmd() *cobra.Command {
cmd.Flags().StringSliceVarP(&selectors, "label", "l", nil, "label key value pair: --label key1=value1")
cmd.Flags().BoolVar(&logsOnly, "logs-only", false, "show only execution logs")
cmd.Flags().StringSliceVarP(&tags, "tag", "", nil, "tag key value pair: --tag key1=value1")
cmd.Flags().StringVarP(&actorName, "actorName", "", "", "test workflow running context actor name")
cmd.Flags().StringVarP(&actorType, "actorType", "", "", "test workflow running context actor type one of cron|testtrigger|user|testworkfow|testworkflowexecution|program")

return cmd
}

func validateActorType(actorType testkube.TestWorkflowRunningContextActorType) error {
if actorType == "" {
return nil
}

actorTypes := map[testkube.TestWorkflowRunningContextActorType]struct{}{
testkube.CRON_TestWorkflowRunningContextActorType: {},
testkube.TESTTRIGGER_TestWorkflowRunningContextActorType: {},
testkube.USER_TestWorkflowRunningContextActorType: {},
testkube.TESTWORKFLOW_TestWorkflowRunningContextActorType: {},
testkube.TESTWORKFLOWEXECUTION_TestWorkflowRunningContextActorType: {},
testkube.PROGRAM_TestWorkflowRunningContextActorType: {},
}

if _, ok := actorTypes[actorType]; !ok {
return fmt.Errorf("please pass one of cron|testtrigger|user|testworkfow|testworkflowexecution|program for actor type")
}

return nil
}
10 changes: 10 additions & 0 deletions internal/app/api/v1/testworkflowexecutions.go
Original file line number Diff line number Diff line change
Expand Up @@ -496,5 +496,15 @@ func getWorkflowExecutionsFilterFromRequest(c *fiber.Ctx) testworkflow2.Filter {
filter = filter.WithTagSelector(tagSelector)
}

actorName := c.Query("actorName")
if actorName != "" {
filter = filter.WithActorName(actorName)
}

actorType := c.Query("actorType")
if actorType != "" {
filter = filter.WithActorType(testkube.TestWorkflowRunningContextActorType(actorType))
}

return filter
}
10 changes: 9 additions & 1 deletion pkg/api/v1/client/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ type TestWorkflowAPI interface {
// TestWorkflowExecutionAPI describes test workflow api methods
type TestWorkflowExecutionAPI interface {
GetTestWorkflowExecution(executionID string) (execution testkube.TestWorkflowExecution, err error)
ListTestWorkflowExecutions(id string, limit int, selector, tagSelector string) (executions testkube.TestWorkflowExecutionsResult, err error)
ListTestWorkflowExecutions(id string, limit int, options FilterTestWorkflowExecutionOptions) (executions testkube.TestWorkflowExecutionsResult, err error)
AbortTestWorkflowExecution(workflow string, id string) error
AbortTestWorkflowExecutions(workflow string) error
GetTestWorkflowExecutionArtifacts(executionID string) (artifacts testkube.Artifacts, err error)
Expand Down Expand Up @@ -286,6 +286,14 @@ type ExecuteTestSuiteOptions struct {
DisableWebhooks bool
}

// FilterTestWorkflowExecutionOptions contains filter test workflow execution options
type FilterTestWorkflowExecutionOptions struct {
Selector string
TagSelector string
ActorName string
ActorType testkube.TestWorkflowRunningContextActorType
}

// Gettable is an interface of gettable objects
type Gettable interface {
testkube.Test | testkube.TestSuite | testkube.ExecutorDetails |
Expand Down
8 changes: 5 additions & 3 deletions pkg/api/v1/client/testworkflow.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,15 +136,17 @@ func (c TestWorkflowClient) GetTestWorkflowExecution(id string) (testkube.TestWo
}

// ListTestWorkflowExecutions list test workflow executions for selected workflow
func (c TestWorkflowClient) ListTestWorkflowExecutions(id string, limit int, selector, tagSelector string) (testkube.TestWorkflowExecutionsResult, error) {
func (c TestWorkflowClient) ListTestWorkflowExecutions(id string, limit int, options FilterTestWorkflowExecutionOptions) (testkube.TestWorkflowExecutionsResult, error) {
uri := c.testWorkflowExecutionsResultTransport.GetURI("/test-workflow-executions/")
if id != "" {
uri = c.testWorkflowExecutionsResultTransport.GetURI(fmt.Sprintf("/test-workflows/%s/executions", id))
}
params := map[string]string{
"selector": selector,
"selector": options.Selector,
"pageSize": fmt.Sprintf("%d", limit),
"tagSelector": tagSelector,
"tagSelector": options.TagSelector,
"actionName": options.ActorName,
"actionType": string(options.ActorType),
}
return c.testWorkflowExecutionsResultTransport.Execute(http.MethodGet, uri, nil, params)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ type TestWorkflowRunningContextActorType string
// List of TestWorkflowRunningContextActorType
const (
CRON_TestWorkflowRunningContextActorType TestWorkflowRunningContextActorType = "cron"
TESTRIGGER_TestWorkflowRunningContextActorType TestWorkflowRunningContextActorType = "testrigger"
TESTTRIGGER_TestWorkflowRunningContextActorType TestWorkflowRunningContextActorType = "testtrigger"
USER_TestWorkflowRunningContextActorType TestWorkflowRunningContextActorType = "user"
TESTWORKFLOW_TestWorkflowRunningContextActorType TestWorkflowRunningContextActorType = "testworkflow"
TESTWORKFLOWEXECUTION_TestWorkflowRunningContextActorType TestWorkflowRunningContextActorType = "testworkflowexecution"
Expand Down
28 changes: 28 additions & 0 deletions pkg/repository/testworkflow/filter.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ type FilterImpl struct {
FSelector string
FTagSelector string
FLabelSelector *LabelSelector
FActorName string
FActorType testkube.TestWorkflowRunningContextActorType
}

func NewExecutionsFilter() *FilterImpl {
Expand Down Expand Up @@ -84,6 +86,16 @@ func (f *FilterImpl) WithTagSelector(tagSelector string) *FilterImpl {
return f
}

func (f *FilterImpl) WithActorName(actorName string) *FilterImpl {
f.FActorName = actorName
return f
}

func (f *FilterImpl) WithActorType(actorType testkube.TestWorkflowRunningContextActorType) *FilterImpl {
f.FActorType = actorType
return f
}

func (f *FilterImpl) WithLabelSelector(selector *LabelSelector) *FilterImpl {
f.FLabelSelector = selector
return f
Expand Down Expand Up @@ -164,3 +176,19 @@ func (f FilterImpl) TagSelector() string {
func (f FilterImpl) LabelSelector() *LabelSelector {
return f.FLabelSelector
}

func (f FilterImpl) ActorName() string {
return f.FActorName
}

func (f FilterImpl) ActorType() testkube.TestWorkflowRunningContextActorType {
return f.FActorType
}

func (f FilterImpl) ActorNameDefined() bool {
return f.FActorName != ""
}

func (f FilterImpl) ActorTypeDefined() bool {
return f.FActorType != ""
}
4 changes: 4 additions & 0 deletions pkg/repository/testworkflow/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ type Filter interface {
Selector() string
TagSelector() string
LabelSelector() *LabelSelector
ActorName() string
ActorNameDefined() bool
ActorType() testkube.TestWorkflowRunningContextActorType
ActorTypeDefined() bool
}

//go:generate mockgen -destination=./mock_repository.go -package=testworkflow "github.com/kubeshop/testkube/pkg/repository/testworkflow" Repository
Expand Down
8 changes: 8 additions & 0 deletions pkg/repository/testworkflow/mongo.go
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,14 @@ func composeQueryAndOpts(filter Filter) (bson.M, *options.FindOptions) {
query["$or"] = subquery
}

if filter.ActorNameDefined() {
query["runningContext.actor.name"] = filter.ActorName()
}

if filter.ActorTypeDefined() {
query["runningContext.actor.type"] = filter.ActorType()
}

opts.SetSkip(int64(filter.Page() * filter.PageSize()))
opts.SetLimit(int64(filter.PageSize()))
opts.SetSort(bson.D{{Key: "scheduledat", Value: -1}})
Expand Down
106 changes: 106 additions & 0 deletions pkg/repository/testworkflow/mongo_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"

"github.com/kubeshop/testkube/internal/common"
"github.com/kubeshop/testkube/pkg/api/v1/testkube"
)

Expand Down Expand Up @@ -325,3 +326,108 @@ func TestNewMongoRepository_GetExecutions_Tags_Integration(t *testing.T) {

assert.Len(t, res, 2)
}

func TestNewMongoRepository_GetExecutions_Actor_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-actor-mongo-repository-test")
t.Cleanup(func() {
db.Drop(ctx)
})

repo := NewMongoRepository(db, false)

execution := testkube.TestWorkflowExecution{
Id: "test-id-1",
Name: "test-name-1",
Workflow: &testkube.TestWorkflow{
Name: "test-name-1",
Spec: &testkube.TestWorkflowSpec{},
},
RunningContext: &testkube.TestWorkflowRunningContext{
Actor: &testkube.TestWorkflowRunningContextActor{
Name: "user-1",
Type_: common.Ptr(testkube.USER_TestWorkflowRunningContextActorType),
},
},
}
if err := repo.Insert(ctx, execution); err != nil {
t.Fatalf("error inserting execution: %v", err)
}

execution = testkube.TestWorkflowExecution{
Id: "test-id-2",
Name: "test-name-2",
Workflow: &testkube.TestWorkflow{
Name: "test-name-2",
Spec: &testkube.TestWorkflowSpec{},
},
RunningContext: &testkube.TestWorkflowRunningContext{
Actor: &testkube.TestWorkflowRunningContextActor{
Name: "user-2",
Type_: common.Ptr(testkube.USER_TestWorkflowRunningContextActorType),
},
},
}
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, 2)

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

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

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

assert.Len(t, res, 2)

actorName = "user-1"
actorType = testkube.USER_TestWorkflowRunningContextActorType
res, err = repo.GetExecutions(ctx, NewExecutionsFilter().WithActorName(actorName).WithActorType(actorType))
if err != nil {
t.Fatalf("error getting executions: %v", err)
}

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

actorName = "user-1"
actorType = testkube.PROGRAM_TestWorkflowRunningContextActorType
res, err = repo.GetExecutions(ctx, NewExecutionsFilter().WithActorName(actorName).WithActorType(actorType))
if err != nil {
t.Fatalf("error getting executions: %v", err)
}

assert.Len(t, res, 0)

actorName = "user-3"
actorType = testkube.USER_TestWorkflowRunningContextActorType
res, err = repo.GetExecutions(ctx, NewExecutionsFilter().WithActorName(actorName).WithActorType(actorType))
if err != nil {
t.Fatalf("error getting executions: %v", err)
}

assert.Len(t, res, 0)
}
2 changes: 1 addition & 1 deletion pkg/tcl/testworkflowstcl/mapper/cdevents.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ func MapTestkubeTestWorkflowRunningContextActorToCDEventTiggerType(actor testkub
case testkube.USER_TestWorkflowRunningContextActorType, testkube.PROGRAM_TestWorkflowRunningContextActorType:
return "manual"
case testkube.TESTWORKFLOW_TestWorkflowRunningContextActorType, testkube.TESTWORKFLOWEXECUTION_TestWorkflowRunningContextActorType,
testkube.TESTRIGGER_TestWorkflowRunningContextActorType:
testkube.TESTTRIGGER_TestWorkflowRunningContextActorType:
return "event"
case testkube.CRON_TestWorkflowRunningContextActorType:
return "schedule"
Expand Down
Loading

0 comments on commit 8cd4890

Please sign in to comment.