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

Add test cases for part of main logics (#133)

* Add test cases for getCrumb

* Add branch name

* Add branch name

* Add branch name

* Add test cases for job client

* Add more tests

* Refactor delete job function

* Add test for job type cmd

* Add test for job stop cmd

* Add test for job search cmd

* Add test for job delete cmd

* Add test case for plugin manager client

* Add test cases for plugin search cmd
上级 8c3052f2
......@@ -22,4 +22,4 @@ script:
# file to see the specific configuration
- curl -LsS https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-4.0.0.1744-linux.zip > sonar-scanner-cli-4.0.0.1744-linux.zip
- unzip sonar-scanner-cli-4.0.0.1744-linux.zip
- sonar-scanner-4.0.0.1744-linux/bin/sonar-scanner -Dsonar.projectKey=jenkins-zh_jenkins-cli -Dsonar.organization=jenkins-zh -Dsonar.sources=. -Dsonar.host.url=https://sonarcloud.io -Dsonar.login=674e187e300edc0ad56a05705bd0b21cbe18bd52
- sonar-scanner-4.0.0.1744-linux/bin/sonar-scanner -D sonar.branch.name=$TRAVIS_BRANCH -Dsonar.projectKey=jenkins-zh_jenkins-cli -Dsonar.organization=jenkins-zh -Dsonar.sources=. -Dsonar.host.url=https://sonarcloud.io -Dsonar.login=674e187e300edc0ad56a05705bd0b21cbe18bd52
......@@ -4,6 +4,7 @@ import (
"encoding/json"
"fmt"
"github.com/jenkins-zh/jenkins-cli/client"
"github.com/AlecAivazis/survey/v2"
"github.com/spf13/cobra"
"gopkg.in/yaml.v2"
......@@ -96,3 +97,13 @@ type InteractiveOption struct {
func (b *InteractiveOption) SetFlag(cmd *cobra.Command) {
cmd.Flags().BoolVarP(&b.Interactive, "interactive", "i", false, "Interactive mode")
}
func getCurrentJenkinsAndClient(jclient *client.JenkinsCore) (jenkins *JenkinsServer) {
jenkins = getCurrentJenkinsFromOptionsOrDie()
jclient.URL = jenkins.URL
jclient.UserName = jenkins.UserName
jclient.Token = jenkins.Token
jclient.Proxy = jenkins.Proxy
jclient.ProxyAuth = jenkins.ProxyAuth
return
}
......@@ -4,6 +4,7 @@ import (
"encoding/json"
"fmt"
"log"
"net/http"
"github.com/AlecAivazis/survey/v2"
"github.com/jenkins-zh/jenkins-cli/client"
......@@ -15,6 +16,8 @@ type JobBuildOption struct {
Param string
Debug bool
RoundTripper http.RoundTripper
}
var jobBuildOption JobBuildOption
......@@ -42,13 +45,12 @@ var jobBuildCmd = &cobra.Command{
return
}
jenkins := getCurrentJenkinsFromOptionsOrDie()
jclient := &client.JobClient{}
jclient.URL = jenkins.URL
jclient.UserName = jenkins.UserName
jclient.Token = jenkins.Token
jclient.Proxy = jenkins.Proxy
jclient.ProxyAuth = jenkins.ProxyAuth
jclient := &client.JobClient{
JenkinsCore: client.JenkinsCore{
RoundTripper: jobBuildOption.RoundTripper,
},
}
getCurrentJenkinsAndClient(&(jclient.JenkinsCore))
paramDefs := []client.ParameterDefinition{}
hasParam := false
......
package cmd
import (
"bytes"
"fmt"
"io/ioutil"
"net/http"
"os"
"github.com/golang/mock/gomock"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/jenkins-zh/jenkins-cli/mock/mhttp"
)
var _ = Describe("job build command", func() {
var (
ctrl *gomock.Controller
roundTripper *mhttp.MockRoundTripper
)
BeforeEach(func() {
ctrl = gomock.NewController(GinkgoT())
roundTripper = mhttp.NewMockRoundTripper(ctrl)
rootCmd.SetArgs([]string{})
rootOptions.Jenkins = ""
rootOptions.ConfigFile = "test.yaml"
jobBuildOption.RoundTripper = roundTripper
})
AfterEach(func() {
rootCmd.SetArgs([]string{})
os.Remove(rootOptions.ConfigFile)
rootOptions.ConfigFile = ""
ctrl.Finish()
})
Context("basic cases", func() {
It("should success", func() {
data, err := generateSampleConfig()
Expect(err).To(BeNil())
err = ioutil.WriteFile(rootOptions.ConfigFile, data, 0664)
Expect(err).To(BeNil())
jobName := "fakeJob"
request, _ := http.NewRequest("POST", fmt.Sprintf("http://localhost:8080/jenkins/job/%s/build", jobName), nil)
request.Header.Add("CrumbRequestField", "Crumb")
request.SetBasicAuth("admin", "111e3a2f0231198855dceaff96f20540a9")
response := &http.Response{
StatusCode: 201,
Proto: "HTTP/1.1",
Request: request,
Body: ioutil.NopCloser(bytes.NewBufferString("")),
}
roundTripper.EXPECT().
RoundTrip(request).Return(response, nil)
requestCrumb, _ := http.NewRequest("GET", "http://localhost:8080/jenkins/crumbIssuer/api/json", nil)
requestCrumb.SetBasicAuth("admin", "111e3a2f0231198855dceaff96f20540a9")
responseCrumb := &http.Response{
StatusCode: 200,
Proto: "HTTP/1.1",
Request: requestCrumb,
Body: ioutil.NopCloser(bytes.NewBufferString(`
{"crumbRequestField":"CrumbRequestField","crumb":"Crumb"}
`)),
}
roundTripper.EXPECT().
RoundTrip(requestCrumb).Return(responseCrumb, nil)
rootCmd.SetArgs([]string{"job", "build", jobName, "-b", "true"})
_, err = rootCmd.ExecuteC()
Expect(err).To(BeNil())
})
})
})
......@@ -3,6 +3,7 @@ package cmd
import (
"fmt"
"log"
"net/http"
"github.com/jenkins-zh/jenkins-cli/client"
"github.com/spf13/cobra"
......@@ -10,6 +11,8 @@ import (
type JobDeleteOption struct {
BatchOption
RoundTripper http.RoundTripper
}
var jobDeleteOption JobDeleteOption
......@@ -34,13 +37,12 @@ var jobDeleteCmd = &cobra.Command{
return
}
jenkins := getCurrentJenkinsFromOptionsOrDie()
jclient := &client.JobClient{}
jclient.URL = jenkins.URL
jclient.UserName = jenkins.UserName
jclient.Token = jenkins.Token
jclient.Proxy = jenkins.Proxy
jclient.ProxyAuth = jenkins.ProxyAuth
jclient := &client.JobClient{
JenkinsCore: client.JenkinsCore{
RoundTripper: jobDeleteOption.RoundTripper,
},
}
getCurrentJenkinsAndClient(&(jclient.JenkinsCore))
if err := jclient.Delete(jobName); err != nil {
log.Fatal(err)
......
package cmd
import (
"bytes"
"fmt"
"io/ioutil"
"net/http"
"os"
"github.com/golang/mock/gomock"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/jenkins-zh/jenkins-cli/mock/mhttp"
"github.com/jenkins-zh/jenkins-cli/util"
)
var _ = Describe("job delete command", func() {
var (
ctrl *gomock.Controller
roundTripper *mhttp.MockRoundTripper
)
BeforeEach(func() {
ctrl = gomock.NewController(GinkgoT())
roundTripper = mhttp.NewMockRoundTripper(ctrl)
jobDeleteOption.RoundTripper = roundTripper
rootCmd.SetArgs([]string{})
rootOptions.Jenkins = ""
rootOptions.ConfigFile = "test.yaml"
})
AfterEach(func() {
rootCmd.SetArgs([]string{})
os.Remove(rootOptions.ConfigFile)
rootOptions.ConfigFile = ""
ctrl.Finish()
})
Context("basic cases", func() {
It("should success, with batch mode", func() {
data, err := generateSampleConfig()
Expect(err).To(BeNil())
err = ioutil.WriteFile(rootOptions.ConfigFile, data, 0664)
Expect(err).To(BeNil())
jobName := "fakeJob"
request, _ := http.NewRequest("POST", fmt.Sprintf("http://localhost:8080/jenkins/job/%s/doDelete", jobName), nil)
request.Header.Add("CrumbRequestField", "Crumb")
request.SetBasicAuth("admin", "111e3a2f0231198855dceaff96f20540a9")
request.Header.Add(util.CONTENT_TYPE, util.APP_FORM)
response := &http.Response{
StatusCode: 200,
Proto: "HTTP/1.1",
Request: request,
Body: ioutil.NopCloser(bytes.NewBufferString("")),
}
roundTripper.EXPECT().
RoundTrip(request).Return(response, nil)
requestCrumb, _ := http.NewRequest("GET", "http://localhost:8080/jenkins/crumbIssuer/api/json", nil)
requestCrumb.SetBasicAuth("admin", "111e3a2f0231198855dceaff96f20540a9")
responseCrumb := &http.Response{
StatusCode: 200,
Proto: "HTTP/1.1",
Request: requestCrumb,
Body: ioutil.NopCloser(bytes.NewBufferString(`
{"crumbRequestField":"CrumbRequestField","crumb":"Crumb"}
`)),
}
roundTripper.EXPECT().
RoundTrip(requestCrumb).Return(responseCrumb, nil)
rootCmd.SetArgs([]string{"job", "delete", jobName, "-b", "true"})
buf := new(bytes.Buffer)
rootCmd.SetOutput(buf)
_, err = rootCmd.ExecuteC()
Expect(err).To(BeNil())
Expect(buf.String()).To(Equal(""))
})
})
})
package cmd
import (
"fmt"
"log"
"net/http"
"github.com/jenkins-zh/jenkins-cli/client"
"github.com/spf13/cobra"
......@@ -10,6 +10,8 @@ import (
type JobSearchOption struct {
OutputOption
RoundTripper http.RoundTripper
}
var jobSearchOption JobSearchOption
......@@ -31,18 +33,17 @@ var jobSearchCmd = &cobra.Command{
keyword := args[0]
jenkins := getCurrentJenkinsFromOptionsOrDie()
jclient := &client.JobClient{}
jclient.URL = jenkins.URL
jclient.UserName = jenkins.UserName
jclient.Token = jenkins.Token
jclient.Proxy = jenkins.Proxy
jclient.ProxyAuth = jenkins.ProxyAuth
jclient := &client.JobClient{
JenkinsCore: client.JenkinsCore{
RoundTripper: jobSearchOption.RoundTripper,
},
}
getCurrentJenkinsAndClient(&(jclient.JenkinsCore))
if status, err := jclient.Search(keyword); err == nil {
var data []byte
if data, err = Format(status, queueOption.Format); err == nil {
fmt.Printf("%s\n", string(data))
cmd.Println(string(data))
} else {
log.Fatal(err)
}
......
package cmd
import (
"bytes"
"fmt"
"io/ioutil"
"net/http"
"os"
"github.com/golang/mock/gomock"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/jenkins-zh/jenkins-cli/mock/mhttp"
)
var _ = Describe("job search command", func() {
var (
ctrl *gomock.Controller
roundTripper *mhttp.MockRoundTripper
)
BeforeEach(func() {
ctrl = gomock.NewController(GinkgoT())
roundTripper = mhttp.NewMockRoundTripper(ctrl)
jobSearchOption.RoundTripper = roundTripper
rootCmd.SetArgs([]string{})
rootOptions.Jenkins = ""
rootOptions.ConfigFile = "test.yaml"
})
AfterEach(func() {
rootCmd.SetArgs([]string{})
os.Remove(rootOptions.ConfigFile)
rootOptions.ConfigFile = ""
ctrl.Finish()
})
Context("basic cases", func() {
It("should success, search with one result item", func() {
data, err := generateSampleConfig()
Expect(err).To(BeNil())
err = ioutil.WriteFile(rootOptions.ConfigFile, data, 0664)
Expect(err).To(BeNil())
keyword := "fake"
request, _ := http.NewRequest("GET", fmt.Sprintf("http://localhost:8080/jenkins/search/suggest?query=%s", keyword), nil)
request.SetBasicAuth("admin", "111e3a2f0231198855dceaff96f20540a9")
response := &http.Response{
StatusCode: 200,
Proto: "HTTP/1.1",
Request: request,
Body: ioutil.NopCloser(bytes.NewBufferString(`{"suggestions": [{"name": "fake"}]}`)),
}
roundTripper.EXPECT().
RoundTrip(request).Return(response, nil)
rootCmd.SetArgs([]string{"job", "search", keyword})
buf := new(bytes.Buffer)
rootCmd.SetOutput(buf)
_, err = rootCmd.ExecuteC()
Expect(err).To(BeNil())
Expect(buf.String()).To(Equal(`{
"Suggestions": [
{
"Name": "fake"
}
]
}
`))
})
})
})
......@@ -3,6 +3,7 @@ package cmd
import (
"fmt"
"log"
"net/http"
"strconv"
"github.com/jenkins-zh/jenkins-cli/client"
......@@ -11,6 +12,8 @@ import (
type JobStopOption struct {
BatchOption
RoundTripper http.RoundTripper
}
var jobStopOption JobStopOption
......@@ -35,7 +38,8 @@ var jobStopCmd = &cobra.Command{
err error
)
if buildNum, err = strconv.Atoi(args[1]); err != nil {
log.Fatal(err)
cmd.PrintErrln(err)
return
}
jobName := args[0]
......@@ -43,13 +47,12 @@ var jobStopCmd = &cobra.Command{
return
}
jenkins := getCurrentJenkinsFromOptionsOrDie()
jclient := &client.JobClient{}
jclient.URL = jenkins.URL
jclient.UserName = jenkins.UserName
jclient.Token = jenkins.Token
jclient.Proxy = jenkins.Proxy
jclient.ProxyAuth = jenkins.ProxyAuth
jclient := &client.JobClient{
JenkinsCore: client.JenkinsCore{
RoundTripper: jobStopOption.RoundTripper,
},
}
getCurrentJenkinsAndClient(&(jclient.JenkinsCore))
if err := jclient.StopJob(jobName, buildNum); err != nil {
log.Fatal(err)
......
package cmd
import (
"bytes"
"fmt"
"io/ioutil"
"net/http"
"os"
"github.com/golang/mock/gomock"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/jenkins-zh/jenkins-cli/mock/mhttp"
)
var _ = Describe("job stop command", func() {
var (
ctrl *gomock.Controller
roundTripper *mhttp.MockRoundTripper
)
BeforeEach(func() {
ctrl = gomock.NewController(GinkgoT())
roundTripper = mhttp.NewMockRoundTripper(ctrl)
jobStopOption.RoundTripper = roundTripper
rootCmd.SetArgs([]string{})
rootOptions.Jenkins = ""
rootOptions.ConfigFile = "test.yaml"
})
AfterEach(func() {
rootCmd.SetArgs([]string{})
os.Remove(rootOptions.ConfigFile)
rootOptions.ConfigFile = ""
ctrl.Finish()
})
Context("basic cases", func() {
It("should success, with batch mode", func() {
data, err := generateSampleConfig()
Expect(err).To(BeNil())
err = ioutil.WriteFile(rootOptions.ConfigFile, data, 0664)
Expect(err).To(BeNil())
jobName := "fakeJob"
buildID := 1
request, _ := http.NewRequest("POST", fmt.Sprintf("http://localhost:8080/jenkins/job/%s/%d/stop", jobName, buildID), nil)
request.Header.Add("CrumbRequestField", "Crumb")
request.SetBasicAuth("admin", "111e3a2f0231198855dceaff96f20540a9")
response := &http.Response{
StatusCode: 200,
Proto: "HTTP/1.1",
Request: request,
Body: ioutil.NopCloser(bytes.NewBufferString("")),
}
roundTripper.EXPECT().
RoundTrip(request).Return(response, nil)
requestCrumb, _ := http.NewRequest("GET", "http://localhost:8080/jenkins/crumbIssuer/api/json", nil)
requestCrumb.SetBasicAuth("admin", "111e3a2f0231198855dceaff96f20540a9")
responseCrumb := &http.Response{
StatusCode: 200,
Proto: "HTTP/1.1",
Request: requestCrumb,
Body: ioutil.NopCloser(bytes.NewBufferString(`
{"crumbRequestField":"CrumbRequestField","crumb":"Crumb"}
`)),
}
roundTripper.EXPECT().
RoundTrip(requestCrumb).Return(responseCrumb, nil)
rootCmd.SetArgs([]string{"job", "stop", jobName, "1", "-b", "true"})
buf := new(bytes.Buffer)
rootCmd.SetOutput(buf)
_, err = rootCmd.ExecuteC()
Expect(err).To(BeNil())
Expect(buf.String()).To(Equal(""))
})
})
})
package cmd
import (
"bytes"
"fmt"
"log"
"os"
"net/http"
"github.com/jenkins-zh/jenkins-cli/client"
"github.com/jenkins-zh/jenkins-cli/util"
......@@ -12,6 +13,8 @@ import (
type JobTypeOption struct {
OutputOption
RoundTripper http.RoundTripper
}
var jobTypeOption JobTypeOption
......@@ -25,20 +28,19 @@ var jobTypeCmd = &cobra.Command{
Use: "type",
Short: "Print the types of job which in your Jenkins",
Long: `Print the types of job which in your Jenkins`,
Run: func(_ *cobra.Command, _ []string) {
jenkins := getCurrentJenkinsFromOptionsOrDie()
jclient := &client.JobClient{}
jclient.URL = jenkins.URL
jclient.UserName = jenkins.UserName
jclient.Token = jenkins.Token
jclient.Proxy = jenkins.Proxy
jclient.ProxyAuth = jenkins.ProxyAuth
Run: func(cmd *cobra.Command, _ []string) {
jclient := &client.JobClient{
JenkinsCore: client.JenkinsCore{
RoundTripper: centerUpgradeOption.RoundTripper,
},
}
getCurrentJenkinsAndClient(&(jclient.JenkinsCore))
if status, err := jclient.GetJobTypeCategories(); err == nil {
var data []byte
if data, err = jobTypeOption.Output(status); err == nil {
if len(data) > 0 {
fmt.Printf("%s\n", string(data))
cmd.Print(string(data))
}
} else {
log.Fatal(err)
......@@ -49,10 +51,13 @@ var jobTypeCmd = &cobra.Command{
},
}
// Output renders data into a table
func (o *JobTypeOption) Output(obj interface{}) (data []byte, err error) {
if data, err = o.OutputOption.Output(obj); err != nil {
buf := new(bytes.Buffer)
jobCategories := obj.([]client.JobCategory)
table := util.CreateTable(os.Stdout)
table := util.CreateTable(buf)
table.AddRow("number", "name", "type")
for _, jobCategory := range jobCategories {
for i, item := range jobCategory.Items {
......@@ -62,7 +67,7 @@ func (o *JobTypeOption) Output(obj interface{}) (data []byte, err error) {
}
table.Render()
err = nil
data = []byte{}
data = buf.Bytes()
}
return
}
package cmd
import (
"bytes"
"io/ioutil"
"net/http"
"os"
"github.com/golang/mock/gomock"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/jenkins-zh/jenkins-cli/mock/mhttp"
)
var _ = Describe("job type command", func() {
var (
ctrl *gomock.Controller
roundTripper *mhttp.MockRoundTripper
)
BeforeEach(func() {
ctrl = gomock.NewController(GinkgoT())
roundTripper = mhttp.NewMockRoundTripper(ctrl)
centerUpgradeOption.RoundTripper = roundTripper
rootCmd.SetArgs([]string{})
rootOptions.Jenkins = ""
rootOptions.ConfigFile = "test.yaml"
})
AfterEach(func() {
rootCmd.SetArgs([]string{})
os.Remove(rootOptions.ConfigFile)
rootOptions.ConfigFile = ""
ctrl.Finish()
})
Context("basic cases", func() {
It("should success, empty list", func() {
data, err := generateSampleConfig()
Expect(err).To(BeNil())
err = ioutil.WriteFile(rootOptions.ConfigFile, data, 0664)
Expect(err).To(BeNil())
request, _ := http.NewRequest("GET", "http://localhost:8080/jenkins/view/all/itemCategories?depth=3", nil)
request.SetBasicAuth("admin", "111e3a2f0231198855dceaff96f20540a9")
response := &http.Response{
StatusCode: 200,
Proto: "HTTP/1.1",
Request: request,
Body: ioutil.NopCloser(bytes.NewBufferString("{}")),
}
roundTripper.EXPECT().
RoundTrip(request).Return(response, nil)
rootCmd.SetArgs([]string{"job", "type"})
buf := new(bytes.Buffer)
rootCmd.SetOutput(buf)
_, err = rootCmd.ExecuteC()
Expect(err).To(BeNil())
Expect(buf.String()).To(Equal("number name type\n"))
})
It("should success, empty list", func() {
data, err := generateSampleConfig()
Expect(err).To(BeNil())
err = ioutil.WriteFile(rootOptions.ConfigFile, data, 0664)
Expect(err).To(BeNil())
request, _ := http.NewRequest("GET", "http://localhost:8080/jenkins/view/all/itemCategories?depth=3", nil)
request.SetBasicAuth("admin", "111e3a2f0231198855dceaff96f20540a9")
response := &http.Response{
StatusCode: 200,
Proto: "HTTP/1.1",
Request: request,
Body: ioutil.NopCloser(bytes.NewBufferString("{}")),
}
roundTripper.EXPECT().
RoundTrip(request).Return(response, nil)
rootCmd.SetArgs([]string{"job", "type"})
buf := new(bytes.Buffer)
rootCmd.SetOutput(buf)
_, err = rootCmd.ExecuteC()
Expect(err).To(BeNil())
Expect(buf.String()).To(Equal("number name type\n"))
})
It("should success, one item", func() {
data, err := generateSampleConfig()
Expect(err).To(BeNil())
err = ioutil.WriteFile(rootOptions.ConfigFile, data, 0664)
Expect(err).To(BeNil())
request, _ := http.NewRequest("GET", "http://localhost:8080/jenkins/view/all/itemCategories?depth=3", nil)
request.SetBasicAuth("admin", "111e3a2f0231198855dceaff96f20540a9")
response := &http.Response{
StatusCode: 200,
Proto: "HTTP/1.1",
Request: request,
Body: ioutil.NopCloser(bytes.NewBufferString(`
{"categories":[
{
"description" : "description",
"id" : "standalone-projects",
"items" : [
{
"displayName" : "displayName",
"iconFilePathPattern" : "iconFilePathPattern",
"description" : "description",
"iconClassName" : "iconClassName",
"class" : "class",
"order" : 1
}],
"minToShow" : 1,
"name" : "Nested Projects",
"order" : 1
}]
}`)),
}
roundTripper.EXPECT().
RoundTrip(request).Return(response, nil)
buf := new(bytes.Buffer)
rootCmd.SetOutput(buf)
rootCmd.SetArgs([]string{"job", "type"})
_, err = rootCmd.ExecuteC()
Expect(err).To(BeNil())
Expect(buf.String()).To(Equal(`number name type
0 displayName Nested Projects
`))
})
})
})
package cmd
import (
"bytes"
"fmt"
"log"
"os"
"net/http"
"strings"
"github.com/jenkins-zh/jenkins-cli/client"
......@@ -13,6 +14,8 @@ import (
type PluginSearchOption struct {
OutputOption
RoundTripper http.RoundTripper
}
var pluginSearchOption PluginSearchOption
......@@ -34,20 +37,19 @@ var pluginSearchCmd = &cobra.Command{
keyword := args[0]
jenkins := getCurrentJenkinsFromOptionsOrDie()
jclient := &client.PluginManager{}
jclient.URL = jenkins.URL
jclient.UserName = jenkins.UserName
jclient.Token = jenkins.Token
jclient.Proxy = jenkins.Proxy
jclient.ProxyAuth = jenkins.ProxyAuth
jclient := &client.PluginManager{
JenkinsCore: client.JenkinsCore{
RoundTripper: pluginSearchOption.RoundTripper,
},
}
getCurrentJenkinsAndClient(&(jclient.JenkinsCore))
if plugins, err := jclient.GetAvailablePlugins(); err == nil {
result := searchPlugins(plugins, keyword)
if data, err := pluginSearchOption.Output(result); err == nil {
if len(data) > 0 {
fmt.Println(string(data))
cmd.Print(string(data))
}
} else {
log.Fatal(err)
......@@ -69,11 +71,14 @@ func searchPlugins(plugins *client.AvailablePluginList, keyword string) []client
return result
}
// Output output the data into buffer
func (o *PluginSearchOption) Output(obj interface{}) (data []byte, err error) {
if data, err = o.OutputOption.Output(obj); err != nil {
pluginList := obj.([]client.AvailablePlugin)
buf := new(bytes.Buffer)
if len(pluginList) != 0 {
table := util.CreateTable(os.Stdout)
table := util.CreateTable(buf)
table.AddRow("number", "name", "installed", "title")
for i, plugin := range pluginList {
......@@ -83,7 +88,7 @@ func (o *PluginSearchOption) Output(obj interface{}) (data []byte, err error) {
table.Render()
}
err = nil
data = []byte{}
data = buf.Bytes()
}
return
}
package cmd
import (
"bytes"
"io/ioutil"
"os"
"github.com/golang/mock/gomock"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/jenkins-zh/jenkins-cli/client"
"github.com/jenkins-zh/jenkins-cli/mock/mhttp"
)
var _ = Describe("plugin search command", func() {
var (
ctrl *gomock.Controller
roundTripper *mhttp.MockRoundTripper
)
BeforeEach(func() {
ctrl = gomock.NewController(GinkgoT())
roundTripper = mhttp.NewMockRoundTripper(ctrl)
pluginSearchOption.RoundTripper = roundTripper
rootCmd.SetArgs([]string{})
rootOptions.Jenkins = ""
rootOptions.ConfigFile = "test.yaml"
})
AfterEach(func() {
rootCmd.SetArgs([]string{})
os.Remove(rootOptions.ConfigFile)
rootOptions.ConfigFile = ""
ctrl.Finish()
})
Context("basic cases", func() {
It("should success, empty list", func() {
data, err := generateSampleConfig()
Expect(err).To(BeNil())
err = ioutil.WriteFile(rootOptions.ConfigFile, data, 0664)
Expect(err).To(BeNil())
request, _ := client.PrepareForEmptyAvaiablePluginList(roundTripper, "http://localhost:8080/jenkins")
request.SetBasicAuth("admin", "111e3a2f0231198855dceaff96f20540a9")
rootCmd.SetArgs([]string{"plugin", "search", "fake"})
buf := new(bytes.Buffer)
rootCmd.SetOutput(buf)
_, err = rootCmd.ExecuteC()
Expect(err).To(BeNil())
Expect(buf.String()).To(Equal(""))
})
It("one plugin in the list", func() {
data, err := generateSampleConfig()
Expect(err).To(BeNil())
err = ioutil.WriteFile(rootOptions.ConfigFile, data, 0664)
Expect(err).To(BeNil())
request, _ := client.PrepareForOneAvaiablePlugin(roundTripper, "http://localhost:8080/jenkins")
request.SetBasicAuth("admin", "111e3a2f0231198855dceaff96f20540a9")
rootCmd.SetArgs([]string{"plugin", "search", "fake"})
buf := new(bytes.Buffer)
rootCmd.SetOutput(buf)
_, err = rootCmd.ExecuteC()
Expect(err).To(BeNil())
Expect(buf.String()).To(Equal(`number name installed title
0 fake false fake
`))
})
})
})
......@@ -5,12 +5,14 @@ import (
"encoding/base64"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"log"
"net/http"
"net/url"
)
// JenkinsCore core informations of Jenkins
type JenkinsCore struct {
JenkinsCrumb
URL string
......@@ -23,6 +25,7 @@ type JenkinsCore struct {
RoundTripper http.RoundTripper
}
// JenkinsCrumb crumb for Jenkins
type JenkinsCrumb struct {
CrumbRequestField string
Crumb string
......@@ -75,6 +78,7 @@ func (j *JenkinsCore) AuthHandle(request *http.Request) (err error) {
return
}
// CrumbHandle handle crum with http request
func (j *JenkinsCore) CrumbHandle(request *http.Request) error {
if c, err := j.GetCrumb(); err == nil && c != nil {
// cannot get the crumb could be a noraml situation
......@@ -88,32 +92,47 @@ func (j *JenkinsCore) CrumbHandle(request *http.Request) error {
return nil
}
func (j *JenkinsCore) GetCrumb() (*JenkinsCrumb, error) {
api := fmt.Sprintf("%s/crumbIssuer/api/json", j.URL)
// GetCrumb get the crumb from Jenkins
func (j *JenkinsCore) GetCrumb() (crumbIssuer *JenkinsCrumb, err error) {
var (
statusCode int
data []byte
)
req, err := http.NewRequest("GET", api, nil)
if err != nil {
return nil, err
if statusCode, data, err = j.Request("GET", "/crumbIssuer/api/json", nil, nil); err == nil {
if statusCode == 200 {
json.Unmarshal(data, &crumbIssuer)
} else if statusCode == 404 {
// return 404 if Jenkins does no have crumb
} else {
err = fmt.Errorf("unexpected status code: %d", statusCode)
}
}
return
}
// Request make a common request
func (j *JenkinsCore) Request(method, api string, headers map[string]string, payload io.Reader) (
statusCode int, data []byte, err error) {
var (
req *http.Request
response *http.Response
)
if req, err = http.NewRequest(method, fmt.Sprintf("%s%s", j.URL, api), payload); err != nil {
return
}
j.AuthHandle(req)
var crumbIssuer JenkinsCrumb
for k, v := range headers {
req.Header.Add(k, v)
}
client := j.GetClient()
if response, err := client.Do(req); err == nil {
if data, err := ioutil.ReadAll(response.Body); err == nil {
if response.StatusCode == 200 {
json.Unmarshal(data, &crumbIssuer)
} else if response.StatusCode == 404 {
return nil, err
} else {
log.Printf("Unexpected status code: %d.", response.StatusCode)
return nil, err
}
} else {
return nil, err
}
} else {
return nil, err
if response, err = client.Do(req); err == nil {
statusCode = response.StatusCode
data, err = ioutil.ReadAll(response.Body)
}
return &crumbIssuer, nil
return
}
package client
import (
"bytes"
"fmt"
"io"
"io/ioutil"
"net/http"
"github.com/golang/mock/gomock"
"github.com/jenkins-zh/jenkins-cli/mock/mhttp"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
var _ = Describe("common test", func() {
var (
ctrl *gomock.Controller
jenkinsCore JenkinsCore
roundTripper *mhttp.MockRoundTripper
)
BeforeEach(func() {
ctrl = gomock.NewController(GinkgoT())
jenkinsCore = JenkinsCore{}
roundTripper = mhttp.NewMockRoundTripper(ctrl)
jenkinsCore.RoundTripper = roundTripper
jenkinsCore.URL = "http://localhost"
})
AfterEach(func() {
ctrl.Finish()
})
Context("Request", func() {
var (
method string
api string
headers map[string]string
payload io.Reader
)
BeforeEach(func() {
method = "GET"
api = "/fake"
})
It("normal case for get request", func() {
request, _ := http.NewRequest(method, fmt.Sprintf("%s%s", jenkinsCore.URL, api), payload)
response := &http.Response{
StatusCode: 200,
Proto: "HTTP/1.1",
Header: http.Header{},
Request: request,
Body: ioutil.NopCloser(bytes.NewBufferString("")),
}
roundTripper.EXPECT().
RoundTrip(request).Return(response, nil)
statusCode, data, err := jenkinsCore.Request(method, api, headers, payload)
Expect(err).To(BeNil())
Expect(statusCode).To(Equal(200))
Expect(string(data)).To(Equal(""))
})
It("normal case for post request", func() {
method = "POST"
request, _ := http.NewRequest(method, fmt.Sprintf("%s%s", jenkinsCore.URL, api), payload)
request.Header.Add("CrumbRequestField", "Crumb")
request.Header.Add("Fake", "fake")
response := &http.Response{
StatusCode: 200,
Proto: "HTTP/1.1",
Request: request,
Body: ioutil.NopCloser(bytes.NewBufferString("")),
}
roundTripper.EXPECT().
RoundTrip(request).Return(response, nil)
requestCrumb, _ := http.NewRequest("GET", fmt.Sprintf("%s%s", jenkinsCore.URL, "/crumbIssuer/api/json"), payload)
responseCrumb := &http.Response{
StatusCode: 200,
Proto: "HTTP/1.1",
Request: requestCrumb,
Body: ioutil.NopCloser(bytes.NewBufferString(`
{"crumbRequestField":"CrumbRequestField","crumb":"Crumb"}
`)),
}
roundTripper.EXPECT().
RoundTrip(requestCrumb).Return(responseCrumb, nil)
headers = make(map[string]string, 1)
headers["fake"] = "fake"
statusCode, data, err := jenkinsCore.Request(method, api, headers, payload)
Expect(err).To(BeNil())
Expect(statusCode).To(Equal(200))
Expect(string(data)).To(Equal(""))
})
})
Context("GetCrumb", func() {
It("without crumb setting", func() {
requestCrumb, _ := http.NewRequest("GET", fmt.Sprintf("%s%s", jenkinsCore.URL, "/crumbIssuer/api/json"), nil)
responseCrumb := &http.Response{
StatusCode: 404,
Proto: "HTTP/1.1",
Request: requestCrumb,
Body: ioutil.NopCloser(bytes.NewBufferString("")),
}
roundTripper.EXPECT().
RoundTrip(requestCrumb).Return(responseCrumb, nil)
crumb, err := jenkinsCore.GetCrumb()
Expect(crumb).To(BeNil())
Expect(err).To(BeNil())
})
It("with crumb setting", func() {
RequestCrumb(roundTripper, jenkinsCore.URL)
crumb, err := jenkinsCore.GetCrumb()
Expect(err).To(BeNil())
Expect(crumb).NotTo(BeNil())
Expect(crumb.CrumbRequestField).To(Equal("CrumbRequestField"))
Expect(crumb.Crumb).To(Equal("Crumb"))
})
It("with error from server", func() {
requestCrumb, _ := http.NewRequest("GET", fmt.Sprintf("%s%s", jenkinsCore.URL, "/crumbIssuer/api/json"), nil)
responseCrumb := &http.Response{
StatusCode: 500,
Proto: "HTTP/1.1",
Request: requestCrumb,
Body: ioutil.NopCloser(bytes.NewBufferString("")),
}
roundTripper.EXPECT().
RoundTrip(requestCrumb).Return(responseCrumb, nil)
_, err := jenkinsCore.GetCrumb()
Expect(err).To(HaveOccurred())
})
})
})
// RequestCrumb only for the test case
func RequestCrumb(roundTripper *mhttp.MockRoundTripper, rootURL string) {
requestCrumb, _ := http.NewRequest("GET", fmt.Sprintf("%s%s", rootURL, "/crumbIssuer/api/json"), nil)
responseCrumb := &http.Response{
StatusCode: 200,
Proto: "HTTP/1.1",
Request: requestCrumb,
Body: ioutil.NopCloser(bytes.NewBufferString(`
{"crumbRequestField":"CrumbRequestField","crumb":"Crumb"}
`)),
}
roundTripper.EXPECT().
RoundTrip(requestCrumb).Return(responseCrumb, nil)
}
......@@ -13,115 +13,80 @@ import (
"github.com/jenkins-zh/jenkins-cli/util"
)
// JobClient is client for operate jobs
type JobClient struct {
JenkinsCore
}
// Search find a set of jobs by name
func (q *JobClient) Search(keyword string) (status *SearchResult, err error) {
api := fmt.Sprintf("%s/search/suggest?query=%s", q.URL, keyword)
var (
req *http.Request
response *http.Response
statusCode int
data []byte
)
req, err = http.NewRequest("GET", api, nil)
if err == nil {
q.AuthHandle(req)
} else {
return
}
client := q.GetClient()
if response, err = client.Do(req); err == nil {
code := response.StatusCode
var data []byte
data, err = ioutil.ReadAll(response.Body)
if code == 200 {
if err == nil {
status = &SearchResult{}
err = json.Unmarshal(data, status)
}
if statusCode, data, err = q.Request("GET", fmt.Sprintf("/search/suggest?query=%s", keyword), nil, nil); err == nil {
if statusCode == 200 {
json.Unmarshal(data, &status)
} else {
log.Fatal(string(data))
err = fmt.Errorf("unexpected status code: %d", statusCode)
}
} else {
log.Fatal(err)
}
return
}
// Build trigger a job
func (q *JobClient) Build(jobName string) (err error) {
path := parseJobPath(jobName)
api := fmt.Sprintf("%s/%s/build", q.URL, path)
var (
req *http.Request
response *http.Response
statusCode int
data []byte
)
req, err = http.NewRequest("POST", api, nil)
if err == nil {
q.AuthHandle(req)
} else {
return
}
if err = q.CrumbHandle(req); err != nil {
log.Fatal(err)
}
client := q.GetClient()
if response, err = client.Do(req); err == nil {
code := response.StatusCode
var data []byte
data, err = ioutil.ReadAll(response.Body)
if code == 201 { // Jenkins will send redirect by this api
if statusCode, data, err = q.Request("POST", fmt.Sprintf("%s/build", path), nil, nil); err == nil {
if statusCode == 201 {
fmt.Println("build successfully")
} else {
log.Fatal(string(data))
err = fmt.Errorf("unexpected status code: %d", statusCode)
if q.Debug {
ioutil.WriteFile("debug.html", data, 0664)
}
}
} else {
log.Fatal(err)
}
return
}
// GetBuild get build information of a job
func (q *JobClient) GetBuild(jobName string, id int) (job *JobBuild, err error) {
path := parseJobPath(jobName)
var api string
if id == -1 {
api = fmt.Sprintf("%s/%s/lastBuild/api/json", q.URL, path)
api = fmt.Sprintf("%s/lastBuild/api/json", path)
} else {
api = fmt.Sprintf("%s/%s/%d/api/json", q.URL, path, id)
api = fmt.Sprintf("%s/%d/api/json", path, id)
}
var (
req *http.Request
response *http.Response
statusCode int
data []byte
)
req, err = http.NewRequest("GET", api, nil)
if err == nil {
q.AuthHandle(req)
} else {
return
}
client := q.GetClient()
if response, err = client.Do(req); err == nil {
code := response.StatusCode
var data []byte
data, err = ioutil.ReadAll(response.Body)
if code == 200 {
if statusCode, data, err = q.Request("GET", api, nil, nil); err == nil {
if statusCode == 200 {
job = &JobBuild{}
err = json.Unmarshal(data, job)
} else {
log.Fatal(string(data))
err = fmt.Errorf("unexpected status code: %d", statusCode)
if q.Debug {
ioutil.WriteFile("debug.html", data, 0664)
}
}
} else {
log.Fatal(err)
}
return
}
// BuildWithParams build a job which has params
func (q *JobClient) BuildWithParams(jobName string, parameters []ParameterDefinition) (err error) {
path := parseJobPath(jobName)
api := fmt.Sprintf("%s/%s/build", q.URL, path)
......@@ -170,92 +135,60 @@ func (q *JobClient) BuildWithParams(jobName string, parameters []ParameterDefini
return
}
// StopJob stops a job build
func (q *JobClient) StopJob(jobName string, num int) (err error) {
path := parseJobPath(jobName)
api := fmt.Sprintf("%s/%s/%d/stop", q.URL, path, num)
api := fmt.Sprintf("%s/%d/stop", path, num)
var (
req *http.Request
response *http.Response
statusCode int
data []byte
)
req, err = http.NewRequest("POST", api, nil)
if err == nil {
q.AuthHandle(req)
} else {
return
}
client := q.GetClient()
if response, err = client.Do(req); err == nil {
code := response.StatusCode
var data []byte
data, err = ioutil.ReadAll(response.Body)
if code == 200 {
if statusCode, data, err = q.Request("POST", api, nil, nil); err == nil {
if statusCode == 200 {
fmt.Println("stoped successfully")
} else {
fmt.Println("status code", code)
err = fmt.Errorf("unexpected status code: %d", statusCode)
if q.Debug {
ioutil.WriteFile("debug.html", data, 0664)
}
}
} else {
log.Fatal(err)
}
return
}
// GetJob returns the job info
func (q *JobClient) GetJob(name string) (job *Job, err error) {
path := parseJobPath(name)
api := fmt.Sprintf("%s/%s/api/json", q.URL, path)
api := fmt.Sprintf("%s/api/json", path)
var (
req *http.Request
response *http.Response
statusCode int
data []byte
)
req, err = http.NewRequest("GET", api, nil)
if err == nil {
q.AuthHandle(req)
} else {
return
}
client := q.GetClient()
if response, err = client.Do(req); err == nil {
code := response.StatusCode
var data []byte
data, err = ioutil.ReadAll(response.Body)
if code == 200 {
if statusCode, data, err = q.Request("GET", api, nil, nil); err == nil {
if statusCode == 200 {
job = &Job{}
err = json.Unmarshal(data, job)
} else {
log.Fatal(string(data))
err = fmt.Errorf("unexpected status code: %d", statusCode)
if q.Debug {
ioutil.WriteFile("debug.html", data, 0664)
}
}
} else {
log.Fatal(err)
}
return
}
// GetJobTypeCategories returns all categories of jobs
func (q *JobClient) GetJobTypeCategories() (jobCategories []JobCategory, err error) {
api := fmt.Sprintf("%s/view/all/itemCategories?depth=3", q.URL)
var (
req *http.Request
response *http.Response
statusCode int
data []byte
)
req, err = http.NewRequest("GET", api, nil)
if err == nil {
q.AuthHandle(req)
} else {
return
}
client := q.GetClient()
if response, err = client.Do(req); err == nil {
code := response.StatusCode
var data []byte
data, err = ioutil.ReadAll(response.Body)
if code == 200 {
if statusCode, data, err = q.Request("GET", "/view/all/itemCategories?depth=3", nil, nil); err == nil {
if statusCode == 200 {
type innerJobCategories struct {
Categories []JobCategory
}
......@@ -263,10 +196,11 @@ func (q *JobClient) GetJobTypeCategories() (jobCategories []JobCategory, err err
err = json.Unmarshal(data, result)
jobCategories = result.Categories
} else {
log.Fatal(string(data))
err = fmt.Errorf("unexpected status code: %d", statusCode)
if q.Debug {
ioutil.WriteFile("debug.html", data, 0664)
}
}
} else {
log.Fatal(err)
}
return
}
......@@ -342,6 +276,7 @@ func (q *JobClient) GetPipeline(name string) (pipeline *Pipeline, err error) {
return
}
// GetHistory returns the build history of a job
func (q *JobClient) GetHistory(name string) (builds []JobBuild, err error) {
var job *Job
if job, err = q.GetJob(name); err == nil {
......@@ -479,37 +414,32 @@ func (q *JobClient) Create(jobName string, jobType string) (err error) {
return
}
// Delete will delete a job by name
func (q *JobClient) Delete(jobName string) (err error) {
api := fmt.Sprintf("%s/job/%s/doDelete", q.URL, jobName)
var (
req *http.Request
response *http.Response
statusCode int
data []byte
)
req, err = http.NewRequest("POST", api, nil)
if err == nil {
q.AuthHandle(req)
} else {
return
api := fmt.Sprintf("/job/%s/doDelete", jobName)
header := map[string]string{
util.CONTENT_TYPE: util.APP_FORM,
}
req.Header.Add(util.CONTENT_TYPE, util.APP_FORM)
client := q.GetClient()
if response, err = client.Do(req); err == nil {
code := response.StatusCode
var data []byte
data, err = ioutil.ReadAll(response.Body)
if code == 302 || code == 200 { // Jenkins will send redirect by this api
if statusCode, data, err = q.Request("POST", api, header, nil); err == nil {
if statusCode == 200 || statusCode == 302 {
fmt.Println("delete successfully")
} else {
fmt.Printf("status code: %d\n", code)
log.Fatal(string(data))
err = fmt.Errorf("unexpected status code: %d", statusCode)
if q.Debug {
ioutil.WriteFile("debug.html", data, 0664)
}
}
} else {
log.Fatal(err)
}
return
}
// parseJobPath leads with slash
func parseJobPath(jobName string) (path string) {
jobItems := strings.Split(jobName, " ")
path = ""
......@@ -519,12 +449,14 @@ func parseJobPath(jobName string) (path string) {
return
}
// JobLog holds the log text
type JobLog struct {
HasMore bool
NextStart int64
Text string
}
// SearchResult holds the result items
type SearchResult struct {
Suggestions []SearchResultItem
}
......
package client
import (
"bytes"
"fmt"
"io/ioutil"
"net/http"
"github.com/golang/mock/gomock"
"github.com/jenkins-zh/jenkins-cli/mock/mhttp"
"github.com/jenkins-zh/jenkins-cli/util"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
var _ = Describe("job test", func() {
var (
ctrl *gomock.Controller
jobClient JobClient
roundTripper *mhttp.MockRoundTripper
)
BeforeEach(func() {
ctrl = gomock.NewController(GinkgoT())
jobClient = JobClient{}
roundTripper = mhttp.NewMockRoundTripper(ctrl)
jobClient.RoundTripper = roundTripper
jobClient.URL = "http://localhost"
})
AfterEach(func() {
ctrl.Finish()
})
Context("Search", func() {
It("basic case with one result item", func() {
keyword := "fake"
request, _ := http.NewRequest("GET", fmt.Sprintf("%s%s%s", jobClient.URL, "/search/suggest?query=", keyword), nil)
response := &http.Response{
StatusCode: 200,
Proto: "HTTP/1.1",
Request: request,
Body: ioutil.NopCloser(bytes.NewBufferString(`{"suggestions": [{"name": "fake"}]}`)),
}
roundTripper.EXPECT().
RoundTrip(request).Return(response, nil)
result, err := jobClient.Search(keyword)
Expect(err).To(BeNil())
Expect(result).NotTo(BeNil())
Expect(len(result.Suggestions)).To(Equal(1))
Expect(result.Suggestions[0].Name).To(Equal("fake"))
})
It("basic case without any result items", func() {
keyword := "fake"
request, _ := http.NewRequest("GET", fmt.Sprintf("%s%s%s", jobClient.URL, "/search/suggest?query=", keyword), nil)
response := &http.Response{
StatusCode: 200,
Proto: "HTTP/1.1",
Request: request,
Body: ioutil.NopCloser(bytes.NewBufferString(`{"suggestions":[]}`)),
}
roundTripper.EXPECT().
RoundTrip(request).Return(response, nil)
result, err := jobClient.Search(keyword)
Expect(err).To(BeNil())
Expect(result).NotTo(BeNil())
Expect(len(result.Suggestions)).To(Equal(0))
})
})
Context("Build", func() {
It("trigger a simple job without a folder", func() {
jobName := "fakeJob"
request, _ := http.NewRequest("POST", fmt.Sprintf("%s/job/%s/build", jobClient.URL, jobName), nil)
request.Header.Add("CrumbRequestField", "Crumb")
response := &http.Response{
StatusCode: 201,
Proto: "HTTP/1.1",
Request: request,
Body: ioutil.NopCloser(bytes.NewBufferString("")),
}
roundTripper.EXPECT().
RoundTrip(request).Return(response, nil)
requestCrumb, _ := http.NewRequest("GET", fmt.Sprintf("%s%s", jobClient.URL, "/crumbIssuer/api/json"), nil)
responseCrumb := &http.Response{
StatusCode: 200,
Proto: "HTTP/1.1",
Request: requestCrumb,
Body: ioutil.NopCloser(bytes.NewBufferString(`
{"crumbRequestField":"CrumbRequestField","crumb":"Crumb"}
`)),
}
roundTripper.EXPECT().
RoundTrip(requestCrumb).Return(responseCrumb, nil)
err := jobClient.Build(jobName)
Expect(err).To(BeNil())
})
It("trigger a simple job with an error", func() {
jobName := "fakeJob"
request, _ := http.NewRequest("POST", fmt.Sprintf("%s/job/%s/build", jobClient.URL, jobName), nil)
request.Header.Add("CrumbRequestField", "Crumb")
response := &http.Response{
StatusCode: 500,
Proto: "HTTP/1.1",
Request: request,
Body: ioutil.NopCloser(bytes.NewBufferString("")),
}
roundTripper.EXPECT().
RoundTrip(request).Return(response, nil)
requestCrumb, _ := http.NewRequest("GET", fmt.Sprintf("%s%s", jobClient.URL, "/crumbIssuer/api/json"), nil)
responseCrumb := &http.Response{
StatusCode: 200,
Proto: "HTTP/1.1",
Request: requestCrumb,
Body: ioutil.NopCloser(bytes.NewBufferString(`
{"crumbRequestField":"CrumbRequestField","crumb":"Crumb"}
`)),
}
roundTripper.EXPECT().
RoundTrip(requestCrumb).Return(responseCrumb, nil)
err := jobClient.Build(jobName)
Expect(err).To(HaveOccurred())
})
})
Context("GetBuild", func() {
It("basic case with the last build", func() {
jobName := "fake"
buildID := -1
request, _ := http.NewRequest("GET", fmt.Sprintf("%s/job/%s/lastBuild/api/json", jobClient.URL, jobName), nil)
response := &http.Response{
StatusCode: 200,
Proto: "HTTP/1.1",
Request: request,
Body: ioutil.NopCloser(bytes.NewBufferString(`
{"displayName":"fake"}
`)),
}
roundTripper.EXPECT().
RoundTrip(request).Return(response, nil)
result, err := jobClient.GetBuild(jobName, buildID)
Expect(err).To(BeNil())
Expect(result).NotTo(BeNil())
})
It("basic case with one build", func() {
jobName := "fake"
buildID := 2
request, _ := http.NewRequest("GET", fmt.Sprintf("%s/job/%s/%d/api/json", jobClient.URL, jobName, buildID), nil)
response := &http.Response{
StatusCode: 200,
Proto: "HTTP/1.1",
Request: request,
Body: ioutil.NopCloser(bytes.NewBufferString(`
{"displayName":"fake"}
`)),
}
roundTripper.EXPECT().
RoundTrip(request).Return(response, nil)
result, err := jobClient.GetBuild(jobName, buildID)
Expect(err).To(BeNil())
Expect(result).NotTo(BeNil())
})
})
Context("StopJob", func() {
It("stop a job build without a folder", func() {
jobName := "fakeJob"
buildID := 1
request, _ := http.NewRequest("POST", fmt.Sprintf("%s/job/%s/%d/stop", jobClient.URL, jobName, buildID), nil)
request.Header.Add("CrumbRequestField", "Crumb")
response := &http.Response{
StatusCode: 200,
Proto: "HTTP/1.1",
Request: request,
Body: ioutil.NopCloser(bytes.NewBufferString("")),
}
roundTripper.EXPECT().
RoundTrip(request).Return(response, nil)
requestCrumb, _ := http.NewRequest("GET", fmt.Sprintf("%s%s", jobClient.URL, "/crumbIssuer/api/json"), nil)
responseCrumb := &http.Response{
StatusCode: 200,
Proto: "HTTP/1.1",
Request: requestCrumb,
Body: ioutil.NopCloser(bytes.NewBufferString(`
{"crumbRequestField":"CrumbRequestField","crumb":"Crumb"}
`)),
}
roundTripper.EXPECT().
RoundTrip(requestCrumb).Return(responseCrumb, nil)
err := jobClient.StopJob(jobName, buildID)
Expect(err).To(BeNil())
})
})
Context("GetJob", func() {
It("get a job without in a folder", func() {
jobName := "fake"
request, _ := http.NewRequest("GET", fmt.Sprintf("%s/job/%s/api/json", jobClient.URL, jobName), nil)
response := &http.Response{
StatusCode: 200,
Proto: "HTTP/1.1",
Request: request,
Body: ioutil.NopCloser(bytes.NewBufferString(`
{"name":"fake"}
`)),
}
roundTripper.EXPECT().
RoundTrip(request).Return(response, nil)
result, err := jobClient.GetJob(jobName)
Expect(err).To(BeNil())
Expect(result).NotTo(BeNil())
Expect(result.Name).To(Equal(jobName))
})
})
Context("GetJobTypeCategories", func() {
It("simple case, should success", func() {
request, _ := http.NewRequest("GET", fmt.Sprintf("%s/view/all/itemCategories?depth=3", jobClient.URL), nil)
response := &http.Response{
StatusCode: 200,
Proto: "HTTP/1.1",
Request: request,
Body: ioutil.NopCloser(bytes.NewBufferString("{}")),
}
roundTripper.EXPECT().
RoundTrip(request).Return(response, nil)
_, err := jobClient.GetJobTypeCategories()
Expect(err).To(BeNil())
})
})
Context("Delete", func() {
It("delete a job", func() {
jobName := "fakeJob"
request, _ := http.NewRequest("POST", fmt.Sprintf("%s/job/%s/doDelete", jobClient.URL, jobName), nil)
request.Header.Add("CrumbRequestField", "Crumb")
request.Header.Add(util.CONTENT_TYPE, util.APP_FORM)
response := &http.Response{
StatusCode: 200,
Proto: "HTTP/1.1",
Request: request,
Body: ioutil.NopCloser(bytes.NewBufferString("")),
}
roundTripper.EXPECT().
RoundTrip(request).Return(response, nil)
requestCrumb, _ := http.NewRequest("GET", fmt.Sprintf("%s%s", jobClient.URL, "/crumbIssuer/api/json"), nil)
responseCrumb := &http.Response{
StatusCode: 200,
Proto: "HTTP/1.1",
Request: requestCrumb,
Body: ioutil.NopCloser(bytes.NewBufferString(`
{"crumbRequestField":"CrumbRequestField","crumb":"Crumb"}
`)),
}
roundTripper.EXPECT().
RoundTrip(requestCrumb).Return(responseCrumb, nil)
err := jobClient.Delete(jobName)
Expect(err).To(BeNil())
})
})
})
package client
import (
"bytes"
"fmt"
"io/ioutil"
"net/http"
"github.com/golang/mock/gomock"
"github.com/jenkins-zh/jenkins-cli/mock/mhttp"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
var _ = Describe("PluginManager test", func() {
var (
ctrl *gomock.Controller
ctrl *gomock.Controller
roundTripper *mhttp.MockRoundTripper
pluginMgr PluginManager
)
BeforeEach(func() {
ctrl = gomock.NewController(GinkgoT())
roundTripper = mhttp.NewMockRoundTripper(ctrl)
pluginMgr = PluginManager{}
pluginMgr.RoundTripper = roundTripper
pluginMgr.URL = "http://localhost"
})
AfterEach(func() {
......@@ -34,4 +46,156 @@ var _ = Describe("PluginManager test", func() {
Expect(getPluginsInstallQuery(names)).To(Equal("plugin.abc=&plugin.def="))
})
})
Context("GetAvailablePlugins", func() {
It("no plugin in the list", func() {
PrepareForEmptyAvaiablePluginList(roundTripper, pluginMgr.URL)
pluginList, err := pluginMgr.GetAvailablePlugins()
Expect(err).To(BeNil())
Expect(pluginList).NotTo(BeNil())
Expect(len(pluginList.Data)).To(Equal(0))
})
It("one plugin in the list", func() {
PrepareForOneAvaiablePlugin(roundTripper, pluginMgr.URL)
pluginList, err := pluginMgr.GetAvailablePlugins()
Expect(err).To(BeNil())
Expect(pluginList).NotTo(BeNil())
Expect(len(pluginList.Data)).To(Equal(1))
Expect(pluginList.Data[0].Name).To(Equal("fake"))
})
It("response with 500", func() {
request, _ := http.NewRequest("GET", fmt.Sprintf("%s/pluginManager/plugins", pluginMgr.URL), nil)
response := &http.Response{
StatusCode: 500,
Proto: "HTTP/1.1",
Request: request,
Body: ioutil.NopCloser(bytes.NewBufferString("")),
}
roundTripper.EXPECT().
RoundTrip(request).Return(response, nil)
_, err := pluginMgr.GetAvailablePlugins()
Expect(err).To(HaveOccurred())
})
})
Context("GetPlugins", func() {
var (
api string
)
BeforeEach(func() {
api = fmt.Sprintf("%s/pluginManager/api/json?depth=1", pluginMgr.URL)
})
It("no plugin in the list", func() {
request, _ := http.NewRequest("GET", api, nil)
response := &http.Response{
StatusCode: 200,
Proto: "HTTP/1.1",
Request: request,
Body: ioutil.NopCloser(bytes.NewBufferString(`{
"plugins": []
}`)),
}
roundTripper.EXPECT().
RoundTrip(request).Return(response, nil)
pluginList, err := pluginMgr.GetPlugins()
Expect(err).To(BeNil())
Expect(pluginList).NotTo(BeNil())
Expect(len(pluginList.Plugins)).To(Equal(0))
})
It("one plugin in the list", func() {
request, _ := http.NewRequest("GET", api, nil)
response := &http.Response{
StatusCode: 200,
Proto: "HTTP/1.1",
Request: request,
Body: ioutil.NopCloser(bytes.NewBufferString(`{
"plugins": [{
"shortName": "fake"
}]
}`)),
}
roundTripper.EXPECT().
RoundTrip(request).Return(response, nil)
pluginList, err := pluginMgr.GetPlugins()
Expect(err).To(BeNil())
Expect(pluginList).NotTo(BeNil())
Expect(len(pluginList.Plugins)).To(Equal(1))
Expect(pluginList.Plugins[0].ShortName).To(Equal("fake"))
})
It("response with 500", func() {
request, _ := http.NewRequest("GET", api, nil)
response := &http.Response{
StatusCode: 500,
Proto: "HTTP/1.1",
Request: request,
Body: ioutil.NopCloser(bytes.NewBufferString("")),
}
roundTripper.EXPECT().
RoundTrip(request).Return(response, nil)
_, err := pluginMgr.GetPlugins()
Expect(err).To(HaveOccurred())
})
})
Context("UninstallPlugin", func() {
var (
api string
pluginName string
)
BeforeEach(func() {
pluginName = "fake"
api = fmt.Sprintf("%s/pluginManager/plugin/%s/uninstall", pluginMgr.URL, pluginName)
})
It("normal case, should success", func() {
request, _ := http.NewRequest("POST", api, nil)
request.Header.Add("CrumbRequestField", "Crumb")
response := &http.Response{
StatusCode: 200,
Proto: "HTTP/1.1",
Request: request,
Body: ioutil.NopCloser(bytes.NewBufferString("")),
}
roundTripper.EXPECT().
RoundTrip(request).Return(response, nil)
// common crumb request
RequestCrumb(roundTripper, pluginMgr.URL)
err := pluginMgr.UninstallPlugin(pluginName)
Expect(err).To(BeNil())
})
It("response with 500", func() {
request, _ := http.NewRequest("POST", api, nil)
request.Header.Add("CrumbRequestField", "Crumb")
response := &http.Response{
StatusCode: 500,
Proto: "HTTP/1.1",
Request: request,
Body: ioutil.NopCloser(bytes.NewBufferString("")),
}
roundTripper.EXPECT().
RoundTrip(request).Return(response, nil)
// common crumb request
RequestCrumb(roundTripper, pluginMgr.URL)
err := pluginMgr.UninstallPlugin(pluginName)
Expect(err).To(HaveOccurred())
})
})
})
......@@ -87,68 +87,44 @@ func (p *PluginManager) CheckUpdate(handle func(*http.Response)) {
}
}
// GetAvailablePlugins get the aviable plugins from Jenkins
func (p *PluginManager) GetAvailablePlugins() (pluginList *AvailablePluginList, err error) {
api := fmt.Sprintf("%s/pluginManager/plugins", p.URL)
var (
req *http.Request
response *http.Response
statusCode int
data []byte
)
req, err = http.NewRequest("GET", api, nil)
if err == nil {
p.AuthHandle(req)
} else {
return
}
client := p.GetClient()
if response, err = client.Do(req); err == nil {
code := response.StatusCode
var data []byte
data, err = ioutil.ReadAll(response.Body)
if code == 200 {
if err == nil {
pluginList = &AvailablePluginList{}
err = json.Unmarshal(data, pluginList)
}
if statusCode, data, err = p.Request("GET", "/pluginManager/plugins", nil, nil); err == nil {
if statusCode == 200 {
pluginList = &AvailablePluginList{}
err = json.Unmarshal(data, pluginList)
} else {
log.Fatal(string(data))
err = fmt.Errorf("unexpected status code: %d", statusCode)
if p.Debug {
ioutil.WriteFile("debug.html", data, 0664)
}
}
} else {
log.Fatal(err)
}
return
}
// GetPlugins get installed plugins
func (p *PluginManager) GetPlugins() (pluginList *InstalledPluginList, err error) {
api := fmt.Sprintf("%s/pluginManager/api/json?pretty=true&depth=1", p.URL)
var (
req *http.Request
response *http.Response
statusCode int
data []byte
)
req, err = http.NewRequest("GET", api, nil)
if err == nil {
p.AuthHandle(req)
} else {
return
}
client := p.GetClient()
if response, err = client.Do(req); err == nil {
code := response.StatusCode
var data []byte
data, err = ioutil.ReadAll(response.Body)
if code == 200 {
if err == nil {
pluginList = &InstalledPluginList{}
err = json.Unmarshal(data, pluginList)
}
if statusCode, data, err = p.Request("GET", "/pluginManager/api/json?depth=1", nil, nil); err == nil {
if statusCode == 200 {
pluginList = &InstalledPluginList{}
err = json.Unmarshal(data, pluginList)
} else {
log.Fatal(string(data))
err = fmt.Errorf("unexpected status code: %d", statusCode)
if p.Debug {
ioutil.WriteFile("debug.html", data, 0664)
}
}
} else {
log.Fatal(err)
}
return
}
......@@ -213,31 +189,21 @@ func (p *PluginManager) InstallPlugin(names []string) (err error) {
// UninstallPlugin uninstall a plugin by name
func (p *PluginManager) UninstallPlugin(name string) (err error) {
api := fmt.Sprintf("%s/pluginManager/plugin/%s/uninstall", p.URL, name)
api := fmt.Sprintf("/pluginManager/plugin/%s/uninstall", name)
var (
req *http.Request
response *http.Response
statusCode int
data []byte
)
req, err = http.NewRequest("POST", api, nil)
if err == nil {
p.AuthHandle(req)
} else {
return
}
client := p.GetClient()
if response, err = client.Do(req); err == nil {
code := response.StatusCode
var data []byte
data, err = ioutil.ReadAll(response.Body)
if code == 200 {
if statusCode, data, err = p.Request("POST", api, nil, nil); err == nil {
if statusCode == 200 {
fmt.Println("uninstall succeed.")
} else {
log.Fatal(string(data))
err = fmt.Errorf("unexpected status code: %d", statusCode)
if p.Debug {
ioutil.WriteFile("debug.html", data, 0664)
}
}
} else {
log.Fatal(err)
}
return
}
......
package client
import (
"bytes"
"fmt"
"io/ioutil"
"net/http"
"github.com/jenkins-zh/jenkins-cli/mock/mhttp"
)
// PrepareForEmptyAvaiablePluginList only for test
func PrepareForEmptyAvaiablePluginList(roundTripper *mhttp.MockRoundTripper, rootURL string) (
request *http.Request, response *http.Response) {
request, _ = http.NewRequest("GET", fmt.Sprintf("%s/pluginManager/plugins", rootURL), nil)
response = &http.Response{
StatusCode: 200,
Proto: "HTTP/1.1",
Request: request,
Body: ioutil.NopCloser(bytes.NewBufferString(`{
"status": "ok",
"data": []
}`)),
}
roundTripper.EXPECT().
RoundTrip(request).Return(response, nil)
return
}
// PrepareForOneAvaiablePlugin only for test
func PrepareForOneAvaiablePlugin(roundTripper *mhttp.MockRoundTripper, rootURL string) (
request *http.Request, response *http.Response) {
request, _ = http.NewRequest("GET", fmt.Sprintf("%s/pluginManager/plugins", rootURL), nil)
response = &http.Response{
StatusCode: 200,
Proto: "HTTP/1.1",
Request: request,
Body: ioutil.NopCloser(bytes.NewBufferString(`{
"status": "ok",
"data": [{
"name": "fake",
"title": "fake"
}]
}`)),
}
roundTripper.EXPECT().
RoundTrip(request).Return(response, nil)
return
}
......@@ -88,6 +88,7 @@ golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a h1:aYOabOQFp6Vj6W1F80affTUvO
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262 h1:qsl9y/CJx34tuA7QCPNp86JNJe4spst6Ff8MjvPUdPg=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册