// Waits for the timestamp on the Jenkins job to change. Returns // and error if the timeout expires. func (jmon *JobMon) await(timeout time.Duration) error { err := wait.Poll(10*time.Second, timeout, func() (bool, error) { buildNumber, err := jmon.j.getJobBuildNumber(jmon.jobName, time.Minute) o.ExpectWithOffset(1, err).NotTo(o.HaveOccurred()) ginkgolog("Checking build number for job %q current[%v] vs last[%v]", jmon.jobName, buildNumber, jmon.lastBuildNumber) if buildNumber == jmon.lastBuildNumber { return false, nil } if jmon.buildNumber == "" { jmon.buildNumber = buildNumber } body, status, err := jmon.j.getResource("job/%s/%s/api/json?depth=1", jmon.jobName, jmon.buildNumber) o.ExpectWithOffset(1, err).NotTo(o.HaveOccurred()) o.ExpectWithOffset(1, status).To(o.Equal(200)) body = strings.ToLower(body) if strings.Contains(body, "\"building\":true") { ginkgolog("Jenkins job %q still building:\n%s\n\n", jmon.jobName, body) return false, nil } if strings.Contains(body, "\"result\":null") { ginkgolog("Jenkins job %q still building result:\n%s\n\n", jmon.jobName, body) return false, nil } ginkgolog("Jenkins job %q build complete:\n%s\n\n", jmon.jobName, body) return true, nil }) return err }
func doTest(bldPrefix, debugStr string, same bool, oc *exutil.CLI) { // corrupt the builder image exutil.CorruptImage(fullImageName, corruptor) if bldPrefix == buildPrefixFC || bldPrefix == buildPrefixTC { // grant access to the custom build strategy err := oc.AsAdmin().Run("adm").Args("policy", "add-cluster-role-to-user", "system:build-strategy-custom", oc.Username()).Execute() o.Expect(err).NotTo(o.HaveOccurred()) defer func() { err = oc.AsAdmin().Run("adm").Args("policy", "remove-cluster-role-from-user", "system:build-strategy-custom", oc.Username()).Execute() o.Expect(err).NotTo(o.HaveOccurred()) }() } // kick off the app/lang build and verify the builder image accordingly _, err := exutil.StartBuildAndWait(oc, bldPrefix) o.ExpectWithOffset(1, err).NotTo(o.HaveOccurred()) if same { exutil.VerifyImagesSame(fullImageName, corruptor, debugStr) } else { exutil.VerifyImagesDifferent(fullImageName, corruptor, debugStr) } // reset corrupted tagging for next test exutil.ResetImage(resetData) // dump tags/hexids for debug _, err = exutil.DumpAndReturnTagging(tags) o.ExpectWithOffset(1, err).NotTo(o.HaveOccurred()) }
// Returns the content of a Jenkins job XML file. Instances of the // string "PROJECT_NAME" are replaced with the specified namespace. func (j *JenkinsRef) readJenkinsJob(filename, namespace string) string { pre := exutil.FixturePath("testdata", "jenkins-plugin", filename) post := exutil.ArtifactPath(filename) err := exutil.VarSubOnFile(pre, post, "PROJECT_NAME", namespace) o.ExpectWithOffset(1, err).NotTo(o.HaveOccurred()) data, err := ioutil.ReadFile(post) o.ExpectWithOffset(1, err).NotTo(o.HaveOccurred()) return string(data) }
// Finds the pod running Jenkins func FindJenkinsPod(oc *exutil.CLI) *kapi.Pod { pods, err := exutil.GetDeploymentConfigPods(oc, "jenkins") o.ExpectWithOffset(1, err).NotTo(o.HaveOccurred()) if pods == nil || pods.Items == nil { g.Fail("No pods matching jenkins deploymentconfig in namespace " + oc.Namespace()) } o.ExpectWithOffset(1, len(pods.Items)).To(o.Equal(1)) return &pods.Items[0] }
// ReadJenkinsJobUsingVars returns the content of a Jenkins job XML file. Instances of the // string "PROJECT_NAME" are replaced with the specified namespace. // Variables named in the vars map will also be replaced with their // corresponding value. func (j *JenkinsRef) ReadJenkinsJobUsingVars(filename, namespace string, vars map[string]string) string { pre := exutil.FixturePath("testdata", "jenkins-plugin", filename) post := exutil.ArtifactPath(filename) if vars == nil { vars = map[string]string{} } vars["PROJECT_NAME"] = namespace err := exutil.VarSubOnFile(pre, post, vars) o.ExpectWithOffset(1, err).NotTo(o.HaveOccurred()) data, err := ioutil.ReadFile(post) o.ExpectWithOffset(1, err).NotTo(o.HaveOccurred()) return string(data) }
// Dumps logs and triggers a Ginkgo assertion if the build did NOT have an error (this will not assert on timeouts) func (t *BuildResult) AssertFailure() *BuildResult { if !t.BuildFailure { t.DumpLogs() } o.ExpectWithOffset(1, t.BuildFailure).To(o.BeTrue()) return t }
// Dumps logs and triggers a Ginkgo assertion if the build did NOT succeed. func (t *BuildResult) AssertSuccess() *BuildResult { if !t.BuildSuccess { t.DumpLogs() } o.ExpectWithOffset(1, t.BuildSuccess).To(o.BeTrue()) return t }
// Post sends a POST to the Jenkins server. Returns response body and status code or an error. func (j *JenkinsRef) Post(reqBody io.Reader, resourcePathFormat, contentType string, a ...interface{}) (string, int, error) { uri := j.BuildURI(resourcePathFormat, a...) req, err := http.NewRequest("POST", uri, reqBody) o.ExpectWithOffset(1, err).NotTo(o.HaveOccurred()) // http://stackoverflow.com/questions/17714494/golang-http-request-results-in-eof-errors-when-making-multiple-requests-successi req.Close = true if reqBody != nil { req.Header.Set("Content-Type", contentType) req.Header.Del("Expect") // jenkins will return 417 if we have an expect hdr } req.SetBasicAuth("admin", j.password) client := &http.Client{} ginkgolog("Posting to Jenkins resource: %q", uri) resp, err := client.Do(req) if err != nil { return "", 0, fmt.Errorf("Error posting request to %q: %v", uri, err) } defer resp.Body.Close() status := resp.StatusCode body, err := ioutil.ReadAll(resp.Body) if err != nil { return "", 0, fmt.Errorf("Error reading Post response body %q: %v", uri, err) } return string(body), status, nil }
func assertEnvVars(oc *exutil.CLI, buildPrefix string, varsToFind map[string]string) { buildList, err := oc.REST().Builds(oc.Namespace()).List(kapi.ListOptions{}) o.Expect(err).NotTo(o.HaveOccurred()) // Ensure that expected start-build environment variables were injected for _, build := range buildList.Items { ginkgolog("Found build: %q", build.GetName()) if strings.HasPrefix(build.GetName(), buildPrefix) { envs := []kapi.EnvVar{} if build.Spec.Strategy.DockerStrategy != nil && build.Spec.Strategy.DockerStrategy.Env != nil { envs = build.Spec.Strategy.DockerStrategy.Env } else if build.Spec.Strategy.SourceStrategy != nil && build.Spec.Strategy.SourceStrategy.Env != nil { envs = build.Spec.Strategy.SourceStrategy.Env } else { continue } for k, v := range varsToFind { found := false for _, env := range envs { ginkgolog("Found %s=%s in build %s", env.Name, env.Value, build.GetName()) if k == env.Name && v == env.Value { found = true break } } o.ExpectWithOffset(1, found).To(o.BeTrue()) } } } }
// StartJob triggers a named Jenkins job. The job can be monitored with the // returned object. func (j *JenkinsRef) StartJob(jobName string) *JobMon { lastBuildNumber, err := j.GetJobBuildNumber(jobName, time.Minute) o.ExpectWithOffset(1, err).NotTo(o.HaveOccurred()) jmon := &JobMon{ j: j, lastBuildNumber: lastBuildNumber, buildNumber: "", jobName: jobName, } ginkgolog("Current timestamp for [%s]: %q", jobName, jmon.lastBuildNumber) g.By(fmt.Sprintf("Starting jenkins job: %s", jobName)) _, status, err := j.PostXML(nil, "job/%s/build?delay=0sec", jobName) o.ExpectWithOffset(1, err).NotTo(o.HaveOccurred()) o.ExpectWithOffset(1, status).To(o.Equal(201)) return jmon }
func doTest(bldPrefix, debugStr string, same bool, oc *exutil.CLI) { // corrupt the builder image exutil.CorruptImage(fullImageName, corruptor) // kick off the app/lang build and verify the builder image accordingly _, err := exutil.StartBuildAndWait(oc, bldPrefix) o.ExpectWithOffset(1, err).NotTo(o.HaveOccurred()) if same { exutil.VerifyImagesSame(fullImageName, corruptor, debugStr) } else { exutil.VerifyImagesDifferent(fullImageName, corruptor, debugStr) } // reset corrupted tagging for next test exutil.ResetImage(resetData) // dump tags/hexids for debug _, err = exutil.DumpAndReturnTagging(tags) o.ExpectWithOffset(1, err).NotTo(o.HaveOccurred()) }
// Stands up a simple pod which can be used for exec commands func initExecPod(oc *exutil.CLI) *kapi.Pod { // Create a running pod in which we can execute our commands oc.Run("run").Args("centos", "--image", "centos:7", "--command", "--", "sleep", "1800").Execute() var targetPod *kapi.Pod err := wait.Poll(10*time.Second, 10*time.Minute, func() (bool, error) { pods, err := oc.KubeClient().Core().Pods(oc.Namespace()).List(kapi.ListOptions{}) o.ExpectWithOffset(1, err).NotTo(o.HaveOccurred()) for _, p := range pods.Items { if strings.HasPrefix(p.Name, "centos") && !strings.Contains(p.Name, "deploy") && p.Status.Phase == "Running" { targetPod = &p return true, nil } } return false, nil }) o.ExpectWithOffset(1, err).NotTo(o.HaveOccurred()) return targetPod }
// CreateItem submits XML to create a named item on the Jenkins server. func (j *JenkinsRef) CreateItem(name string, itemDefXML string) { g.By(fmt.Sprintf("Creating new jenkins item: %s", name)) _, status, err := j.PostXML(bytes.NewBufferString(itemDefXML), "createItem?name=%s", name) o.ExpectWithOffset(1, err).NotTo(o.HaveOccurred()) o.ExpectWithOffset(1, status).To(o.Equal(200)) }
// Loads a Jenkins related template using new-app. func loadFixture(oc *exutil.CLI, filename string) { resourcePath := exutil.FixturePath("testdata", "jenkins-plugin", filename) err := oc.Run("new-app").Args(resourcePath).Execute() o.ExpectWithOffset(1, err).NotTo(o.HaveOccurred()) }