Skip to content
Open
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
f7450e6
fix flaky E2E tests failing
JoshVanL Mar 17, 2026
228d6c6
Swap sleeps for eventuallys
JoshVanL Mar 17, 2026
f3ab369
Fix kill group in MacOS
JoshVanL Mar 17, 2026
15895d3
Fix more flakes
JoshVanL Mar 17, 2026
ba47e3c
Wait for ports free
JoshVanL Mar 17, 2026
26f71b7
Fix t.Context being cancelled
JoshVanL Mar 18, 2026
1d86cca
Adds more eventually waiting
JoshVanL Mar 19, 2026
9f94ce6
Add more waits
JoshVanL Mar 19, 2026
41dfb51
More cleanup
JoshVanL Mar 19, 2026
f60d889
Wait for log context
JoshVanL Mar 19, 2026
e1e5721
Try again
JoshVanL Mar 19, 2026
1e94ae2
wait for app healthy
JoshVanL Mar 19, 2026
8f7adb2
Remove fragile line count
JoshVanL Mar 20, 2026
22b244c
more
JoshVanL Mar 20, 2026
0fa85f7
more fixes
JoshVanL Mar 23, 2026
5926233
more
JoshVanL Mar 23, 2026
5a3f145
Fix template test timeouts by cancelling context after stop
JoshVanL Mar 23, 2026
af158f7
again
JoshVanL Mar 23, 2026
14d8edc
again
JoshVanL Mar 23, 2026
87ce58d
more eventually
JoshVanL Mar 23, 2026
e238466
again
JoshVanL Mar 24, 2026
d2628e3
more
JoshVanL Mar 24, 2026
5f1a0fb
again
JoshVanL Mar 24, 2026
8d27c4e
Try reuse install
JoshVanL Mar 24, 2026
7e73e66
cleanup handlers
JoshVanL Mar 24, 2026
db9b026
Merge branch 'master' into fix-e2e-flakes
JoshVanL Apr 1, 2026
47a3d79
Wait for app to be healthy
JoshVanL Apr 1, 2026
b5bedf0
isSlim
JoshVanL Apr 1, 2026
762db74
Increase timeout
JoshVanL Apr 1, 2026
594dc10
Do full uninstalls
JoshVanL Apr 1, 2026
27ef36a
uninstall where needed
JoshVanL Apr 1, 2026
2981fc3
retry
JoshVanL Apr 2, 2026
6d549c7
Increase timeouts
JoshVanL Apr 2, 2026
4b595ae
Prevent hang on wait for shutdown
JoshVanL Apr 2, 2026
1a32823
Increase timeouts
JoshVanL Apr 2, 2026
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
7 changes: 7 additions & 0 deletions cmd/run_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,13 @@ func killProcessGroup(process *os.Process) error {
if errors.Is(err, syscall.ESRCH) {
return nil // process group gone
}
// EPERM can occur on macOS when the process group is in a
// dying/zombie state. Keep polling rather than returning an
// error so we can fall through to SIGKILL if needed.
if errors.Is(err, syscall.EPERM) {
time.Sleep(100 * time.Millisecond)
continue
}
return fmt.Errorf("failed to check status of process group %d: %w", pgid, err)
}
// Grace period elapsed — force kill.
Expand Down
43 changes: 27 additions & 16 deletions pkg/version/version_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,15 @@ limitations under the License.
package version

import (
"context"
"fmt"
"net"
"net/http"
"testing"
"time"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestGetVersionsGithub(t *testing.T) {
Expand Down Expand Up @@ -209,7 +212,7 @@ func TestGetVersionsGithub(t *testing.T) {
},
}
m := http.NewServeMux()
s := http.Server{Addr: ":12345", Handler: m, ReadHeaderTimeout: time.Duration(5) * time.Second}
s := http.Server{Handler: m, ReadHeaderTimeout: time.Duration(5) * time.Second}

for _, tc := range tests {
body := tc.ResponseBody
Expand All @@ -218,13 +221,19 @@ func TestGetVersionsGithub(t *testing.T) {
})
}

go func() {
s.ListenAndServe()
}()
ln, err := net.Listen("tcp", ":0")
require.NoError(t, err)
t.Cleanup(func() {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
s.Shutdown(ctx)
})
go func() { s.Serve(ln) }()
addr := fmt.Sprintf("http://localhost:%d", ln.Addr().(*net.TCPAddr).Port)

for _, tc := range tests {
t.Run(tc.Name, func(t *testing.T) {
version, err := GetLatestReleaseGithub("http://localhost:12345" + tc.Path)
version, err := GetLatestReleaseGithub(addr + tc.Path)
assert.Equal(t, tc.ExpectedVer, version)
if tc.ExpectedErr != "" {
assert.EqualError(t, err, tc.ExpectedErr)
Expand All @@ -233,18 +242,16 @@ func TestGetVersionsGithub(t *testing.T) {
}

t.Run("error on 404", func(t *testing.T) {
version, err := GetLatestReleaseGithub("http://localhost:12345/non-existant/path")
version, err := GetLatestReleaseGithub(addr + "/non-existant/path")
assert.Equal(t, "", version)
assert.EqualError(t, err, "http://localhost:12345/non-existant/path - 404 Not Found")
assert.EqualError(t, err, addr+"/non-existant/path - 404 Not Found")
})

t.Run("error on bad addr", func(t *testing.T) {
version, err := GetLatestReleaseGithub("http://a.super.non.existant.domain/")
assert.Equal(t, "", version)
assert.Error(t, err)
})

s.Shutdown(t.Context())
}

func TestGetVersionsHelm(t *testing.T) {
Expand Down Expand Up @@ -318,7 +325,7 @@ entries:
},
}
m := http.NewServeMux()
s := http.Server{Addr: ":12346", Handler: m, ReadHeaderTimeout: time.Duration(5) * time.Second}
s := http.Server{Handler: m, ReadHeaderTimeout: time.Duration(5) * time.Second}

for _, tc := range tests {
body := tc.ResponseBody
Expand All @@ -327,19 +334,23 @@ entries:
})
}

go func() {
s.ListenAndServe()
}()
ln, err := net.Listen("tcp", ":0")
require.NoError(t, err)
t.Cleanup(func() {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
s.Shutdown(ctx)
})
go func() { s.Serve(ln) }()
addr := fmt.Sprintf("http://localhost:%d", ln.Addr().(*net.TCPAddr).Port)

for _, tc := range tests {
t.Run(tc.Name, func(t *testing.T) {
version, err := GetLatestReleaseHelmChart("http://localhost:12346" + tc.Path)
version, err := GetLatestReleaseHelmChart(addr + tc.Path)
assert.Equal(t, tc.ExpectedVer, version)
if tc.ExpectedErr != "" {
assert.EqualError(t, err, tc.ExpectedErr)
}
})
}

s.Shutdown(t.Context())
}
8 changes: 6 additions & 2 deletions tests/e2e/standalone/list_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,13 @@ func TestStandaloneList(t *testing.T) {
cmd := exec.Command(daprdPath, "--app-id", "daprd_e2e_list", "--dapr-http-port", "3555", "--dapr-grpc-port", "4555", "--app-port", "0")
cmd.Start()

output, err := cmdList("")
// Wait for daprd to register and appear in the list.
var output string
require.Eventually(t, func() bool {
output, err = cmdList("")
return err == nil && !strings.Contains(output, "No Dapr instances found")
}, 30*time.Second, time.Second, "daprd instance did not appear in list")
t.Log(output)
require.NoError(t, err, "dapr list failed with daprd instance")
listOutputCheck(t, output, false)

// TODO: remove this condition when `dapr stop` starts working for Windows.
Expand Down
48 changes: 36 additions & 12 deletions tests/e2e/standalone/run_template_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ package standalone_test
import (
"fmt"
"io/ioutil"
"net"
"path/filepath"
"strings"
"testing"
Expand All @@ -29,6 +30,23 @@ import (
"github.com/stretchr/testify/require"
)

// waitForPortsFree polls until all given ports are available for binding.
// This prevents port contention between sequential subtests that use
// hardcoded ports.
func waitForPortsFree(t *testing.T, ports ...int) {
t.Helper()
require.Eventually(t, func() bool {
for _, port := range ports {
ln, err := net.Listen("tcp", fmt.Sprintf("127.0.0.1:%d", port))
if err != nil {
return false
}
ln.Close()
}
return true
}, 30*time.Second, time.Second, "ports %v not available in time", ports)
}

type AppTestOutput struct {
appID string
appLogContents []string
Expand Down Expand Up @@ -59,18 +77,19 @@ func TestRunWithTemplateFile(t *testing.T) {
"-f", runFilePath,
}

waitForPortsFree(t, 3510, 3511)
outputCh := make(chan string)
go func() {
output, _ := cmdRun("", args...)
t.Logf("%s", output)
outputCh <- output
}()
time.Sleep(time.Second * 10)
time.Sleep(10 * time.Second)
cmdStopWithRunTemplate(runFilePath)
var output string
select {
case output = <-outputCh:
case <-time.After(25 * time.Second):
case <-time.After(30 * time.Second):
t.Fatal("timed out waiting for run command to finish")
}

Expand Down Expand Up @@ -122,18 +141,19 @@ func TestRunWithTemplateFile(t *testing.T) {
"-f", runFilePath,
}

waitForPortsFree(t, 3510, 3511)
outputCh := make(chan string)
go func() {
output, _ := cmdRun("", args...)
t.Logf("%s", output)
outputCh <- output
}()
time.Sleep(time.Second * 10)
time.Sleep(10 * time.Second)
cmdStopWithRunTemplate(runFilePath)
var output string
select {
case output = <-outputCh:
case <-time.After(time.Second * 10):
case <-time.After(30 * time.Second):
t.Fatal("timed out waiting for run command to finish")
}

Expand Down Expand Up @@ -191,18 +211,19 @@ func TestRunWithTemplateFile(t *testing.T) {
args := []string{
"-f", runFilePath,
}
waitForPortsFree(t, 3510, 3511)
outputCh := make(chan string)
go func() {
output, _ := cmdRun("", args...)
t.Logf("%s", output)
outputCh <- output
}()
time.Sleep(time.Second * 10)
time.Sleep(10 * time.Second)
cmdStopWithRunTemplate(runFilePath)
var output string
select {
case output = <-outputCh:
case <-time.After(25 * time.Second):
case <-time.After(30 * time.Second):
t.Fatal("timed out waiting for run command to finish")
}

Expand Down Expand Up @@ -254,18 +275,19 @@ func TestRunWithTemplateFile(t *testing.T) {
args := []string{
"-f", runFilePath,
}
waitForPortsFree(t, 3510, 3511)
outputCh := make(chan string)
go func() {
output, _ := cmdRun("", args...)
t.Logf("%s", output)
outputCh <- output
}()
time.Sleep(time.Second * 10)
time.Sleep(10 * time.Second)
cmdStopWithRunTemplate(runFilePath)
var output string
select {
case output = <-outputCh:
case <-time.After(25 * time.Second):
case <-time.After(30 * time.Second):
t.Fatal("timed out waiting for run command to finish")
}

Expand Down Expand Up @@ -318,18 +340,19 @@ func TestRunWithTemplateFile(t *testing.T) {
args := []string{
"-f", runFilePath,
}
waitForPortsFree(t, 3510, 3511)
outputCh := make(chan string)
go func() {
output, _ := cmdRun("", args...)
t.Logf("%s", output)
outputCh <- output
}()
time.Sleep(time.Second * 10)
time.Sleep(10 * time.Second)
cmdStopWithRunTemplate(runFilePath)
var output string
select {
case output = <-outputCh:
case <-time.After(25 * time.Second):
case <-time.After(30 * time.Second):
t.Fatal("timed out waiting for run command to finish")
}

Expand Down Expand Up @@ -378,18 +401,19 @@ func TestRunWithTemplateFile(t *testing.T) {
args := []string{
"-f", runFilePath,
}
waitForPortsFree(t, 3510, 3511)
outputCh := make(chan string)
go func() {
output, _ := cmdRun("", args...)
t.Logf("%s", output)
outputCh <- output
}()
time.Sleep(time.Second * 10)
time.Sleep(10 * time.Second)
cmdStopWithRunTemplate(runFilePath)
var output string
select {
case output = <-outputCh:
case <-time.After(25 * time.Second):
case <-time.After(30 * time.Second):
t.Fatal("timed out waiting for run command to finish")
}

Expand Down
20 changes: 12 additions & 8 deletions tests/e2e/standalone/stop_with_run_template_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ func TestStopAppsStartedWithRunTemplate(t *testing.T) {
cleanUpLogs()
})
go ensureAllAppsStartedWithRunTemplate(t)
time.Sleep(10 * time.Second)
cliPID := getCLIPID(t)
// Assert dapr list contains template name
assertTemplateListOutput(t, "test_dapr_template")
Expand All @@ -58,7 +57,6 @@ func TestStopAppsStartedWithRunTemplate(t *testing.T) {
cleanUpLogs()
})
go ensureAllAppsStartedWithRunTemplate(t)
time.Sleep(10 * time.Second)
cliPID := getCLIPID(t)
output, err := cmdStopWithRunTemplate("../testdata/run-template-files")
assert.NoError(t, err, "failed to stop apps started with run template")
Expand Down Expand Up @@ -86,7 +84,6 @@ func TestStopAppsStartedWithRunTemplate(t *testing.T) {
cleanUpLogs()
})
go ensureAllAppsStartedWithRunTemplate(t)
time.Sleep(10 * time.Second)
cliPID := getCLIPID(t)
output, err := cmdStopWithAppID("emit-metrics", "processor")
assert.NoError(t, err, "failed to stop apps started with run template")
Expand Down Expand Up @@ -124,11 +121,18 @@ func tearDownTestSetup(t *testing.T) {
}

func getCLIPID(t *testing.T) string {
output, err := cmdList("json")
require.NoError(t, err, "failed to list apps")
result := []map[string]interface{}{}
err = json.Unmarshal([]byte(output), &result)
assert.Equal(t, 2, len(result))
var result []map[string]interface{}
require.Eventually(t, func() bool {
output, err := cmdList("json")
if err != nil {
return false
}
result = nil
if err := json.Unmarshal([]byte(output), &result); err != nil {
return false
}
return len(result) == 2
}, 30*time.Second, time.Second, "expected 2 apps in list")
return fmt.Sprintf("%v", result[0]["cliPid"])
}

Expand Down
5 changes: 3 additions & 2 deletions tests/e2e/standalone/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,18 +118,19 @@ func executeAgainstRunningDapr(t *testing.T, f func(), daprArgs ...string) {

err := cmd.Wait()
hasAppCommand := !strings.Contains(daprOutput, "WARNING: no application command found")
terminatedBySignal := strings.Contains(daprOutput, "terminated signal received: shutting down")
if err != nil {
var exitErr *exec.ExitError
if errors.As(err, &exitErr) && exitErr.ExitCode() == 1 &&
strings.Contains(daprOutput, "Exited Dapr successfully") &&
(!hasAppCommand || strings.Contains(daprOutput, "Exited App successfully")) {
(!hasAppCommand || terminatedBySignal || strings.Contains(daprOutput, "Exited App successfully")) {
err = nil
}
}
require.NoError(t, err, "dapr didn't exit cleanly")
assert.NotContains(t, daprOutput, "The App process exited with error code: exit status", "Stop command should have been called before the app had a chance to exit")
assert.Contains(t, daprOutput, "Exited Dapr successfully")
if hasAppCommand {
if hasAppCommand && !terminatedBySignal {
assert.Contains(t, daprOutput, "Exited App successfully")
}
}
Expand Down
Loading