Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -270,11 +270,8 @@ default_source_release="$(HELMFILE_ENV="$default_source_environment_name" \
--selector name=llm-request-router \
list --skip-charts --output json)"
default_source_chart="$(jq -r '.[0].chart // ""' <<<"$default_source_release")"
default_source_version="$(jq -r '.[0].version // ""' <<<"$default_source_release")"
test "$default_source_chart" = 'nvcf/helm-nvcf-llm-request-router' ||
fail "expected default request-router chart, got ${default_source_chart:-missing}"
test "$default_source_version" = '1.12.1' ||
fail "expected default request-router version 1.12.1, got ${default_source_version:-missing}"

default_source_values="$work_dir/default-source-router-values.yaml"
HELMFILE_ENV="$default_source_environment_name" \
Expand Down
4 changes: 3 additions & 1 deletion tests/bdd/PLAN.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ They preserve the real command output for subsequent assertions.

| Step | Command |
|------|---------|
| `When I successfully observe WatchStargates at {string} with TLS authority {string} using CA secret {string} in namespace {string} and context {string} for {string} seconds` | Reads the named CA certificate from the explicit Kubernetes secret and context, runs the public `WatchStargates` gRPC method against the visible endpoint and TLS authority, and requires a streamed response before accepting the expected client deadline. |
| `When I successfully observe WatchStargates at {string} with TLS authority {string} using CA secret {string} in namespace {string} and context {string} for {string} seconds` | Reads the named CA certificate from the explicit Kubernetes secret and context, runs the public `WatchStargates` gRPC method against the visible endpoint and TLS authority with W3C trace context propagated through a generated `traceparent` header, and requires a streamed response before accepting the expected client deadline. |

#### Function lifecycle command adapters

Expand Down Expand Up @@ -169,6 +169,8 @@ original order. Repeated options and empty values are preserved.
| `Then the command should fail` | Requires a non-zero last-run exit code. It does not accept a runner error that prevented command execution and never records the failed command in the successful-command cache. |
| `Then the command output should contain {string}` | Substring match on combined stdout + stderr. The interpolated value must not be empty or whitespace-only. |
| `Then the command output should not contain {string}` | Negative substring match. The interpolated value must not be empty or whitespace-only. |
| `Then the command output should not match {string}` | Negative Go regular-expression match on combined stdout + stderr. The interpolated pattern must be non-empty and compile. Use it for shapes a fixed string cannot express, such as a dashed pod-IP hostname alias. |
| `Then the command output should have exactly {string} distinct matches of {string}` | Counts unique substrings matched by the interpolated Go regular expression in combined stdout + stderr. Repeated occurrences of the same substring count once. |
| `Then the command output should contain all:` (table) | Requires a `text` header and one or more strings. Every interpolated string must be non-empty and appear in combined stdout + stderr. |
| `Then the command output should contain one of:` (table) | Requires a `text` header and one or more strings. Every interpolated candidate must be non-empty, and at least one must appear in combined stdout + stderr. |
| `Then file {string} should exist` | |
Expand Down
29 changes: 29 additions & 0 deletions tests/bdd/dsl/registration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"os"
"os/exec"
"path/filepath"
"regexp"
"strings"
"testing"
)
Expand Down Expand Up @@ -118,6 +119,34 @@ exit 1
}
}

func TestObserveWatchStargatesScriptSendsW3CTraceContext(t *testing.T) {
fakeBin := t.TempDir()
writeExecutable(t, filepath.Join(fakeBin, "kubectl"), "#!/bin/sh\nprintf 'dGVzdC1jYQ=='\n")
writeExecutable(t, filepath.Join(fakeBin, "grpcurl"), `#!/bin/sh
printf '{\n "stargates": []\n}\n'
for arg in "$@"; do
case "$arg" in
traceparent:*) printf 'observed %s\n' "$arg" >&2 ;;
esac
done
sleep 1
printf 'ERROR:\n Code: DeadlineExceeded\n Message: context deadline exceeded\n' >&2
exit 1
`)

output, err := runRegistrationScript(t, fakeBin, "observe-watch-stargates.sh", "127.0.0.1:50071", "router.nvcf.svc", "tls", "nvcf", "context", "1")
if err != nil {
t.Fatalf("observe WatchStargates: %v\n%s", err, output)
}
traceparent := regexp.MustCompile(`observed traceparent: (\S+)`).FindStringSubmatch(output)
if traceparent == nil {
t.Fatalf("output = %q, want an observed traceparent header", output)
}
if !regexp.MustCompile(`^00-[0-9a-f]{32}-[0-9a-f]{16}-01$`).MatchString(traceparent[1]) {
t.Fatalf("traceparent = %q, want a valid W3C trace context value", traceparent[1])
}
}

func TestObserveWatchStargatesScriptRejectsImmediateProductDeadline(t *testing.T) {
fakeBin := t.TempDir()
writeExecutable(t, filepath.Join(fakeBin, "kubectl"), "#!/bin/sh\nprintf 'dGVzdC1jYQ=='\n")
Expand Down
39 changes: 39 additions & 0 deletions tests/bdd/dsl/textsearch.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"os"
"path"
"path/filepath"
"regexp"
"strings"
)

Expand Down Expand Up @@ -193,3 +194,41 @@ func FilesDoNotContain(root string, needles []string) error {
}
return nil
}

// OutputMatches reports whether the interpolated regular expression
// matches anywhere in text.
func OutputMatches(text, pattern string) (bool, error) {
expression, err := compileOutputPattern(pattern)
if err != nil {
return false, err
}
return expression.MatchString(text), nil
}

// DistinctOutputMatches counts the unique substrings of text matched by
// the interpolated regular expression. Repeated occurrences of the same
// substring count once, so a feature can assert how many distinct
// identities an observation advertises.
func DistinctOutputMatches(text, pattern string) (int, error) {
expression, err := compileOutputPattern(pattern)
if err != nil {
return 0, err
}
unique := make(map[string]struct{})
for _, match := range expression.FindAllString(text, -1) {
unique[match] = struct{}{}
}
return len(unique), nil
}

func compileOutputPattern(pattern string) (*regexp.Regexp, error) {
resolved := strings.TrimSpace(Interpolate(pattern))
if resolved == "" {
return nil, fmt.Errorf("expected output pattern resolves to an empty value")
}
expression, err := regexp.Compile(resolved)
if err != nil {
return nil, fmt.Errorf("invalid output pattern %q: %w", resolved, err)
}
return expression, nil
}
39 changes: 39 additions & 0 deletions tests/bdd/dsl/textsearch_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,3 +103,42 @@ func writeRenderedManifest(t *testing.T, root, relativePath, body string) {
t.Fatalf("write rendered manifest: %v", err)
}
}

func TestOutputMatchesDetectsDashedPodIPAlias(t *testing.T) {
const pattern = `([0-9]{1,3}-){3}[0-9]{1,3}\.`
matched, err := OutputMatches("10-42-0-7.llm-request-router-region-b-headless.nvcf.svc.cluster.local", pattern)
if err != nil {
t.Fatalf("match output: %v", err)
}
if !matched {
t.Fatal("expected dashed pod-IP alias to match")
}

matched, err = OutputMatches("llm-request-router-region-b-0.nvcf.svc.cluster.local", pattern)
if err != nil {
t.Fatalf("match output: %v", err)
}
if matched {
t.Fatal("expected a stable StatefulSet identity not to match")
}
}

func TestDistinctOutputMatchesCountsUniqueIdentities(t *testing.T) {
output := "llm-request-router-region-b-0 llm-request-router-region-b-1 llm-request-router-region-b-0"
got, err := DistinctOutputMatches(output, "llm-request-router-region-b-[0-9]+")
if err != nil {
t.Fatalf("count distinct matches: %v", err)
}
if got != 2 {
t.Fatalf("distinct matches = %d, want 2", got)
}
}

func TestOutputPatternRejectsEmptyAndInvalidPatterns(t *testing.T) {
if _, err := OutputMatches("output", " "); err == nil {
t.Fatal("expected empty pattern error")
}
if _, err := DistinctOutputMatches("output", "llm-request-router-["); err == nil {
t.Fatal("expected invalid pattern error")
}
}
Loading
Loading