未验证 提交 b82c9862 编写于 作者: LinuxSuRen's avatar LinuxSuRen 提交者: GitHub

Add diagnose for casc cmd (#280)

* Add diagnose for casc cmd

* Complete the test for casc cmd health check

* Fix the test error

* Add test cases for invalid loggger level
上级 1dedfdac
package cmd package cmd
import ( import (
"fmt"
"github.com/jenkins-zh/jenkins-cli/client"
"github.com/jenkins-zh/jenkins-cli/app/i18n" "github.com/jenkins-zh/jenkins-cli/app/i18n"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
func init() { func init() {
rootCmd.AddCommand(cascCmd) rootCmd.AddCommand(cascCmd)
healthCheckRegister.Register(getCmdPath(cascCmd)+".*", &cascOptions)
}
// CASCOptions is the option of casc
type CASCOptions struct {
CommonOption
}
var cascOptions CASCOptions
// Check do the health check of casc cmd
func (o *CASCOptions) Check() (err error) {
jClient := &client.PluginManager{
JenkinsCore: client.JenkinsCore{
RoundTripper: cascOptions.RoundTripper,
},
}
getCurrentJenkinsAndClient(&(jClient.JenkinsCore))
support := false
var plugins *client.InstalledPluginList
if plugins, err = jClient.GetPlugins(1); err == nil {
for _, plugin := range plugins.Plugins {
if plugin.ShortName == "configuration-as-code" {
support = true
break
}
}
}
if !support {
err = fmt.Errorf(i18n.T("lack of plugin configuration-as-code"))
}
return
} }
var cascCmd = &cobra.Command{ var cascCmd = &cobra.Command{
......
package cmd
import (
"io/ioutil"
"os"
"github.com/jenkins-zh/jenkins-cli/client"
"github.com/golang/mock/gomock"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/jenkins-zh/jenkins-cli/mock/mhttp"
)
var _ = Describe("casc command check", func() {
var (
ctrl *gomock.Controller
roundTripper *mhttp.MockRoundTripper
rootURL string
user string
password string
)
BeforeEach(func() {
ctrl = gomock.NewController(GinkgoT())
roundTripper = mhttp.NewMockRoundTripper(ctrl)
cascOptions.RoundTripper = roundTripper
rootOptions.Jenkins = ""
rootOptions.ConfigFile = "test.yaml"
rootURL = "http://localhost:8080/jenkins"
user = "admin"
password = "111e3a2f0231198855dceaff96f20540a9"
})
AfterEach(func() {
rootCmd.SetArgs([]string{})
os.Remove(rootOptions.ConfigFile)
rootOptions.ConfigFile = ""
ctrl.Finish()
})
Context("basic cases", func() {
It("without casc plugin", func() {
data, err := generateSampleConfig()
Expect(err).To(BeNil())
err = ioutil.WriteFile(rootOptions.ConfigFile, data, 0664)
Expect(err).To(BeNil())
req, _ := client.PrepareForOneInstalledPlugin(roundTripper, rootURL)
req.SetBasicAuth(user, password)
err = cascOptions.Check()
Expect(err).To(HaveOccurred())
})
It("with casc plugin", func() {
data, err := generateSampleConfig()
Expect(err).To(BeNil())
err = ioutil.WriteFile(rootOptions.ConfigFile, data, 0664)
Expect(err).To(BeNil())
req, _ := client.PrepareForOneInstalledPluginWithPluginName(roundTripper, rootURL,
"configuration-as-code")
req.SetBasicAuth(user, password)
err = cascOptions.Check()
Expect(err).NotTo(HaveOccurred())
})
})
})
...@@ -3,11 +3,12 @@ package cmd ...@@ -3,11 +3,12 @@ package cmd
import ( import (
"bytes" "bytes"
"fmt" "fmt"
"github.com/jenkins-zh/jenkins-cli/client"
"io/ioutil" "io/ioutil"
"net/http" "net/http"
"os" "os"
"github.com/jenkins-zh/jenkins-cli/client"
"github.com/golang/mock/gomock" "github.com/golang/mock/gomock"
. "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
......
...@@ -74,6 +74,8 @@ func (o *JobHistoryOption) Output(obj interface{}) (data []byte, err error) { ...@@ -74,6 +74,8 @@ func (o *JobHistoryOption) Output(obj interface{}) (data []byte, err error) {
// ColorResult output the result with color // ColorResult output the result with color
func ColorResult(result string) string { func ColorResult(result string) string {
switch result { switch result {
case "":
return ""
case "SUCCESS": case "SUCCESS":
return util.ColorInfo(result) return util.ColorInfo(result)
case "FAILURE": case "FAILURE":
......
...@@ -2,10 +2,11 @@ package cmd ...@@ -2,10 +2,11 @@ package cmd
import ( import (
"bytes" "bytes"
"github.com/jenkins-zh/jenkins-cli/client"
"io/ioutil" "io/ioutil"
"os" "os"
"github.com/jenkins-zh/jenkins-cli/client"
"github.com/golang/mock/gomock" "github.com/golang/mock/gomock"
. "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
...@@ -77,8 +78,8 @@ var _ = Describe("job history command", func() { ...@@ -77,8 +78,8 @@ var _ = Describe("job history command", func() {
var _ = Describe("ColorResult test", func() { var _ = Describe("ColorResult test", func() {
It("should success", func() { It("should success", func() {
Expect(ColorResult("unknown")).To(Equal("unknown")) Expect(ColorResult("unknown")).To(ContainSubstring("unknown"))
Expect(ColorResult("SUCCESS")).To(Equal("SUCCESS")) Expect(ColorResult("SUCCESS")).To(ContainSubstring("SUCCESS"))
Expect(ColorResult("FAILURE")).To(Equal("FAILURE")) Expect(ColorResult("FAILURE")).To(ContainSubstring("FAILURE"))
}) })
}) })
...@@ -6,8 +6,11 @@ import ( ...@@ -6,8 +6,11 @@ import (
"log" "log"
"os" "os"
"os/exec" "os/exec"
"regexp"
"strings" "strings"
"github.com/jenkins-zh/jenkins-cli/app/health"
"github.com/jenkins-zh/jenkins-cli/app/i18n" "github.com/jenkins-zh/jenkins-cli/app/i18n"
"github.com/jenkins-zh/jenkins-cli/util" "github.com/jenkins-zh/jenkins-cli/util"
...@@ -27,9 +30,15 @@ type RootOptions struct { ...@@ -27,9 +30,15 @@ type RootOptions struct {
Version bool Version bool
Debug bool Debug bool
Doctor bool
LoggerLevel string LoggerLevel string
} }
var healthCheckRegister = &health.CheckRegister{
Member: make(map[string]health.CommandHealth, 0),
}
var rootCmd = &cobra.Command{ var rootCmd = &cobra.Command{
Use: "jcli", Use: "jcli",
Short: i18n.T("jcli is a tool which could help you with your multiple Jenkins"), Short: i18n.T("jcli is a tool which could help you with your multiple Jenkins"),
...@@ -67,6 +76,8 @@ More information could found at https://jenkins-zh.cn`, ...@@ -67,6 +76,8 @@ More information could found at https://jenkins-zh.cn`,
if config != nil { if config != nil {
client.SetLanguage(config.Language) client.SetLanguage(config.Language)
} }
err = rootOptions.RunDiagnose(cmd)
return return
}, },
BashCompletionFunction: jcliBashCompletionFunc, BashCompletionFunction: jcliBashCompletionFunc,
...@@ -87,6 +98,23 @@ More information could found at https://jenkins-zh.cn`, ...@@ -87,6 +98,23 @@ More information could found at https://jenkins-zh.cn`,
}, },
} }
// RunDiagnose run the diagnose for a specific command
func (o *RootOptions) RunDiagnose(cmd *cobra.Command) (err error) {
if !o.Doctor {
return
}
path := getCmdPath(cmd)
for k, v := range healthCheckRegister.Member {
if ok, _ := regexp.MatchString(k, path); ok {
err = v.Check()
break
}
}
return
}
// Execute will execute the command // Execute will execute the command
func Execute() { func Execute() {
if err := rootCmd.Execute(); err != nil { if err := rootCmd.Execute(); err != nil {
...@@ -104,6 +132,8 @@ func init() { ...@@ -104,6 +132,8 @@ func init() {
rootCmd.PersistentFlags().BoolVarP(&rootOptions.Debug, "debug", "", false, "Print the output into debug.html") rootCmd.PersistentFlags().BoolVarP(&rootOptions.Debug, "debug", "", false, "Print the output into debug.html")
rootCmd.PersistentFlags().StringVarP(&rootOptions.LoggerLevel, "logger-level", "", "warn", rootCmd.PersistentFlags().StringVarP(&rootOptions.LoggerLevel, "logger-level", "", "warn",
"Logger level which could be: debug, info, warn, error") "Logger level which could be: debug, info, warn, error")
rootCmd.PersistentFlags().BoolVarP(&rootOptions.Doctor, "doctor", "", false,
i18n.T("Run the diagnose for current command"))
rootCmd.Flags().BoolVarP(&rootOptions.Version, "version", "v", false, rootCmd.Flags().BoolVarP(&rootOptions.Version, "version", "v", false,
i18n.T("Print the version of Jenkins CLI")) i18n.T("Print the version of Jenkins CLI"))
rootCmd.SetOut(os.Stdout) rootCmd.SetOut(os.Stdout)
......
...@@ -2,6 +2,7 @@ package cmd ...@@ -2,6 +2,7 @@ package cmd
import ( import (
"bytes" "bytes"
"github.com/golang/mock/gomock" "github.com/golang/mock/gomock"
. "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
...@@ -10,15 +11,15 @@ import ( ...@@ -10,15 +11,15 @@ import (
var _ = Describe("Root cmd test", func() { var _ = Describe("Root cmd test", func() {
var ( var (
ctrl *gomock.Controller ctrl *gomock.Controller
rootCmd *cobra.Command fakeRootCmd *cobra.Command
successCmd string successCmd string
errorCmd string errorCmd string
) )
BeforeEach(func() { BeforeEach(func() {
ctrl = gomock.NewController(GinkgoT()) ctrl = gomock.NewController(GinkgoT())
rootCmd = &cobra.Command{Use: "root"} fakeRootCmd = &cobra.Command{Use: "root"}
successCmd = "echo 1" successCmd = "echo 1"
errorCmd = "exit 1" errorCmd = "exit 1"
config = nil config = nil
...@@ -29,9 +30,21 @@ var _ = Describe("Root cmd test", func() { ...@@ -29,9 +30,21 @@ var _ = Describe("Root cmd test", func() {
ctrl.Finish() ctrl.Finish()
}) })
Context("invalid logger level", func() {
It("cause errors", func() {
rootCmd.SetArgs([]string{"--logger-level", "fake"})
_, err := rootCmd.ExecuteC()
Expect(err).To(HaveOccurred())
rootCmd.SetArgs([]string{"--logger-level", "warn"})
_, err = rootCmd.ExecuteC()
Expect(err).NotTo(HaveOccurred())
})
})
Context("PreHook test", func() { Context("PreHook test", func() {
It("only with root cmd", func() { It("only with root cmd", func() {
path := getCmdPath(rootCmd) path := getCmdPath(fakeRootCmd)
Expect(path).To(Equal("")) Expect(path).To(Equal(""))
}) })
...@@ -39,7 +52,7 @@ var _ = Describe("Root cmd test", func() { ...@@ -39,7 +52,7 @@ var _ = Describe("Root cmd test", func() {
subCmd := &cobra.Command{ subCmd := &cobra.Command{
Use: "sub", Use: "sub",
} }
rootCmd.AddCommand(subCmd) fakeRootCmd.AddCommand(subCmd)
path := getCmdPath(subCmd) path := getCmdPath(subCmd)
Expect(path).To(Equal("sub")) Expect(path).To(Equal("sub"))
...@@ -52,7 +65,7 @@ var _ = Describe("Root cmd test", func() { ...@@ -52,7 +65,7 @@ var _ = Describe("Root cmd test", func() {
sub2Cmd := &cobra.Command{ sub2Cmd := &cobra.Command{
Use: "sub2", Use: "sub2",
} }
rootCmd.AddCommand(sub1Cmd) fakeRootCmd.AddCommand(sub1Cmd)
sub1Cmd.AddCommand(sub2Cmd) sub1Cmd.AddCommand(sub2Cmd)
path := getCmdPath(sub2Cmd) path := getCmdPath(sub2Cmd)
...@@ -164,3 +177,24 @@ var _ = Describe("Root cmd test", func() { ...@@ -164,3 +177,24 @@ var _ = Describe("Root cmd test", func() {
}) })
}) })
}) })
// FakeOpt only for test
type FakeOpt struct{}
// Check fake, only for test
func (o *FakeOpt) Check() error {
return nil
}
var _ = Describe("RunDiagnose test", func() {
It("should success", func() {
opt := RootOptions{Doctor: true}
rootCmd := &cobra.Command{
Use: "fake",
}
healthCheckRegister.Register(getCmdPath(rootCmd), &FakeOpt{})
err := opt.RunDiagnose(rootCmd)
Expect(err).NotTo(HaveOccurred())
})
})
package health package health
import "github.com/spf13/cobra"
// CommandHealth is the interface for register a command checker // CommandHealth is the interface for register a command checker
type CommandHealth interface { type CommandHealth interface {
Check() error Check() error
...@@ -9,15 +7,10 @@ type CommandHealth interface { ...@@ -9,15 +7,10 @@ type CommandHealth interface {
// CheckRegister is the register container // CheckRegister is the register container
type CheckRegister struct { type CheckRegister struct {
Member map[*cobra.Command]CommandHealth Member map[string]CommandHealth
}
// Init init the storage
func (c *CheckRegister) Init() {
c.Member = make(map[*cobra.Command]CommandHealth, 0)
} }
// Register can register a command and function // Register can register a command and function
func (c *CheckRegister) Register(cmd *cobra.Command, health CommandHealth) { func (c *CheckRegister) Register(path string, health CommandHealth) {
c.Member[cmd] = health c.Member[path] = health
} }
...@@ -3,7 +3,6 @@ package health ...@@ -3,7 +3,6 @@ package health
import ( import (
. "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
"github.com/spf13/cobra"
) )
// Opt only for test // Opt only for test
...@@ -20,8 +19,9 @@ var _ = Describe("test command health check interface", func() { ...@@ -20,8 +19,9 @@ var _ = Describe("test command health check interface", func() {
) )
BeforeEach(func() { BeforeEach(func() {
register = CheckRegister{} register = CheckRegister{
register.Init() Member: make(map[string]CommandHealth, 0),
}
}) })
It("basic test", func() { It("basic test", func() {
...@@ -31,7 +31,7 @@ var _ = Describe("test command health check interface", func() { ...@@ -31,7 +31,7 @@ var _ = Describe("test command health check interface", func() {
Context("register a fake one", func() { Context("register a fake one", func() {
It("should success", func() { It("should success", func() {
register.Register(&cobra.Command{}, &Opt{}) register.Register("fake", &Opt{})
Expect(len(register.Member)).To(Equal(1)) Expect(len(register.Member)).To(Equal(1))
}) })
}) })
......
package client
import (
"bytes"
"fmt"
"io/ioutil"
"net/http"
"github.com/jenkins-zh/jenkins-cli/mock/mhttp"
)
// PrepareForOneInstalledPluginWithPluginName only for test
func PrepareForOneInstalledPluginWithPluginName(roundTripper *mhttp.MockRoundTripper, rootURL, pluginName string) (
request *http.Request, response *http.Response) {
request, response = PrepareForEmptyInstalledPluginList(roundTripper, rootURL, 1)
response.Body = ioutil.NopCloser(bytes.NewBufferString(fmt.Sprintf(`{
"plugins": [{
"shortName": "%s",
"version": "1.0",
"hasUpdate": true,
"enable": true,
"active": true
}]
}`, pluginName)))
return
}
...@@ -106,16 +106,8 @@ func PrepareForEmptyInstalledPluginList(roundTripper *mhttp.MockRoundTripper, ro ...@@ -106,16 +106,8 @@ func PrepareForEmptyInstalledPluginList(roundTripper *mhttp.MockRoundTripper, ro
// PrepareForOneInstalledPlugin only for test // PrepareForOneInstalledPlugin only for test
func PrepareForOneInstalledPlugin(roundTripper *mhttp.MockRoundTripper, rootURL string) ( func PrepareForOneInstalledPlugin(roundTripper *mhttp.MockRoundTripper, rootURL string) (
request *http.Request, response *http.Response) { request *http.Request, response *http.Response) {
request, response = PrepareForEmptyInstalledPluginList(roundTripper, rootURL, 1) request, response = PrepareForOneInstalledPluginWithPluginName(
response.Body = ioutil.NopCloser(bytes.NewBufferString(`{ roundTripper, rootURL, "fake")
"plugins": [{
"shortName": "fake",
"version": "1.0",
"hasUpdate": true,
"enable": true,
"active": true
}]
}`))
return return
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册