Skip to content

[WiP]:seedling: (cli; alpha commands): Add unit tests for alpha commands #4931

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

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ require (
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
github.com/google/go-cmp v0.7.0 // indirect
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 // indirect
github.com/h2non/gock v1.2.0 // indirect
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/kr/pretty v0.3.1 // indirect
github.com/pkg/errors v0.9.1 // indirect
Expand Down
5 changes: 5 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 h1:BHT72Gu3keYf3ZEu2J0b1vyeLSOYI8bm5wbJM/8yDe8=
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA=
github.com/h2non/gock v1.2.0 h1:K6ol8rfrRkUOefooBC8elXoaNGYkpp7y2qcxGG6BzUE=
github.com/h2non/gock v1.2.0/go.mod h1:tNhoxHYW2W42cYkYb1WqzdbYIieALC99kpYr7rH/BQk=
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw=
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
Expand All @@ -27,6 +31,7 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms=
github.com/onsi/ginkgo/v2 v2.23.4 h1:ktYTpKJAVZnDT4VjxSbiBenUjmlL/5QkBEocaWXiQus=
github.com/onsi/ginkgo/v2 v2.23.4/go.mod h1:Bt66ApGPBFzHyR+JO10Zbt0Gsp4uWxu5mIOTusL46e8=
github.com/onsi/gomega v1.37.0 h1:CdEG8g0S133B4OswTDC/5XPSzE1OeP29QOioj2PID2Y=
Expand Down
43 changes: 43 additions & 0 deletions pkg/cli/alpha/command_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
Copyright 2023 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package alpha

import (
"testing"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)

// Figuring out ways to test run these tests similar to existing.
// Currently unable to run without this on VSCode. Will remove once done
func TestCommand(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "alpha")
}

var _ = Describe("NewScaffoldCommand", func() {
When("NewScaffoldCommand", func() {
It("Testing the NewScaffoldCommand", func() {
cmd := NewScaffoldCommand()
Expect(cmd).NotTo(BeNil())
Expect(cmd.Use).NotTo(Equal(""))
Expect(cmd.Use).To(ContainSubstring("generate"))
Expect(cmd.Short).NotTo(Equal(""))
Expect(cmd.Short).To(ContainSubstring("Re-scaffold a Kubebuilder project from its PROJECT file"))
Expect(cmd.Example).NotTo(Equal(""))
Expect(cmd.Example).To(ContainSubstring("kubebuilder alpha generate"))
})
})
})
2 changes: 1 addition & 1 deletion pkg/cli/alpha/internal/update/prepare.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ func (opts *Update) defineFromVersion(config store.Store) (string, error) {

func (opts *Update) defineToVersion() string {
if len(opts.ToVersion) != 0 {
if !strings.HasPrefix(opts.FromVersion, "v") {
if !strings.HasPrefix(opts.ToVersion, "v") {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please rebase with master?
So that we have no this change it is fixed and merged now 👍

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure Camila, will do

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@camilamacedo86 I have rebased. But the code in master still checks prefix for opts.FromVersion in function defineToVersion(). Can you re-check and confirm if this change is not needed?

return "v" + opts.ToVersion
}
return opts.ToVersion
Expand Down
193 changes: 193 additions & 0 deletions pkg/cli/alpha/internal/update/prepare_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
/*
Copyright 2025 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package update

import (
"os"
"path/filepath"
"testing"

"github.com/h2non/gock"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"sigs.k8s.io/kubebuilder/v4/pkg/cli/alpha/internal/common"
"sigs.k8s.io/kubebuilder/v4/pkg/config"
"sigs.k8s.io/kubebuilder/v4/pkg/config/store/yaml"
v3 "sigs.k8s.io/kubebuilder/v4/pkg/config/v3"
)

func TestCommand(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "update")
}

var _ = Describe("Prepare for internal update", func() {
var (
tmpDir string
workDir string
projectFile string
err error
)

BeforeEach(func() {
workDir, err = os.Getwd()
Expect(err).ToNot(HaveOccurred())

tmpDir, err = os.MkdirTemp("", "kubebuilder-prepare-test")
Expect(err).ToNot(HaveOccurred())
err = os.Chdir(tmpDir)
Expect(err).ToNot(HaveOccurred())

projectFile = filepath.Join(tmpDir, yaml.DefaultPath)

config.Register(config.Version{Number: 3}, func() config.Config {
return &v3.Cfg{Version: config.Version{Number: 3}, CliVersion: "1.0.0"}
})

gock.New("https://api.github.com").
Get("/repos/kubernetes-sigs/kubebuilder/releases/latest").
Reply(200).
JSON(map[string]string{
"tag_name": "v1.1.0",
})
})

AfterEach(func() {
err = os.Chdir(workDir)
Expect(err).ToNot(HaveOccurred())

err = os.RemoveAll(tmpDir)
Expect(err).ToNot(HaveOccurred())
defer gock.Off()
})

Context("Prepare", func() {
DescribeTable("should succeed for valid options",
func(options *Update) {

const version = `version: "3"`
Expect(os.WriteFile(projectFile, []byte(version), 0o644)).To(Succeed())

result := options.Prepare()
Expect(result).To(BeNil())
Expect(options.Prepare()).To(Succeed())
Expect(options.FromVersion).To(Equal("v1.0.0"))
Expect(options.ToVersion).To(Equal("v1.1.0"))
},
Entry("options", &Update{FromVersion: "v1.0.0", ToVersion: "v1.1.0", FromBranch: "test"}),
Entry("options", &Update{FromVersion: "1.0.0", ToVersion: "1.1.0", FromBranch: "test"}),
Entry("options", &Update{FromVersion: "v1.0.0", ToVersion: "v1.1.0"}),
Entry("options", &Update{}),
)

DescribeTable("Should fail to prepare if project path is undetermined",
func(options *Update) {
err = options.Prepare()
Expect(err).To(HaveOccurred())
Expect(err.Error()).Should(ContainSubstring("failed to determine project path"))
},
Entry("options", &Update{FromVersion: "v1.0.0", ToVersion: "v1.1.0", FromBranch: "test"}),
)

DescribeTable("Should fail if PROJECT config could not be loaded",
func(options *Update) {
const version = ""
Expect(os.WriteFile(projectFile, []byte(version), 0o644)).To(Succeed())

err := options.Prepare()
Expect(err).To(HaveOccurred())
Expect(err.Error()).Should(ContainSubstring("failed to load PROJECT config"))
},
Entry("options", &Update{FromVersion: "v1.0.0", ToVersion: "v1.1.0", FromBranch: "test"}),
)

DescribeTable("Should fail if FromVersion cannot be determined",
func(options *Update) {

config.Register(config.Version{Number: 3}, func() config.Config {
return &v3.Cfg{Version: config.Version{Number: 3}}
})

const version = `version: "3"`
Expect(os.WriteFile(projectFile, []byte(version), 0o644)).To(Succeed())

// TODO: Update test. err is Nil as default branch in Prepare() is being hardcoded to "main".
// Hence, the defineFromVersion condition will never fail.
// err := options.Prepare()
// Expect(err).ToNot(HaveOccurred())
// Expect(err.Error()).Should(ContainSubstring("failed to determine the version"))
Expect(options.FromVersion).To(BeEquivalentTo(""))
},
Entry("options", &Update{}),
)
})

Context("DefineFromVersion", func() {

DescribeTable("Should succeed when branch or CliVersion in Project config is present",
func(options *Update) {

const version = `version: "3"`
Expect(os.WriteFile(projectFile, []byte(version), 0o644)).To(Succeed())

config, err := common.LoadProjectConfig(tmpDir)
Expect(err).ToNot(HaveOccurred())
fromVersion, err := options.defineFromVersion(config)
Expect(err).ToNot(HaveOccurred())
Expect(fromVersion).To(BeEquivalentTo("v1.0.0"))
},
Entry("options", &Update{FromVersion: ""}),
Entry("options", &Update{FromBranch: "test"}),
Entry("options", &Update{FromVersion: "1.0.0", FromBranch: "test"}),
)
DescribeTable("Should fail when branch and CliVersion in Project config are absent",
func(options *Update) {

config.Register(config.Version{Number: 3}, func() config.Config {
return &v3.Cfg{Version: config.Version{Number: 3}}
})

const version = `version: "3"`
Expect(os.WriteFile(projectFile, []byte(version), 0o644)).To(Succeed())

config, err := common.LoadProjectConfig(tmpDir)
Expect(err).NotTo(HaveOccurred())
fromVersion, err := options.defineFromVersion(config)
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("no version specified in PROJECT file"))
Expect(fromVersion).To(Equal(""))
},
Entry("options", &Update{FromVersion: ""}),
Entry("options", &Update{FromVersion: "v1.0.0"}),
)
})

Context("DefineToVersion", func() {

DescribeTable("Should succeed.",
func(options *Update) {
toVersion := options.defineToVersion()
Expect(toVersion).To(BeEquivalentTo("v1.1.0"))
},
Entry("options", &Update{ToVersion: "1.1.0"}),
Entry("options", &Update{ToVersion: "v1.1.0"}),
Entry("options", &Update{}),
)

})

})
2 changes: 1 addition & 1 deletion pkg/cli/alpha/internal/update/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@ func runAlphaGenerate(tempDir, version string) error {
if err := cmd.Run(); err != nil {
return fmt.Errorf("failed to run alpha generate: %w", err)
}
log.Info("Successfully ran alpha generate", version)
log.Info("Successfully ran alpha generate ", version)

// TODO: Analyse if this command is still needed in the future.
// It was added because the alpha generate command in versions prior to v4.7.0 does
Expand Down
Loading