Sitelet https://github.com/kubernetes/kops/commit/58c37fb7351340eb77728f01358d49cbf993b2f4
Skip to content

Commit 58c37fb

Browse files
committed
e2e: test the PR's own channels, not master's
In e2e, `kops create cluster --channel=alpha` reads the channel from the kops master branch, so a PR's edits to channels/alpha or channels/stable are never exercised by its own e2e jobs. When kops is built from the PR checkout, the deployer now rewrites --channel to a file:// path into that checkout's channels/ directory (defaulting to alpha when --channel is unset), so the build uses the PR's channels. Downloaded release/marker binaries don't match the checkout and keep using master's channels.
1 parent a84a7ac commit 58c37fb

2 files changed

Lines changed: 102 additions & 0 deletions

File tree

‎tests/e2e/kubetest2-kops/deployer/up.go‎

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"fmt"
2323
"os"
2424
osexec "os/exec"
25+
"path/filepath"
2526
"strconv"
2627
"strings"
2728
"time"
@@ -233,6 +234,11 @@ func (d *deployer) createCluster(zones []string, adminAccess string, yes bool) e
233234
}
234235
args = append(args, createArgs...)
235236
}
237+
if builtFromKopsRoot(d.KopsBinaryPath, d.KopsRoot) {
238+
// A from-source build's channels/ match the binary, so resolve --channel (including the
239+
// default when unset) against them via file:// to test the PR's own channels, not master's.
240+
args = localChannelArgs(args, d.KopsRoot)
241+
}
236242
args = appendIfUnset(args, "--admin-access", adminAccess)
237243

238244
// Dont set --control-plane-count if either --control-plane-count or --master-count
@@ -523,6 +529,43 @@ func extractFlagValues(args, flag string) []string {
523529
return values
524530
}
525531

532+
// builtFromKopsRoot reports whether the kops binary under test was built from the repo checkout at
533+
// kopsRoot (its path lies inside that tree). Scenario scripts pass --kops-root even when running a
534+
// downloaded release/marker binary, so only a binary under the checkout is guaranteed to match the
535+
// checkout's channels/ files.
536+
func builtFromKopsRoot(kopsBinaryPath, kopsRoot string) bool {
537+
if kopsBinaryPath == "" || kopsRoot == "" {
538+
return false
539+
}
540+
rel, err := filepath.Rel(kopsRoot, kopsBinaryPath)
541+
if err != nil {
542+
return false
543+
}
544+
return filepath.IsLocal(rel)
545+
}
546+
547+
// localChannelArgs points --channel at the repo checkout's channels/ via a file:// URL, so a
548+
// from-source build exercises the PR's own channels instead of the master branch copies. The
549+
// channel value is rewritten; when --channel is absent, alpha is added as the e2e default.
550+
func localChannelArgs(args []string, kopsRoot string) []string {
551+
for i, a := range args {
552+
if v, ok := strings.CutPrefix(a, "--channel="); ok {
553+
args[i] = "--channel=" + localChannelURL(kopsRoot, v)
554+
return args
555+
}
556+
if a == "--channel" && i+1 < len(args) {
557+
args[i+1] = localChannelURL(kopsRoot, args[i+1])
558+
return args
559+
}
560+
}
561+
return append(args, "--channel="+localChannelURL(kopsRoot, "alpha"))
562+
}
563+
564+
// localChannelURL returns the file:// URL for channel name under the checkout's channels/ dir.
565+
func localChannelURL(kopsRoot, name string) string {
566+
return "file://" + filepath.ToSlash(filepath.Join(kopsRoot, "channels", name))
567+
}
568+
526569
// prowJobLabel returns a "key=value" cloud-label fragment recording the prow
527570
// JOB_NAME, sanitized for the target cloud provider. Returns ok=false when
528571
// jobName is empty or the cloud provider does not surface kops cloudLabels.

‎tests/e2e/kubetest2-kops/deployer/up_test.go‎

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package deployer
1818

1919
import (
2020
"reflect"
21+
"slices"
2122
"testing"
2223
)
2324

@@ -83,6 +84,64 @@ func TestAppendIfUnset(t *testing.T) {
8384
}
8485
}
8586

87+
func TestBuiltFromKopsRoot(t *testing.T) {
88+
const root = "/home/prow/go/src/k8s.io/kops"
89+
cases := []struct {
90+
name string
91+
binaryPath string
92+
kopsRoot string
93+
want bool
94+
}{
95+
{"binary built under the checkout", root + "/.build/dist/linux/amd64/kops", root, true},
96+
{"binary downloaded to a temp dir", "/tmp/kops.abc123", root, false},
97+
{"sibling dir is not under the checkout", "/home/prow/go/src/k8s.io/kops-other/kops", root, false},
98+
{"empty kops root", root + "/.build/dist/linux/amd64/kops", "", false},
99+
{"empty binary path", "", root, false},
100+
}
101+
for _, tc := range cases {
102+
t.Run(tc.name, func(t *testing.T) {
103+
if got := builtFromKopsRoot(tc.binaryPath, tc.kopsRoot); got != tc.want {
104+
t.Errorf("builtFromKopsRoot(%q, %q) = %v, want %v", tc.binaryPath, tc.kopsRoot, got, tc.want)
105+
}
106+
})
107+
}
108+
}
109+
110+
func TestLocalChannelArgs(t *testing.T) {
111+
const kopsRoot = "/home/prow/go/src/k8s.io/kops"
112+
base := "file://" + kopsRoot + "/channels/"
113+
cases := []struct {
114+
name string
115+
args []string
116+
expected []string
117+
}{
118+
{
119+
name: "rewrites shorthand in equals form",
120+
args: []string{"create", "cluster", "--channel=alpha", "--networking=cilium"},
121+
expected: []string{"create", "cluster", "--channel=" + base + "alpha", "--networking=cilium"},
122+
},
123+
{
124+
name: "rewrites shorthand in space form",
125+
args: []string{"--channel", "stable"},
126+
expected: []string{"--channel", base + "stable"},
127+
},
128+
{
129+
name: "absent channel defaults to alpha pointed at the checkout",
130+
args: []string{"create", "cluster", "--networking=cilium"},
131+
expected: []string{"create", "cluster", "--networking=cilium", "--channel=" + base + "alpha"},
132+
},
133+
}
134+
135+
for _, tc := range cases {
136+
t.Run(tc.name, func(t *testing.T) {
137+
actual := localChannelArgs(slices.Clone(tc.args), kopsRoot)
138+
if !reflect.DeepEqual(actual, tc.expected) {
139+
t.Errorf("localChannelArgs() = %v, want %v", actual, tc.expected)
140+
}
141+
})
142+
}
143+
}
144+
86145
func TestProwJobLabel(t *testing.T) {
87146
cases := []struct {
88147
name string

0 commit comments

Comments
 (0)