From 1400ea6e1291a3c50a2d46e36ff8e96026eb504e Mon Sep 17 00:00:00 2001 From: Jordan Stephens Date: Wed, 24 Sep 2025 14:10:12 -0700 Subject: [PATCH] fix finding urls in deployment output --- tools/testing/deployer/deployer.go | 47 ++++++++++++---------- tools/testing/deployer/deployer_test.go | 52 +++++++++++++++++++++++++ 2 files changed, 78 insertions(+), 21 deletions(-) create mode 100644 tools/testing/deployer/deployer_test.go diff --git a/tools/testing/deployer/deployer.go b/tools/testing/deployer/deployer.go index 74efd691..f7386dca 100644 --- a/tools/testing/deployer/deployer.go +++ b/tools/testing/deployer/deployer.go @@ -120,7 +120,27 @@ func (d *CliDeployer) Deploy(ctx context.Context) error { return err } -var urlRegex = regexp.MustCompile(`will be available at:\s*.*?(https://[^\s]+)`) +var urlRegex = regexp.MustCompile(`DEPLOYMENT_COMPLETED\s*([^\s]+)`) +var internalURLRegex = regexp.MustCompile(`\.internal:\d+$`) + +func findUrlsInOutput(output string) []string { + var urls []string + match := urlRegex.FindAllStringSubmatch(output, -1) + for _, m := range match { + if m[1] == "" { + continue + } + if internalURLRegex.MatchString(m[1]) { + log.Printf("Skipping internal URL %v", m[1]) + continue + } + // Check if the URL starts with a scheme (http, https, etc.) + if strings.HasPrefix(m[1], "https://") { + urls = append(urls, m[1]) + } + } + return urls +} func (d *CliDeployer) RunDeployTest(ctx context.Context, t test.TestInfo) (*test.ItemResult, error) { log := d.Logger @@ -155,22 +175,6 @@ func (d *CliDeployer) RunDeployTest(ctx context.Context, t test.TestInfo) (*test }, } - d.RunCommand(cmdCtx, func(cmd *exec.Cmd) { - if t.Stdout != nil { - cmd.Stdout = io.MultiWriter(&d.Stdout, t.Stdout, detector) - } else { - cmd.Stdout = io.MultiWriter(&d.Stdout, detector) - } - if t.Stderr != nil { - cmd.Stderr = io.MultiWriter(&d.Stderr, t.Stderr, detector) - } else { - cmd.Stderr = io.MultiWriter(&d.Stderr, detector) - } - cmd.Cancel = func() error { - return cmd.Process.Signal(os.Interrupt) // Use interrupt signal to stop the command when context is cancelled - } - }, "defang", "-C", "/tmp/", "compose", "down", "--detach") - d.HasDeployed = true start := time.Now() cmd, err := d.RunCommand(cmdCtx, func(cmd *exec.Cmd) { @@ -204,10 +208,11 @@ func (d *CliDeployer) RunDeployTest(ctx context.Context, t test.TestInfo) (*test result.DeploySucceeded = cmd.ProcessState.Success() } - var urls []string - match := urlRegex.FindAllStringSubmatch(d.Stdout.String(), -1) - for _, m := range match { - urls = append(urls, m[1]) + urls := findUrlsInOutput(d.Stdout.String()) + if len(urls) == 0 { + result.Message = "No service URLs found in deployment output" + log.Printf(result.Message) + return result, fmt.Errorf(result.Message) } result.TotalServices = len(urls) diff --git a/tools/testing/deployer/deployer_test.go b/tools/testing/deployer/deployer_test.go new file mode 100644 index 00000000..994aacb7 --- /dev/null +++ b/tools/testing/deployer/deployer_test.go @@ -0,0 +1,52 @@ +package deployer + +import ( + "slices" + "testing" +) + +func Test_findUrlsInOutput(t *testing.T) { + tests := []struct { + name string + out string + want []string + }{ + { + name: "single url", + out: "some log\nDEPLOYMENT_COMPLETED\thttps://my-service.defang.io\nmore log", + want: []string{"https://my-service.defang.io"}, + }, + { + name: "multiple urls", + out: "log\nDEPLOYMENT_COMPLETED\thttps://service1.defang.io\nlog\nDEPLOYMENT_COMPLETED\thttps://service2.defang.io\nend", + want: []string{"https://service1.defang.io", "https://service2.defang.io"}, + }, + { + name: "no urls", + out: "just some logs without urls", + want: nil, + }, + { + name: "internal url ignored", + out: "log\nDEPLOYMENT_COMPLETED\tservice.internal:8080\nend", + want: nil, + }, + { + name: "url without scheme", + out: "log\nDEPLOYMENT_COMPLETED\tmy-service.defang.io\nend", + want: nil, + }, + { + name: "some other string", + out: "log\nDEPLOYMENT_COMPLETED\tjust-a-string\nend", + want: nil, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := findUrlsInOutput(tt.out); !slices.Equal(got, tt.want) { + t.Errorf("findUrlsInOutput() = %v, want %v", got, tt.want) + } + }) + } +}