未验证 提交 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
import (
"fmt"
"github.com/jenkins-zh/jenkins-cli/client"
"github.com/jenkins-zh/jenkins-cli/app/i18n"
"github.com/spf13/cobra"
)
func init() {
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{
......
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
import (
"bytes"
"fmt"
"github.com/jenkins-zh/jenkins-cli/client"
"io/ioutil"
"net/http"
"os"
"github.com/jenkins-zh/jenkins-cli/client"
"github.com/golang/mock/gomock"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
......
......@@ -74,6 +74,8 @@ func (o *JobHistoryOption) Output(obj interface{}) (data []byte, err error) {
// ColorResult output the result with color
func ColorResult(result string) string {
switch result {
case "":
return ""
case "SUCCESS":
return util.ColorInfo(result)
case "FAILURE":
......
......@@ -2,10 +2,11 @@ package cmd
import (
"bytes"
"github.com/jenkins-zh/jenkins-cli/client"
"io/ioutil"
"os"
"github.com/jenkins-zh/jenkins-cli/client"
"github.com/golang/mock/gomock"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
......@@ -77,8 +78,8 @@ var _ = Describe("job history command", func() {
var _ = Describe("ColorResult test", func() {
It("should success", func() {
Expect(ColorResult("unknown")).To(Equal("unknown"))
Expect(ColorResult("SUCCESS")).To(Equal("SUCCESS"))
Expect(ColorResult("FAILURE")).To(Equal("FAILURE"))
Expect(ColorResult("unknown")).To(ContainSubstring("unknown"))
Expect(ColorResult("SUCCESS")).To(ContainSubstring("SUCCESS"))
Expect(ColorResult("FAILURE")).To(ContainSubstring("FAILURE"))
})
})
......@@ -6,8 +6,11 @@ import (
"log"
"os"
"os/exec"
"regexp"
"strings"
"github.com/jenkins-zh/jenkins-cli/app/health"
"github.com/jenkins-zh/jenkins-cli/app/i18n"
"github.com/jenkins-zh/jenkins-cli/util"
......@@ -27,9 +30,15 @@ type RootOptions struct {
Version bool
Debug bool
Doctor bool
LoggerLevel string
}
var healthCheckRegister = &health.CheckRegister{
Member: make(map[string]health.CommandHealth, 0),
}
var rootCmd = &cobra.Command{
Use: "jcli",
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`,
if config != nil {
client.SetLanguage(config.Language)
}
err = rootOptions.RunDiagnose(cmd)
return
},
BashCompletionFunction: jcliBashCompletionFunc,
......@@ -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
func Execute() {
if err := rootCmd.Execute(); err != nil {
......@@ -104,6 +132,8 @@ func init() {
rootCmd.PersistentFlags().BoolVarP(&rootOptions.Debug, "debug", "", false, "Print the output into debug.html")
rootCmd.PersistentFlags().StringVarP(&rootOptions.LoggerLevel, "logger-level", "", "warn",
"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,
i18n.T("Print the version of Jenkins CLI"))
rootCmd.SetOut(os.Stdout)
......
......@@ -2,6 +2,7 @@ package cmd
import (
"bytes"
"github.com/golang/mock/gomock"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
......@@ -10,15 +11,15 @@ import (
var _ = Describe("Root cmd test", func() {
var (
ctrl *gomock.Controller
rootCmd *cobra.Command
successCmd string
errorCmd string
ctrl *gomock.Controller
fakeRootCmd *cobra.Command
successCmd string
errorCmd string
)
BeforeEach(func() {
ctrl = gomock.NewController(GinkgoT())
rootCmd = &cobra.Command{Use: "root"}
fakeRootCmd = &cobra.Command{Use: "root"}
successCmd = "echo 1"
errorCmd = "exit 1"
config = nil
......@@ -29,9 +30,21 @@ var _ = Describe("Root cmd test", func() {
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() {
It("only with root cmd", func() {
path := getCmdPath(rootCmd)
path := getCmdPath(fakeRootCmd)
Expect(path).To(Equal(""))
})
......@@ -39,7 +52,7 @@ var _ = Describe("Root cmd test", func() {
subCmd := &cobra.Command{
Use: "sub",
}
rootCmd.AddCommand(subCmd)
fakeRootCmd.AddCommand(subCmd)
path := getCmdPath(subCmd)
Expect(path).To(Equal("sub"))
......@@ -52,7 +65,7 @@ var _ = Describe("Root cmd test", func() {
sub2Cmd := &cobra.Command{
Use: "sub2",
}
rootCmd.AddCommand(sub1Cmd)
fakeRootCmd.AddCommand(sub1Cmd)
sub1Cmd.AddCommand(sub2Cmd)
path := getCmdPath(sub2Cmd)
......@@ -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
import "github.com/spf13/cobra"
// CommandHealth is the interface for register a command checker
type CommandHealth interface {
Check() error
......@@ -9,15 +7,10 @@ type CommandHealth interface {
// CheckRegister is the register container
type CheckRegister struct {
Member map[*cobra.Command]CommandHealth
}
// Init init the storage
func (c *CheckRegister) Init() {
c.Member = make(map[*cobra.Command]CommandHealth, 0)
Member map[string]CommandHealth
}
// Register can register a command and function
func (c *CheckRegister) Register(cmd *cobra.Command, health CommandHealth) {
c.Member[cmd] = health
func (c *CheckRegister) Register(path string, health CommandHealth) {
c.Member[path] = health
}
......@@ -3,7 +3,6 @@ package health
import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/spf13/cobra"
)
// Opt only for test
......@@ -20,8 +19,9 @@ var _ = Describe("test command health check interface", func() {
)
BeforeEach(func() {
register = CheckRegister{}
register.Init()
register = CheckRegister{
Member: make(map[string]CommandHealth, 0),
}
})
It("basic test", func() {
......@@ -31,7 +31,7 @@ var _ = Describe("test command health check interface", func() {
Context("register a fake one", func() {
It("should success", func() {
register.Register(&cobra.Command{}, &Opt{})
register.Register("fake", &Opt{})
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
// PrepareForOneInstalledPlugin only for test
func PrepareForOneInstalledPlugin(roundTripper *mhttp.MockRoundTripper, rootURL string) (
request *http.Request, response *http.Response) {
request, response = PrepareForEmptyInstalledPluginList(roundTripper, rootURL, 1)
response.Body = ioutil.NopCloser(bytes.NewBufferString(`{
"plugins": [{
"shortName": "fake",
"version": "1.0",
"hasUpdate": true,
"enable": true,
"active": true
}]
}`))
request, response = PrepareForOneInstalledPluginWithPluginName(
roundTripper, rootURL, "fake")
return
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册