Skip to content
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

[release-1.7] 🐛 Verify that there is a release for the tag #10423

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
203 changes: 199 additions & 4 deletions cmd/clusterctl/client/repository/repository_github_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"context"
"fmt"
"net/http"
"strings"
"testing"
"time"

Expand Down Expand Up @@ -428,6 +429,11 @@ func Test_gitHubRepository_getLatestContractRelease(t *testing.T) {
fmt.Fprint(w, `{"id":13, "tag_name": "v0.5.0", "assets": [{"id": 1, "name": "metadata.yaml"}] }`)
})

mux.HandleFunc("/repos/o/r1/releases/tags/v0.3.2", func(w http.ResponseWriter, r *http.Request) {
goproxytest.HTTPTestMethod(t, r, "GET")
fmt.Fprint(w, `{"id":14, "tag_name": "v0.3.2", "assets": [{"id": 2, "name": "metadata.yaml"}] }`)
})

// Setup a handler for returning a fake release metadata file.
mux.HandleFunc("/repos/o/r1/releases/assets/1", func(w http.ResponseWriter, r *http.Request) {
goproxytest.HTTPTestMethod(t, r, "GET")
Expand All @@ -436,6 +442,13 @@ func Test_gitHubRepository_getLatestContractRelease(t *testing.T) {
fmt.Fprint(w, "apiVersion: clusterctl.cluster.x-k8s.io/v1alpha3\nreleaseSeries:\n - major: 0\n minor: 4\n contract: v1alpha4\n - major: 0\n minor: 5\n contract: v1alpha4\n - major: 0\n minor: 3\n contract: v1alpha3\n")
})

mux.HandleFunc("/repos/o/r1/releases/assets/2", func(w http.ResponseWriter, r *http.Request) {
goproxytest.HTTPTestMethod(t, r, "GET")
w.Header().Set("Content-Type", "application/octet-stream")
w.Header().Set("Content-Disposition", "attachment; filename=metadata.yaml")
fmt.Fprint(w, "apiVersion: clusterctl.cluster.x-k8s.io/v1alpha3\nreleaseSeries:\n - major: 0\n minor: 4\n contract: v1alpha4\n - major: 0\n minor: 5\n contract: v1alpha4\n - major: 0\n minor: 3\n contract: v1alpha3\n")
})

scheme, host, muxGoproxy, teardownGoproxy := goproxytest.NewFakeGoproxy()
clientGoproxy := goproxy.NewClient(scheme, host)

Expand Down Expand Up @@ -534,6 +547,9 @@ func Test_gitHubRepository_getLatestRelease(t *testing.T) {
clientGoproxy := goproxy.NewClient(scheme, host)
defer teardownGoproxy()

client, mux, teardown := test.NewFakeGitHub()
defer teardown()

// Setup a handler for returning 4 fake releases.
muxGoproxy.HandleFunc("/github.com/o/r1/@v/list", func(w http.ResponseWriter, r *http.Request) {
goproxytest.HTTPTestMethod(t, r, "GET")
Expand All @@ -543,9 +559,13 @@ func Test_gitHubRepository_getLatestRelease(t *testing.T) {
fmt.Fprint(w, "foo\n") // no semantic version tag
})
// And also expose a release for them
muxGoproxy.HandleFunc("/api.github.com/repos/o/r1/releases/tags/v0.4.2", func(w http.ResponseWriter, r *http.Request) {
mux.HandleFunc("/repos/o/r1/releases/tags/v0.4.2", func(w http.ResponseWriter, r *http.Request) {
goproxytest.HTTPTestMethod(t, r, "GET")
fmt.Fprint(w, "{}\n")
fmt.Fprint(w, `{"id":13, "tag_name": "v0.4.2", "assets": [{"id": 1, "name": "metadata.yaml"}] }`)
})
mux.HandleFunc("/repos/o/r3/releases/tags/v0.1.0-alpha.2", func(w http.ResponseWriter, r *http.Request) {
goproxytest.HTTPTestMethod(t, r, "GET")
fmt.Fprint(w, `{"id":14, "tag_name": "v0.1.0-alpha.2", "assets": [{"id": 2, "name": "metadata.yaml"}] }`)
})

// Setup a handler for returning no releases.
Expand All @@ -562,6 +582,21 @@ func Test_gitHubRepository_getLatestRelease(t *testing.T) {
fmt.Fprint(w, "v0.1.0-alpha.2\n")
})

// Setup a handler for returning a fake release metadata file.
mux.HandleFunc("/repos/o/r1/releases/assets/1", func(w http.ResponseWriter, r *http.Request) {
goproxytest.HTTPTestMethod(t, r, "GET")
w.Header().Set("Content-Type", "application/octet-stream")
w.Header().Set("Content-Disposition", "attachment; filename=metadata.yaml")
fmt.Fprint(w, "apiVersion: clusterctl.cluster.x-k8s.io/v1alpha3\nreleaseSeries:\n - major: 0\n minor: 4\n contract: v1alpha4\n - major: 0\n minor: 5\n contract: v1alpha4\n - major: 0\n minor: 3\n contract: v1alpha3\n")
})

mux.HandleFunc("/repos/o/r3/releases/assets/2", func(w http.ResponseWriter, r *http.Request) {
goproxytest.HTTPTestMethod(t, r, "GET")
w.Header().Set("Content-Type", "application/octet-stream")
w.Header().Set("Content-Disposition", "attachment; filename=metadata.yaml")
fmt.Fprint(w, "apiVersion: clusterctl.cluster.x-k8s.io/v1alpha3\nreleaseSeries:\n - major: 0\n minor: 4\n contract: v1alpha4\n - major: 0\n minor: 5\n contract: v1alpha4\n - major: 0\n minor: 3\n contract: v1alpha3\n")
})

configVariablesClient := test.NewFakeVariableClient()

type field struct {
Expand Down Expand Up @@ -606,7 +641,7 @@ func Test_gitHubRepository_getLatestRelease(t *testing.T) {

resetCaches()

gRepo, err := NewGitHubRepository(ctx, tt.field.providerConfig, configVariablesClient, injectGoproxyClient(clientGoproxy))
gRepo, err := NewGitHubRepository(ctx, tt.field.providerConfig, configVariablesClient, injectGoproxyClient(clientGoproxy), injectGithubClient(client))
g.Expect(err).ToNot(HaveOccurred())

got, err := latestRelease(ctx, gRepo)
Expand All @@ -628,6 +663,9 @@ func Test_gitHubRepository_getLatestPatchRelease(t *testing.T) {
clientGoproxy := goproxy.NewClient(scheme, host)
defer teardownGoproxy()

client, mux, teardown := test.NewFakeGitHub()
defer teardown()

// Setup a handler for returning 4 fake releases.
muxGoproxy.HandleFunc("/github.com/o/r1/@v/list", func(w http.ResponseWriter, r *http.Request) {
goproxytest.HTTPTestMethod(t, r, "GET")
Expand All @@ -636,6 +674,30 @@ func Test_gitHubRepository_getLatestPatchRelease(t *testing.T) {
fmt.Fprint(w, "v1.3.2\n")
})

// Setup a handler for returning a fake release.
mux.HandleFunc("/repos/o/r1/releases/tags/v0.4.0", func(w http.ResponseWriter, r *http.Request) {
goproxytest.HTTPTestMethod(t, r, "GET")
fmt.Fprint(w, `{"id":13, "tag_name": "v0.4.0", "assets": [{"id": 1, "name": "metadata.yaml"}] }`)
})

mux.HandleFunc("/repos/o/r1/releases/tags/v0.3.2", func(w http.ResponseWriter, r *http.Request) {
goproxytest.HTTPTestMethod(t, r, "GET")
fmt.Fprint(w, `{"id":14, "tag_name": "v0.3.2", "assets": [{"id": 1, "name": "metadata.yaml"}] }`)
})

mux.HandleFunc("/repos/o/r1/releases/tags/v1.3.2", func(w http.ResponseWriter, r *http.Request) {
goproxytest.HTTPTestMethod(t, r, "GET")
fmt.Fprint(w, `{"id":15, "tag_name": "v1.3.2", "assets": [{"id": 1, "name": "metadata.yaml"}] }`)
})

// Setup a handler for returning a fake release metadata file.
mux.HandleFunc("/repos/o/r1/releases/assets/1", func(w http.ResponseWriter, r *http.Request) {
goproxytest.HTTPTestMethod(t, r, "GET")
w.Header().Set("Content-Type", "application/octet-stream")
w.Header().Set("Content-Disposition", "attachment; filename=metadata.yaml")
fmt.Fprint(w, "apiVersion: clusterctl.cluster.x-k8s.io/v1alpha3\nreleaseSeries:\n - major: 0\n minor: 4\n contract: v1alpha4\n - major: 0\n minor: 5\n contract: v1alpha4\n - major: 0\n minor: 3\n contract: v1alpha3\n")
})

major0 := uint(0)
minor3 := uint(3)
minor4 := uint(4)
Expand Down Expand Up @@ -692,7 +754,7 @@ func Test_gitHubRepository_getLatestPatchRelease(t *testing.T) {

resetCaches()

gRepo, err := NewGitHubRepository(ctx, tt.field.providerConfig, configVariablesClient, injectGoproxyClient(clientGoproxy))
gRepo, err := NewGitHubRepository(ctx, tt.field.providerConfig, configVariablesClient, injectGoproxyClient(clientGoproxy), injectGithubClient(client))
g.Expect(err).ToNot(HaveOccurred())

got, err := latestPatchRelease(ctx, gRepo, tt.major, tt.minor)
Expand Down Expand Up @@ -913,3 +975,136 @@ func resetCaches() {
cacheReleases = map[string]*github.RepositoryRelease{}
cacheFiles = map[string][]byte{}
}

func Test_gitHubRepository_releaseNotFound(t *testing.T) {
retryableOperationInterval = 200 * time.Millisecond
retryableOperationTimeout = 1 * time.Second

tests := []struct {
name string
releaseTags []string
ghReleases []string
want string
wantErr bool
}{
{
name: "One release",
releaseTags: []string{"v0.4.2"},
ghReleases: []string{"v0.4.2"},
want: "v0.4.2",
wantErr: false,
},
{
name: "Latest tag without a release",
releaseTags: []string{"v0.5.0", "v0.4.2"},
ghReleases: []string{"v0.4.2"},
want: "v0.4.2",
wantErr: false,
},
{
name: "Two tags without releases",
releaseTags: []string{"v0.6.0", "v0.5.0", "v0.4.2"},
ghReleases: []string{"v0.4.2"},
want: "v0.4.2",
wantErr: false,
},
{
name: "Five tags without releases",
releaseTags: []string{"v0.9.0", "v0.8.0", "v0.7.0", "v0.6.0", "v0.5.0", "v0.4.2"},
ghReleases: []string{"v0.4.2"},
wantErr: true,
},
{
name: "Pre-releases have lower priority",
releaseTags: []string{"v0.7.0-alpha", "v0.6.0-alpha", "v0.5.0-alpha", "v0.4.2"},
ghReleases: []string{"v0.4.2"},
want: "v0.4.2",
wantErr: false,
},
{
name: "Two Github releases",
releaseTags: []string{"v0.7.0", "v0.6.0", "v0.5.0", "v0.4.2"},
ghReleases: []string{"v0.5.0", "v0.4.2"},
want: "v0.5.0",
wantErr: false,
},
{
name: "Github release and prerelease",
releaseTags: []string{"v0.6.0", "v0.5.0-alpha", "v0.4.2"},
ghReleases: []string{"v0.5.0-alpha", "v0.4.2"},
want: "v0.4.2",
wantErr: false,
},
{
name: "No Github releases",
releaseTags: []string{"v0.6.0", "v0.5.0", "v0.4.2"},
ghReleases: []string{},
wantErr: true,
},
{
name: "Pre-releases only",
releaseTags: []string{"v0.6.0-alpha", "v0.5.0-alpha", "v0.4.2-alpha"},
ghReleases: []string{"v0.5.0-alpha"},
want: "v0.5.0-alpha",
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
g := NewWithT(t)

ctx := context.Background()

configVariablesClient := test.NewFakeVariableClient()

resetCaches()

client, mux, teardown := test.NewFakeGitHub()
defer teardown()

providerConfig := config.NewProvider("test", "https://github.com/o/r1/releases/v0.4.1/file.yaml", clusterctlv1.CoreProviderType)

scheme, host, muxGoproxy, teardownGoproxy := goproxytest.NewFakeGoproxy()
clientGoproxy := goproxy.NewClient(scheme, host)

defer teardownGoproxy()

// First, register tags within goproxy.
muxGoproxy.HandleFunc("/github.com/o/r1/@v/list", func(w http.ResponseWriter, r *http.Request) {
goproxytest.HTTPTestMethod(t, r, "GET")
for _, release := range tt.releaseTags {
fmt.Fprint(w, release+"\n")
}
})

// Second, register releases in GitHub.
for _, release := range tt.ghReleases {
mux.HandleFunc(fmt.Sprintf("/repos/o/r1/releases/tags/%s", release), func(w http.ResponseWriter, r *http.Request) {
goproxytest.HTTPTestMethod(t, r, "GET")
parts := strings.Split(r.RequestURI, "/")
version := parts[len(parts)-1]
fmt.Fprintf(w, "{\"id\":13, \"tag_name\": %q, \"assets\": [{\"id\": 1, \"name\": \"metadata.yaml\"}] }", version)
})
}

// Third, setup a handler for returning a fake release metadata file.
mux.HandleFunc("/repos/o/r1/releases/assets/1", func(w http.ResponseWriter, r *http.Request) {
goproxytest.HTTPTestMethod(t, r, "GET")
w.Header().Set("Content-Type", "application/octet-stream")
w.Header().Set("Content-Disposition", "attachment; filename=metadata.yaml")
fmt.Fprint(w, "apiVersion: clusterctl.cluster.x-k8s.io/v1alpha3\nreleaseSeries:\n - major: 0\n minor: 4\n contract: v1alpha4\n - major: 0\n minor: 5\n contract: v1alpha4\n - major: 0\n minor: 3\n contract: v1alpha3\n")
})

gRepo, err := NewGitHubRepository(ctx, providerConfig, configVariablesClient, injectGithubClient(client), injectGoproxyClient(clientGoproxy))
g.Expect(err).ToNot(HaveOccurred())

got, err := latestRelease(ctx, gRepo)
if tt.wantErr {
g.Expect(err).To(HaveOccurred())
return
}
g.Expect(err).ToNot(HaveOccurred())
g.Expect(got).To(Equal(tt.want))
})
}
}
8 changes: 8 additions & 0 deletions cmd/clusterctl/client/repository/repository_local_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ import (
"sigs.k8s.io/cluster-api/cmd/clusterctl/internal/test"
)

const (
metadataContents = "apiVersion: clusterctl.cluster.x-k8s.io/v1alpha3\nreleaseSeries:\n - major: 0\n minor: 4\n contract: v1alpha4\n - major: 0\n minor: 5\n contract: v1alpha4\n - major: 0\n minor: 3\n contract: v1alpha3\n"
)

func Test_localRepository_newLocalRepository(t *testing.T) {
type fields struct {
provider config.Provider
Expand Down Expand Up @@ -157,6 +161,7 @@ func Test_localRepository_newLocalRepository_Latest(t *testing.T) {
// Create several release directories
createLocalTestProviderFile(t, tmpDir, "bootstrap-foo/v1.0.0/bootstrap-components.yaml", "foo: bar")
createLocalTestProviderFile(t, tmpDir, "bootstrap-foo/v1.0.1/bootstrap-components.yaml", "foo: bar")
createLocalTestProviderFile(t, tmpDir, "bootstrap-foo/v1.0.1/metadata.yaml", metadataContents)
createLocalTestProviderFile(t, tmpDir, "bootstrap-foo/v2.0.0-alpha.0/bootstrap-components.yaml", "foo: bar")
createLocalTestProviderFile(t, tmpDir, "bootstrap-foo/Foo.Bar/bootstrap-components.yaml", "foo: bar")
createLocalTestProviderFile(t, tmpDir, "bootstrap-foo/foo.file", "foo: bar")
Expand Down Expand Up @@ -185,8 +190,10 @@ func Test_localRepository_GetFile(t *testing.T) {
p1 := config.NewProvider("foo", dst1, clusterctlv1.BootstrapProviderType)

// Provider 2: URL is for the latest release
createLocalTestProviderFile(t, tmpDir, "bootstrap-baz/v1.0.0-alpha.0/metadata.yaml", metadataContents)
createLocalTestProviderFile(t, tmpDir, "bootstrap-bar/v1.0.0/bootstrap-components.yaml", "version: v1.0.0")
createLocalTestProviderFile(t, tmpDir, "bootstrap-bar/v1.0.1/bootstrap-components.yaml", "version: v1.0.1")
createLocalTestProviderFile(t, tmpDir, "bootstrap-bar/v1.0.1/metadata.yaml", metadataContents)
createLocalTestProviderFile(t, tmpDir, "bootstrap-bar/v2.0.0-alpha.0/bootstrap-components.yaml", "version: v2.0.0-alpha.0")
createLocalTestProviderFile(t, tmpDir, "bootstrap-bar/Foo.Bar/bootstrap-components.yaml", "version: Foo.Bar")
createLocalTestProviderFile(t, tmpDir, "bootstrap-bar/foo.file", "foo: bar")
Expand Down Expand Up @@ -323,6 +330,7 @@ func Test_localRepository_GetVersions(t *testing.T) {
createLocalTestProviderFile(t, tmpDir, "bootstrap-bar/v1.0.0/bootstrap-components.yaml", "version: v1.0.0")
createLocalTestProviderFile(t, tmpDir, "bootstrap-bar/v1.0.1/bootstrap-components.yaml", "version: v1.0.1")
createLocalTestProviderFile(t, tmpDir, "bootstrap-bar/v2.0.1/bootstrap-components.yaml", "version: v2.0.1")
createLocalTestProviderFile(t, tmpDir, "bootstrap-bar/v2.0.2+exp.sha.5114f85/metadata.yaml", metadataContents)
createLocalTestProviderFile(t, tmpDir, "bootstrap-bar/v2.0.2+exp.sha.5114f85/bootstrap-components.yaml", "version: v2.0.2+exp.sha.5114f85")
createLocalTestProviderFile(t, tmpDir, "bootstrap-bar/v2.0.3-alpha/bootstrap-components.yaml", "version: v2.0.3-alpha")
createLocalTestProviderFile(t, tmpDir, "bootstrap-bar/Foo.Bar/bootstrap-components.yaml", "version: Foo.Bar")
Expand Down
Loading