Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions cmd/workflow/simulate/simulate.go
Original file line number Diff line number Diff line change
Expand Up @@ -807,12 +807,9 @@ func makeBeforeStartNonInteractive(holder *TriggerInfoAndBeforeStart, inputs Inp
case "cron-trigger@1.0.0":
holder.TriggerFunc = func() error {
skipWaitSignal := make(chan struct{}, 1)
if err := manualTriggerCaps.ManualCronTrigger.ManualTrigger(ctx, triggerRegistrationID, skipWaitSignal); err != nil {
return err
}
// With cron schedule on non-interactive mode
skipWaitSignal <- struct{}{}
return nil
return manualTriggerCaps.ManualCronTrigger.ManualTrigger(ctx, triggerRegistrationID, skipWaitSignal)
}
case "http-trigger@1.0.0-alpha":
if strings.TrimSpace(inputs.HTTPPayload) == "" {
Expand Down
60 changes: 60 additions & 0 deletions cmd/workflow/simulate/simulate_test.go
Original file line number Diff line number Diff line change
@@ -1,18 +1,27 @@
package simulate

import (
"context"
"encoding/base64"
"fmt"
"io"
"os"
"path/filepath"
rt "runtime"
"testing"
"time"

"github.com/spf13/viper"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

commoncaps "github.com/smartcontractkit/chainlink-common/pkg/capabilities"
crontypedapi "github.com/smartcontractkit/chainlink-common/pkg/capabilities/v2/triggers/cron"
"github.com/smartcontractkit/chainlink-common/pkg/logger"
pb "github.com/smartcontractkit/chainlink-protos/cre/go/sdk"
"github.com/smartcontractkit/chainlink/v2/core/capabilities/fakes"
simulator "github.com/smartcontractkit/chainlink/v2/core/services/workflows/cmd/cre/utils"

cmdcommon "github.com/smartcontractkit/cre-cli/cmd/common"
"github.com/smartcontractkit/cre-cli/internal/runtime"
"github.com/smartcontractkit/cre-cli/internal/settings"
Expand Down Expand Up @@ -438,6 +447,57 @@ func TestSimulateResolveInputs_InvocationDir(t *testing.T) {
assert.Equal(t, invocationDir, inputs.InvocationDir)
}

// TestNonInteractiveCronTriggerDoesNotBlockOnSchedule verifies that when the
// simulator runs in non-interactive mode with a cron trigger, TriggerFunc
// completes immediately without waiting for the actual cron schedule.
//
// The previous broken implementation sent skipWaitSignal *after* ManualTrigger
// returned, so ManualTrigger blocked in its select until the real cron job fired
// (up to 60 s). The fix pre-fills the channel before calling ManualTrigger.
func TestNonInteractiveCronTriggerDoesNotBlockOnSchedule(t *testing.T) {
t.Parallel()

cronSvc, err := fakes.NewManualCronTriggerService(logger.Test(t))
require.NoError(t, err)

ctx, cancel := context.WithCancel(context.Background())
defer cancel()

require.NoError(t, cronSvc.Start(ctx))
t.Cleanup(func() { _ = cronSvc.Close() })

// Register the trigger with the ID that makeBeforeStartNonInteractive will use.
triggerIndex := 0
triggerRegistrationID := fmt.Sprintf("trigger_reg_1111111111111111111111111111111111111111111111111111111111111111_%d", triggerIndex)
_, capErr := cronSvc.RegisterTrigger(ctx, triggerRegistrationID,
commoncaps.RequestMetadata{WorkflowID: "test-workflow"},
&crontypedapi.Config{Schedule: "* * * * *"},
)
require.Nil(t, capErr)

holder := &TriggerInfoAndBeforeStart{}
inputs := Inputs{TriggerIndex: triggerIndex}
manualTriggers := &ManualTriggers{ManualCronTrigger: cronSvc}

beforeStart := makeBeforeStartNonInteractive(holder, inputs, func() *ManualTriggers {
return manualTriggers
})

triggerSub := []*pb.TriggerSubscription{{Id: "cron-trigger@1.0.0"}}
beforeStart(ctx, simulator.RunnerConfig{}, nil, nil, triggerSub)
require.NotNil(t, holder.TriggerFunc)

done := make(chan error, 1)
go func() { done <- holder.TriggerFunc() }()

select {
case err := <-done:
require.NoError(t, err)
case <-time.After(3 * time.Second):
t.Fatal("TriggerFunc blocked waiting for cron schedule; skipWaitSignal must be sent before ManualTrigger is called")
}
}

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

Expand Down
Loading