-
Notifications
You must be signed in to change notification settings - Fork 67
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: allow users to stop a running test #2367
Changes from all commits
76fedd9
d4955bd
054235d
405fad4
24dbe49
435745f
d12b71a
f6ffa52
16cc9ea
b7d4978
ab387f9
8a1939a
687cbfb
3c5f243
2fa05e7
68efd30
2464636
6ffc2dc
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,7 +13,7 @@ exporters: | |
loglevel: debug | ||
|
||
otlp/1: | ||
endpoint: host.docker.internal:21321 | ||
endpoint: tracetest:21321 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this was probablly a leftover from someone doing docker tests, it should point to the internal url There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Question: is this file intended just for local testing, or do we use it in some pipelines? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. local testing. It's used when you run the |
||
tls: | ||
insecure: true | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,3 +4,12 @@ spec: | |
name: OpenTelemetry Collector | ||
type: otlp | ||
isdefault: true | ||
--- | ||
type: Demo | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. addin a default demo locally eased the testing process |
||
spec: | ||
name: "Pokeshop" | ||
enabled: true | ||
type: pokeshop | ||
pokeshop: | ||
grpcEndpoint: demo-api:8082 | ||
httpEndpoint: http://demo-api:8081 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
#!/bin/bash | ||
PORT=$1 | ||
|
||
CONDITION='nc -z -w 1 localhost '$PORT' > /dev/null 2>&1' | ||
IF_TRUE='echo "port '$PORT' ready"' | ||
IF_FALSE='echo "port '$PORT' not available, retry"' | ||
|
||
set -ex | ||
bash -c "until ${CONDITION}; do ${IF_FALSE}; sleep 1; done; ${IF_TRUE}" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
package executor | ||
|
||
import ( | ||
"context" | ||
"log" | ||
|
||
"github.com/kubeshop/tracetest/server/id" | ||
"github.com/kubeshop/tracetest/server/model" | ||
"github.com/kubeshop/tracetest/server/model/events" | ||
"github.com/kubeshop/tracetest/server/subscription" | ||
) | ||
|
||
type StopRequest struct { | ||
TestID id.ID | ||
RunID int | ||
} | ||
|
||
func (sr StopRequest) ResourceID() string { | ||
runID := (model.Run{ID: sr.RunID, TestID: sr.TestID}).ResourceID() | ||
return runID + "/stop" | ||
} | ||
|
||
func (r persistentRunner) listenForStopRequests(ctx context.Context, cancelCtx context.CancelFunc, run model.Run) { | ||
sfn := subscription.NewSubscriberFunction(func(m subscription.Message) error { | ||
stopRequest, ok := m.Content.(StopRequest) | ||
if !ok { | ||
return nil | ||
} | ||
|
||
ctx, _ := r.tracer.Start(ctx, "User Requested Stop Run") | ||
// refresh data from DB to make sure we have the latest possible data before updating | ||
run, err := r.runs.GetRun(ctx, stopRequest.TestID, stopRequest.RunID) | ||
if err != nil { | ||
log.Printf("[TracePoller] Test %s Run %d: fail to get test run data: %s \n", stopRequest.TestID, stopRequest.RunID, err.Error()) | ||
return err | ||
} | ||
|
||
run = run.Stopped() | ||
r.handleDBError(run, r.updater.Update(ctx, run)) | ||
|
||
evt := events.TraceStoppedInfo(stopRequest.TestID, stopRequest.RunID) | ||
err = r.eventEmitter.Emit(ctx, evt) | ||
if err != nil { | ||
log.Printf("[TracePoller] Test %s Run %d: fail to emit TraceStoppedInfo event: %s \n", stopRequest.TestID, stopRequest.RunID, err.Error()) | ||
return err | ||
} | ||
|
||
cancelCtx() | ||
|
||
return nil | ||
}) | ||
|
||
r.subscriptionManager.Subscribe((StopRequest{run.TestID, run.ID}).ResourceID(), sfn) | ||
} |
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Something to think about in another PR: is there a way to add a unit test that checks if the runner behaved correctly on a cancel case? |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -76,12 +76,11 @@ type persistentRunner struct { | |
} | ||
|
||
type execReq struct { | ||
ctx context.Context | ||
test model.Test | ||
run model.Run | ||
subscriptionManager *subscription.Manager | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this var was unused |
||
Headers propagation.MapCarrier | ||
executor expression.Executor | ||
ctx context.Context | ||
test model.Test | ||
run model.Run | ||
Headers propagation.MapCarrier | ||
executor expression.Executor | ||
} | ||
|
||
func (r persistentRunner) handleDBError(run model.Run, err error) { | ||
|
@@ -133,14 +132,18 @@ func getNewCtx(ctx context.Context) context.Context { | |
} | ||
|
||
func (r persistentRunner) Run(ctx context.Context, test model.Test, metadata model.RunMetadata, environment model.Environment) model.Run { | ||
ctx = getNewCtx(ctx) | ||
ctx, cancelCtx := context.WithCancel( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we want to make the context cancellable, since it isn't by default |
||
getNewCtx(ctx), | ||
) | ||
|
||
run := model.NewRun() | ||
run.Metadata = metadata | ||
run.Environment = environment | ||
run, err := r.runs.CreateRun(ctx, test, run) | ||
r.handleDBError(run, err) | ||
|
||
r.listenForStopRequests(ctx, cancelCtx, run) | ||
|
||
ds := []expression.DataStore{expression.EnvironmentDataStore{ | ||
Values: environment.Values, | ||
}} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -133,6 +133,13 @@ func (tp tracePoller) enqueueJob(job PollingRequest) { | |
} | ||
|
||
func (tp tracePoller) processJob(job PollingRequest) { | ||
select { | ||
default: | ||
case <-job.ctx.Done(): | ||
log.Printf("[TracePoller] Context cancelled.") | ||
return | ||
} | ||
|
||
if job.IsFirstRequest() { | ||
err := tp.eventEmitter.Emit(job.ctx, events.TracePollingStart(job.test.ID, job.run.ID)) | ||
if err != nil { | ||
|
@@ -191,7 +198,13 @@ func (tp tracePoller) runAssertions(job PollingRequest) { | |
func (tp tracePoller) handleTraceDBError(job PollingRequest, err error) (bool, string) { | ||
run := job.run | ||
|
||
pp := *tp.ppGetter.GetDefault(job.ctx).Periodic | ||
profile := tp.ppGetter.GetDefault(job.ctx) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. sometimes the context can get cancelled in the middle of this func call, causing a nil pointer panic. This new approach handles the case more gracefully |
||
if profile.Periodic == nil { | ||
log.Println("[TracePoller] cannot get polling profile.") | ||
return true, "Cannot get polling profile" | ||
} | ||
|
||
pp := *profile.Periodic | ||
|
||
// Edge case: the trace still not avaiable on Data Store during polling | ||
if errors.Is(err, connection.ErrTraceNotFound) && time.Since(run.ServiceTriggeredAt) < pp.TimeoutDuration() { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
all test endpoints are actually
/tests
with a trailings