github.com/olli-ai/jx/v2@v2.0.400-0.20210921045218-14731b4dd448/pkg/cmd/controller/pipeline/pipelinerunner_controller_test.go (about) 1 // +build unit 2 3 package pipeline 4 5 import ( 6 "bytes" 7 "context" 8 "errors" 9 "fmt" 10 "io/ioutil" 11 "net" 12 "net/http" 13 "sync" 14 "testing" 15 "time" 16 17 v1 "github.com/jenkins-x/jx-api/pkg/apis/jenkins.io/v1" 18 "github.com/jenkins-x/jx-api/pkg/client/clientset/versioned/fake" 19 "github.com/jenkins-x/jx-logging/pkg/log" 20 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 21 "k8s.io/apimachinery/pkg/runtime" 22 23 . "github.com/onsi/ginkgo" 24 . "github.com/onsi/gomega" 25 ) 26 27 const ( 28 testRequestWithoutProwJobName = ` 29 { 30 "labels": { 31 "created-by-prow": "true" 32 }, 33 "prowJobSpec": { 34 "type": "pullrequest", 35 "agent": "tekton", 36 "cluster": "default", 37 "namespace": "jx", 38 "job": "serverless-jenkins", 39 "refs": { 40 "org": "jenkins-x-quickstarts", 41 "repo": "golang-http", 42 "repo_link": "https://github.com/jenkins-x-quickstarts/golang-http", 43 "base_ref": "master", 44 "base_sha": "3f00363d651280ab2a8ee67f395de1689156d762", 45 "pulls": [ 46 { 47 "number": 1, 48 "sha": "06b5fa6804aa0bd1f4f533010d1b335918a433e2" 49 } 50 ] 51 }, 52 "report": true, 53 "context": "serverless-jenkins", 54 "rerun_command": "/test this" 55 } 56 } 57 ` 58 testRequestMissingPullRefs = ` 59 { 60 "labels": { 61 "created-by-prow": "true", 62 "prowJobName": "cdf89f04-98ec-11e9-a846-4ad95a1bb3ab" 63 }, 64 "prowJobSpec": { 65 "type": "pullrequest", 66 "agent": "tekton", 67 "cluster": "default", 68 "namespace": "jx", 69 "job": "serverless-jenkins", 70 "report": true, 71 "context": "serverless-jenkins", 72 "rerun_command": "/test this" 73 } 74 } 75 ` 76 ) 77 78 func TestPipelineRunner(t *testing.T) { 79 RegisterFailHandler(Fail) 80 RunSpecs(t, "Pipeline Runner Test Suite") 81 } 82 83 var _ = Describe("Pipeline Runner", func() { 84 BeforeSuite(func() { 85 log.SetOutput(GinkgoWriter) 86 }) 87 88 Describe("when running", func() { 89 var ( 90 client *http.Client 91 host string 92 port int 93 err error 94 ctx context.Context 95 cancel context.CancelFunc 96 ) 97 98 BeforeEach(func() { 99 client = &http.Client{} 100 Expect(err).Should(BeNil()) 101 102 jxClient := fake.NewSimpleClientset() 103 Expect(err).Should(BeNil()) 104 105 host = "127.0.0.1" 106 port, _ = getFreePort() 107 controller := controller{ 108 path: "/", 109 bindAddress: host, 110 port: port, 111 useMetaPipeline: true, 112 jxClient: jxClient, 113 ns: "jx", 114 } 115 116 go func() { 117 var wg sync.WaitGroup 118 ctx, cancel = context.WithCancel(context.Background()) 119 controller.startWorkers(ctx, &wg, cancel) 120 wg.Wait() 121 }() 122 123 err := waitForOpenPort(host, port, time.Duration(5)*time.Second) 124 Expect(err).Should(BeNil()) 125 }) 126 127 AfterEach(func() { 128 cancel() 129 }) 130 131 It("GET requests return with HTTP 200 and request POST", func() { 132 resp, err := client.Get(fmt.Sprintf("http://localhost:%d/", port)) 133 Expect(err).Should(BeNil()) 134 Expect(resp.StatusCode).Should(Equal(200)) 135 136 defer func() { 137 err := resp.Body.Close() 138 Expect(err).Should(BeNil()) 139 }() 140 141 htmlData, err := ioutil.ReadAll(resp.Body) 142 Expect(string(htmlData)).Should(ContainSubstring("please POST JSON ")) 143 }) 144 145 It("/health returns HTTP 204", func() { 146 resp, err := client.Get(fmt.Sprintf("http://localhost:%d%s", port, healthPath)) 147 Expect(err).Should(BeNil()) 148 Expect(resp.StatusCode).Should(Equal(http.StatusNoContent)) 149 }) 150 151 It("/ready returns HTTP 204", func() { 152 resp, err := client.Get(fmt.Sprintf("http://localhost:%d%s", port, readyPath)) 153 Expect(err).Should(BeNil()) 154 Expect(resp.StatusCode).Should(Equal(http.StatusNoContent)) 155 }) 156 157 It("POST returns HTTP 400 for invalid JSON", func() { 158 var json = []byte("{\"foo\":\"bar\"}") 159 resp, err := client.Post(fmt.Sprintf("http://localhost:%d/", port), "application/json", bytes.NewBuffer(json)) 160 Expect(err).Should(BeNil()) 161 Expect(resp.StatusCode).Should(Equal(http.StatusBadRequest)) 162 163 defer func() { 164 err := resp.Body.Close() 165 Expect(err).Should(BeNil()) 166 }() 167 168 htmlData, err := ioutil.ReadAll(resp.Body) 169 Expect(string(htmlData)).Should(ContainSubstring("could not start pipeline")) 170 }) 171 172 It("POST returns HTTP 400 for missing pull refs", func() { 173 resp, err := client.Post(fmt.Sprintf("http://localhost:%d/", port), "application/json", bytes.NewBuffer([]byte(testRequestMissingPullRefs))) 174 Expect(err).Should(BeNil()) 175 Expect(resp.StatusCode).Should(Equal(http.StatusBadRequest)) 176 177 defer func() { 178 err := resp.Body.Close() 179 Expect(err).Should(BeNil()) 180 }() 181 182 htmlData, err := ioutil.ReadAll(resp.Body) 183 Expect(string(htmlData)).Should(ContainSubstring("no prowJobSpec.refs passed")) 184 }) 185 186 It("POST returns HTTP 400 for missing prow job name", func() { 187 resp, err := client.Post(fmt.Sprintf("http://localhost:%d/", port), "application/json", bytes.NewBuffer([]byte(testRequestWithoutProwJobName))) 188 Expect(err).Should(BeNil()) 189 Expect(resp.StatusCode).Should(Equal(http.StatusBadRequest)) 190 191 defer func() { 192 err := resp.Body.Close() 193 Expect(err).Should(BeNil()) 194 }() 195 196 htmlData, err := ioutil.ReadAll(resp.Body) 197 Expect(string(htmlData)).Should(ContainSubstring("unable to find prow job name in pipeline request")) 198 }) 199 }) 200 201 Describe("#getSourceURL", func() { 202 var ( 203 testController controller 204 expectedURL = "http://github.com/jenkins-x/jx.git" 205 ) 206 207 BeforeEach(func() { 208 var jxObjects []runtime.Object 209 210 sourceRepo := &v1.SourceRepository{ 211 ObjectMeta: metav1.ObjectMeta{ 212 Namespace: "jx", 213 Labels: map[string]string{"owner": "jenkins-x", "repository": "jx"}, 214 }, 215 216 Spec: v1.SourceRepositorySpec{ 217 Provider: "http://github.com", 218 }, 219 } 220 221 jxObjects = append(jxObjects, sourceRepo) 222 jxClient := fake.NewSimpleClientset(jxObjects...) 223 224 testController = controller{ 225 jxClient: jxClient, 226 ns: "jx", 227 } 228 229 }) 230 231 It("retrieves source URL from cluster", func() { 232 url := testController.getSourceURL("jenkins-x", "jx") 233 Expect(url).Should(Equal(expectedURL)) 234 }) 235 236 It("returns the empty string for an unknown repo", func() { 237 url := testController.getSourceURL("jenkins-x", "foo") 238 Expect(url).Should(BeEmpty()) 239 }) 240 }) 241 }) 242 243 // getFreePort asks the kernel for a free open port that is ready to use. 244 func getFreePort() (int, error) { 245 addr, err := net.ResolveTCPAddr("tcp", "127.0.0.1:0") 246 if err != nil { 247 return 0, err 248 } 249 250 l, err := net.ListenTCP("tcp", addr) 251 if err != nil { 252 return 0, err 253 } 254 defer func() { 255 _ = l.Close() 256 }() 257 return l.Addr().(*net.TCPAddr).Port, nil 258 } 259 260 func waitForOpenPort(host string, port int, timeOut time.Duration) error { 261 connectChannel := make(chan error, 1) 262 go func() { 263 for { 264 addr := fmt.Sprintf("%s:%d", host, port) 265 conn, err := net.Dial("tcp", addr) 266 if err != nil { 267 continue 268 } 269 270 err = conn.Close() 271 if err != nil { 272 connectChannel <- err 273 } 274 connectChannel <- nil 275 } 276 }() 277 278 select { 279 case err := <-connectChannel: 280 return err 281 case <-time.After(timeOut): 282 return errors.New("timout waiting for open port") 283 } 284 }