|  | package goscaffold | 
|  |  | 
|  | import ( | 
|  | "bytes" | 
|  | "crypto/tls" | 
|  | "encoding/json" | 
|  | "errors" | 
|  | "fmt" | 
|  | "io/ioutil" | 
|  | "net" | 
|  | "net/http" | 
|  | "strings" | 
|  | "sync/atomic" | 
|  | "time" | 
|  |  | 
|  | "github.com/SermoDigital/jose/crypto" | 
|  | "github.com/SermoDigital/jose/jws" | 
|  | "github.com/julienschmidt/httprouter" | 
|  |  | 
|  | . "github.com/onsi/ginkgo" | 
|  | . "github.com/onsi/gomega" | 
|  | ) | 
|  |  | 
|  | const ( | 
|  | validJWTSigner   = "https://raw.githubusercontent.com/30x/goscaffold/master/testkeys/jwtcert.json" | 
|  | invalidJWTSigner = "https://raw.githubusercontent.com/30x/goscaffold/master/testkeys/notfound.json" | 
|  | ) | 
|  |  | 
|  | var ( | 
|  | dbURL string | 
|  | ) | 
|  |  | 
|  | var insecureClient = &http.Client{ | 
|  | Transport: &http.Transport{ | 
|  | TLSClientConfig: &tls.Config{ | 
|  | InsecureSkipVerify: true, | 
|  | }, | 
|  | }, | 
|  | } | 
|  |  | 
|  | var _ = Describe("Scaffold Tests", func() { | 
|  | It("Validate framework", func() { | 
|  | s := CreateHTTPScaffold() | 
|  | s.SetlocalBindIPAddressV4(GetLocalIP()) | 
|  | stopChan := make(chan error) | 
|  | err := s.Open() | 
|  | Expect(err).Should(Succeed()) | 
|  |  | 
|  | go func() { | 
|  | fmt.Fprintf(GinkgoWriter, "Gonna listen on %s\n", s.InsecureAddress()) | 
|  | stopErr := s.Listen(&testHandler{}) | 
|  | fmt.Fprintf(GinkgoWriter, "Done listening\n") | 
|  | stopChan <- stopErr | 
|  | }() | 
|  |  | 
|  | Eventually(func() bool { | 
|  | return testGet(s, "") | 
|  | }, 5*time.Second).Should(BeTrue()) | 
|  | resp, err := http.Get(fmt.Sprintf("http://%s", s.InsecureAddress())) | 
|  | Expect(err).Should(Succeed()) | 
|  | resp.Body.Close() | 
|  | Expect(resp.StatusCode).Should(Equal(200)) | 
|  | validatePprof(s.InsecureAddress()) | 
|  | shutdownErr := errors.New("Validate") | 
|  | s.Shutdown(shutdownErr) | 
|  | Eventually(stopChan).Should(Receive(Equal(shutdownErr))) | 
|  | }) | 
|  |  | 
|  | It("Separate management port", func() { | 
|  | s := CreateHTTPScaffold() | 
|  | s.SetlocalBindIPAddressV4(GetLocalIP()) | 
|  | s.SetManagementPort(0) | 
|  | stopChan := make(chan error) | 
|  | err := s.Open() | 
|  | Expect(err).Should(Succeed()) | 
|  |  | 
|  | go func() { | 
|  | fmt.Fprintf(GinkgoWriter, "Gonna listen on %s and %s\n", | 
|  | s.InsecureAddress(), s.ManagementAddress()) | 
|  | stopErr := s.Listen(&testHandler{}) | 
|  | fmt.Fprintf(GinkgoWriter, "Done listening\n") | 
|  | stopChan <- stopErr | 
|  | }() | 
|  |  | 
|  | // Just make sure that it's up | 
|  | Eventually(func() bool { | 
|  | return testGet(s, "") | 
|  | }, 5*time.Second).Should(BeTrue()) | 
|  | resp, err := http.Get(fmt.Sprintf("http://%s", s.InsecureAddress())) | 
|  | Expect(err).Should(Succeed()) | 
|  | resp.Body.Close() | 
|  | Expect(resp.StatusCode).Should(Equal(200)) | 
|  | resp, err = http.Get(fmt.Sprintf("http://%s", s.ManagementAddress())) | 
|  | Expect(err).Should(Succeed()) | 
|  | resp.Body.Close() | 
|  | Expect(resp.StatusCode).Should(Equal(404)) | 
|  | validatePprof(s.ManagementAddress()) | 
|  | shutdownErr := errors.New("Validate") | 
|  | s.Shutdown(shutdownErr) | 
|  | Eventually(stopChan).Should(Receive(Equal(shutdownErr))) | 
|  | }) | 
|  |  | 
|  | It("Shutdown", func() { | 
|  | s := CreateHTTPScaffold() | 
|  | s.SetHealthPath("/health") | 
|  | s.SetReadyPath("/ready") | 
|  | stopChan := make(chan error) | 
|  | err := s.Open() | 
|  | Expect(err).Should(Succeed()) | 
|  |  | 
|  | go func() { | 
|  | stopErr := s.Listen(&testHandler{}) | 
|  | stopChan <- stopErr | 
|  | }() | 
|  |  | 
|  | go func() { | 
|  | code, _ := getText(fmt.Sprintf("http://%s?delay=1s", s.InsecureAddress())) | 
|  | Expect(code).Should(Equal(200)) | 
|  | }() | 
|  |  | 
|  | // Just make sure server is listening | 
|  | Eventually(func() bool { | 
|  | return testGet(s, "") | 
|  | }, 5*time.Second).Should(BeTrue()) | 
|  |  | 
|  | // Ensure that we are healthy and ready | 
|  | code, _ := getText(fmt.Sprintf("http://%s/health", s.InsecureAddress())) | 
|  | Expect(code).Should(Equal(200)) | 
|  | code, _ = getText(fmt.Sprintf("http://%s/ready", s.InsecureAddress())) | 
|  | Expect(code).Should(Equal(200)) | 
|  |  | 
|  | // Previous call prevents server from exiting | 
|  | Consistently(stopChan, 250*time.Millisecond).ShouldNot(Receive()) | 
|  |  | 
|  | // Tell the server to try and exit | 
|  | stopErr := errors.New("Stop") | 
|  | s.Shutdown(stopErr) | 
|  |  | 
|  | // Should take one second -- in the meantime, calls should fail with 503, | 
|  | // health should be good, but ready should be bad | 
|  | code, _ = getText(fmt.Sprintf("http://%s", s.InsecureAddress())) | 
|  | Expect(code).Should(Equal(503)) | 
|  | code, _ = getText(fmt.Sprintf("http://%s/ready", s.InsecureAddress())) | 
|  | Expect(code).Should(Equal(503)) | 
|  | code, _ = getText(fmt.Sprintf("http://%s/health", s.InsecureAddress())) | 
|  | Expect(code).Should(Equal(200)) | 
|  |  | 
|  | // Do a bunch more stops because we are funny that way. | 
|  | // We just want to make sure that we don't hang if we stop a FEW times. | 
|  | for i := 0; i < 25; i++ { | 
|  | s.Shutdown(stopErr) | 
|  | } | 
|  |  | 
|  | // But in less than two seconds, server should be down | 
|  | Eventually(stopChan, 2*time.Second).Should(Receive(Equal(stopErr))) | 
|  | // Calls should now fail | 
|  | Eventually(func() bool { | 
|  | return testGet(s, "") | 
|  | }, time.Second).Should(BeFalse()) | 
|  | }) | 
|  |  | 
|  | It("Markdown", func() { | 
|  | var markedDown int32 | 
|  |  | 
|  | s := CreateHTTPScaffold() | 
|  | s.SetHealthPath("/health") | 
|  | s.SetReadyPath("/ready") | 
|  | s.SetMarkdown("POST", "/markdown", func() { | 
|  | atomic.StoreInt32(&markedDown, 1) | 
|  | }) | 
|  |  | 
|  | stopChan := make(chan error) | 
|  | err := s.Open() | 
|  | Expect(err).Should(Succeed()) | 
|  |  | 
|  | go func() { | 
|  | listenErr := s.Listen(&testHandler{}) | 
|  | stopChan <- listenErr | 
|  | }() | 
|  |  | 
|  | // Just make sure server is listening | 
|  | Eventually(func() bool { | 
|  | return testGet(s, "") | 
|  | }, 5*time.Second).Should(BeTrue()) | 
|  |  | 
|  | // Ensure that we are healthy and ready | 
|  | code, _ := getText(fmt.Sprintf("http://%s/health", s.InsecureAddress())) | 
|  | Expect(code).Should(Equal(200)) | 
|  | code, _ = getText(fmt.Sprintf("http://%s/ready", s.InsecureAddress())) | 
|  | Expect(code).Should(Equal(200)) | 
|  |  | 
|  | // Mark the server down, but don't stop it | 
|  | resp, err := http.Post(fmt.Sprintf("http://%s/markdown", s.InsecureAddress()), | 
|  | "text/plain", strings.NewReader("Goodbye!")) | 
|  | Expect(err).Should(Succeed()) | 
|  | resp.Body.Close() | 
|  | Expect(resp.StatusCode).Should(Equal(200)) | 
|  |  | 
|  | // Server should immediately be marked down, not ready, but healthy | 
|  | Expect(atomic.LoadInt32(&markedDown)).Should(BeEquivalentTo(1)) | 
|  | code, _ = getText(fmt.Sprintf("http://%s", s.InsecureAddress())) | 
|  | Expect(code).Should(Equal(503)) | 
|  | code, _ = getText(fmt.Sprintf("http://%s/ready", s.InsecureAddress())) | 
|  | Expect(code).Should(Equal(503)) | 
|  | code, _ = getText(fmt.Sprintf("http://%s/health", s.InsecureAddress())) | 
|  | Expect(code).Should(Equal(200)) | 
|  |  | 
|  | // Server should not have stopped yet | 
|  | Consistently(stopChan).ShouldNot(Receive()) | 
|  |  | 
|  | stopErr := errors.New("Test stop") | 
|  | s.Shutdown(stopErr) | 
|  | Eventually(stopChan).Should(Receive(Equal(stopErr))) | 
|  | }) | 
|  |  | 
|  | It("Health Check Functions", func() { | 
|  | status := int32(OK) | 
|  | var healthErr = &atomic.Value{} | 
|  |  | 
|  | statusFunc := func() (HealthStatus, error) { | 
|  | stat := HealthStatus(atomic.LoadInt32(&status)) | 
|  | av := healthErr.Load() | 
|  | if av != nil { | 
|  | errPtr := av.(*error) | 
|  | return stat, *errPtr | 
|  | } | 
|  | return stat, nil | 
|  | } | 
|  |  | 
|  | s := CreateHTTPScaffold() | 
|  | s.SetlocalBindIPAddressV4(GetLocalIP()) | 
|  | s.SetManagementPort(0) | 
|  | s.SetHealthPath("/health") | 
|  | s.SetReadyPath("/ready") | 
|  | s.SetHealthChecker(statusFunc) | 
|  | stopChan := make(chan error) | 
|  | err := s.Open() | 
|  | Expect(err).Should(Succeed()) | 
|  |  | 
|  | go func() { | 
|  | fmt.Fprintf(GinkgoWriter, "Gonna listen on %s and %s\n", | 
|  | s.InsecureAddress(), s.ManagementAddress()) | 
|  | stopErr := s.Listen(&testHandler{}) | 
|  | fmt.Fprintf(GinkgoWriter, "Done listening\n") | 
|  | stopChan <- stopErr | 
|  | }() | 
|  |  | 
|  | // Just make sure that it's up | 
|  | Eventually(func() bool { | 
|  | return testGet(s, "") | 
|  | }, 5*time.Second).Should(BeTrue()) | 
|  |  | 
|  | // Health should be good | 
|  | code, _ := getText(fmt.Sprintf("http://%s/health", s.ManagementAddress())) | 
|  | Expect(code).Should(Equal(200)) | 
|  | code, _ = getText(fmt.Sprintf("http://%s/ready", s.ManagementAddress())) | 
|  | Expect(code).Should(Equal(200)) | 
|  |  | 
|  | // Mark down to "unhealthy" state. Should be bad. | 
|  | atomic.StoreInt32(&status, int32(Failed)) | 
|  | code, bod := getText(fmt.Sprintf("http://%s/health", s.ManagementAddress())) | 
|  | Expect(code).Should(Equal(503)) | 
|  | Expect(bod).Should(Equal("Failed")) | 
|  | code, _ = getText(fmt.Sprintf("http://%s/ready", s.ManagementAddress())) | 
|  | Expect(code).Should(Equal(503)) | 
|  |  | 
|  | // Change to merely "not ready" state. Should be healthy but not ready. | 
|  | atomic.StoreInt32(&status, int32(NotReady)) | 
|  | code, _ = getText(fmt.Sprintf("http://%s/health", s.ManagementAddress())) | 
|  | Expect(code).Should(Equal(200)) | 
|  | code, bod = getText(fmt.Sprintf("http://%s/ready", s.ManagementAddress())) | 
|  | Expect(code).Should(Equal(503)) | 
|  | Expect(bod).Should(Equal("NotReady")) | 
|  |  | 
|  | // Customize the error message. | 
|  | customErr := errors.New("Custom") | 
|  | healthErr.Store(&customErr) | 
|  | code, bod = getText(fmt.Sprintf("http://%s/ready", s.ManagementAddress())) | 
|  | Expect(code).Should(Equal(503)) | 
|  | Expect(bod).Should(Equal("Custom")) | 
|  |  | 
|  | // Check it in JSON | 
|  | code, js := getJSON(fmt.Sprintf("http://%s/ready", s.ManagementAddress())) | 
|  | Expect(code).Should(Equal(503)) | 
|  | Expect(js["status"]).Should(Equal("NotReady")) | 
|  | Expect(js["reason"]).Should(Equal("Custom")) | 
|  |  | 
|  | // Mark back up. Should be all good | 
|  | atomic.StoreInt32(&status, int32(OK)) | 
|  | code, _ = getText(fmt.Sprintf("http://%s/health", s.ManagementAddress())) | 
|  | Expect(code).Should(Equal(200)) | 
|  | code, _ = getText(fmt.Sprintf("http://%s/ready", s.ManagementAddress())) | 
|  | Expect(code).Should(Equal(200)) | 
|  |  | 
|  | s.Shutdown(nil) | 
|  | Eventually(stopChan).Should(Receive(Equal(ErrManualStop))) | 
|  | }) | 
|  |  | 
|  | It("Secure And Insecure Ports", func() { | 
|  | s := CreateHTTPScaffold() | 
|  | s.SetSecurePort(0) | 
|  | s.SetKeyFile("./testkeys/clearkey.pem") | 
|  | s.SetCertFile("./testkeys/clearcert.pem") | 
|  | stopChan := make(chan error) | 
|  | err := s.Open() | 
|  | Expect(err).Should(Succeed()) | 
|  |  | 
|  | go func() { | 
|  | fmt.Fprintf(GinkgoWriter, "Gonna listen on %s and %s\n", | 
|  | s.InsecureAddress(), s.SecureAddress()) | 
|  | stopErr := s.Listen(&testHandler{}) | 
|  | fmt.Fprintf(GinkgoWriter, "Done listening\n") | 
|  | stopChan <- stopErr | 
|  | }() | 
|  |  | 
|  | Eventually(func() bool { | 
|  | return testGet(s, "") | 
|  | }, 5*time.Second).Should(BeTrue()) | 
|  | Eventually(func() bool { | 
|  | return testGetSecure(s, "") | 
|  | }, time.Second).Should(BeTrue()) | 
|  |  | 
|  | shutdownErr := errors.New("Validate") | 
|  | s.Shutdown(shutdownErr) | 
|  | Eventually(stopChan).Should(Receive(Equal(shutdownErr))) | 
|  | }) | 
|  |  | 
|  | It("Secure Port Only", func() { | 
|  | s := CreateHTTPScaffold() | 
|  | s.SetSecurePort(0) | 
|  | s.SetInsecurePort(-1) | 
|  | s.SetKeyFile("./testkeys/clearkey.pem") | 
|  | s.SetCertFile("./testkeys/clearcert.pem") | 
|  | stopChan := make(chan error) | 
|  | err := s.Open() | 
|  | Expect(err).Should(Succeed()) | 
|  | Expect(s.InsecureAddress()).Should(BeEmpty()) | 
|  |  | 
|  | go func() { | 
|  | fmt.Fprintf(GinkgoWriter, "Gonna listen on %s\n", | 
|  | s.SecureAddress()) | 
|  | stopErr := s.Listen(&testHandler{}) | 
|  | fmt.Fprintf(GinkgoWriter, "Done listening\n") | 
|  | stopChan <- stopErr | 
|  | }() | 
|  |  | 
|  | Eventually(func() bool { | 
|  | return testGetSecure(s, "") | 
|  | }, 5*time.Second).Should(BeTrue()) | 
|  |  | 
|  | shutdownErr := errors.New("Validate") | 
|  | s.Shutdown(shutdownErr) | 
|  | Eventually(stopChan).Should(Receive(Equal(shutdownErr))) | 
|  | }) | 
|  |  | 
|  | It("DisAllow non-localhost", func() { | 
|  | s := CreateHTTPScaffold() | 
|  | s.SetInsecurePort(8181) | 
|  | s.SetlocalBindIPAddressV4([]byte{127, 0, 0, 1}) | 
|  | stopChan := make(chan error) | 
|  | err := s.Open() | 
|  | Expect(err).Should(Succeed()) | 
|  |  | 
|  | go func() { | 
|  | fmt.Fprintf(GinkgoWriter, "Gonna listen on %s\n", s.InsecureAddress()) | 
|  | stopErr := s.Listen(&testHandler{}) | 
|  | fmt.Fprintf(GinkgoWriter, "Done listening\n") | 
|  | stopChan <- stopErr | 
|  | }() | 
|  |  | 
|  | Eventually(func() bool { | 
|  | return testGet(s, "") | 
|  | }, 5*time.Second).Should(BeTrue()) | 
|  | _, err = http.Get(fmt.Sprintf("http://%s:%s", GetLocalIPStr(), "8181")) | 
|  | Expect(err).ShouldNot(Succeed()) | 
|  | shutdownErr := errors.New("Validate") | 
|  | s.Shutdown(shutdownErr) | 
|  | Eventually(stopChan).Should(Receive(Equal(shutdownErr))) | 
|  |  | 
|  | }) | 
|  |  | 
|  | It("SSO handler validation", func() { | 
|  |  | 
|  | var vals ErrorResponse | 
|  |  | 
|  | router := httprouter.New() | 
|  | Expect(router).ShouldNot(BeNil()) | 
|  | scaf := CreateHTTPScaffold() | 
|  | Expect(scaf).ShouldNot(BeNil()) | 
|  | err := scaf.Open() | 
|  | Expect(err).Should(Succeed()) | 
|  | oauth := scaf.CreateOAuth(validJWTSigner) | 
|  | Expect(oauth).ShouldNot(BeNil()) | 
|  | go func() { | 
|  | fmt.Fprintf(GinkgoWriter, "Gonna listen on %s\n", scaf.InsecureAddress()) | 
|  | router.GET(oauth.SSOHandler("/foobar/:param1/:param2", buslogicHandler)) | 
|  | scaf.Listen(router) | 
|  | }() | 
|  |  | 
|  | Eventually(func() int { | 
|  | req, reqerr := http.NewRequest("GET", | 
|  | "http://"+scaf.InsecureAddress()+"/foobar/xyz/123", nil) | 
|  | Expect(reqerr).Should(Succeed()) | 
|  | req.Header.Set("Authorization", "Bearer "+string(createJWT())) | 
|  | client := &http.Client{} | 
|  | resp, reqerr := client.Do(req) | 
|  | Expect(reqerr).Should(Succeed()) | 
|  | defer resp.Body.Close() | 
|  | return resp.StatusCode | 
|  | }, 2*time.Second).Should(Equal(200)) | 
|  |  | 
|  | req, err := http.NewRequest("GET", | 
|  | "http://"+scaf.InsecureAddress()+"/foobar/xyz/123", nil) | 
|  | Expect(err).Should(Succeed()) | 
|  | req.Header.Set("Authorization", "Bearer DEADBEEF") | 
|  | client := &http.Client{} | 
|  | resp, err := client.Do(req) | 
|  | Expect(err).Should(Succeed()) | 
|  | defer resp.Body.Close() | 
|  | Expect(resp.StatusCode).Should(Equal(400)) | 
|  | body, err := ioutil.ReadAll(resp.Body) | 
|  | Expect(err).Should(Succeed()) | 
|  | err = json.Unmarshal(body, &vals) | 
|  | Expect(err).Should(Succeed()) | 
|  | Expect(vals.Status).Should(Equal("Bad Request")) | 
|  | Expect(vals.Message).Should(Equal("not a compact JWS")) | 
|  | }) | 
|  |  | 
|  | It("SSO handler validation bad public key", func() { | 
|  |  | 
|  | var vals ErrorResponse | 
|  |  | 
|  | router := httprouter.New() | 
|  | Expect(router).ShouldNot(BeNil()) | 
|  | scaf := CreateHTTPScaffold() | 
|  | Expect(scaf).ShouldNot(BeNil()) | 
|  | err := scaf.Open() | 
|  | Expect(err).Should(Succeed()) | 
|  | oauth := scaf.CreateOAuth(invalidJWTSigner) | 
|  | Expect(oauth).ShouldNot(BeNil()) | 
|  | go func() { | 
|  | fmt.Fprintf(GinkgoWriter, "Gonna listen on %s\n", scaf.InsecureAddress()) | 
|  | router.GET(oauth.SSOHandler("/foobar/:param1/:param2", buslogicHandler)) | 
|  | scaf.Listen(router) | 
|  | }() | 
|  |  | 
|  | req, err := http.NewRequest("GET", | 
|  | "http://"+scaf.InsecureAddress()+"/foobar/xyz/123", nil) | 
|  | Expect(err).Should(Succeed()) | 
|  | req.Header.Set("Authorization", "Bearer "+string(createJWT())) | 
|  | client := &http.Client{} | 
|  | resp, err := client.Do(req) | 
|  | Expect(err).Should(Succeed()) | 
|  | defer resp.Body.Close() | 
|  | Expect(resp.StatusCode).Should(Equal(400)) | 
|  | body, err := ioutil.ReadAll(resp.Body) | 
|  | Expect(err).Should(Succeed()) | 
|  | err = json.Unmarshal(body, &vals) | 
|  | Expect(err).Should(Succeed()) | 
|  | Expect(vals.Status).Should(Equal("Bad Request")) | 
|  | Expect(vals.Message).Should(Equal("Public key not configured. Validation failed.")) | 
|  | }) | 
|  |  | 
|  | It("Get stack trace", func() { | 
|  | b := &bytes.Buffer{} | 
|  | dumpStack(b) | 
|  | Expect(b.Len()).ShouldNot(BeZero()) | 
|  | }) | 
|  |  | 
|  | It("Verify JWT creation", func() { | 
|  | // Ensure that our logic in this test for creating a JWT really works | 
|  | jwt := createJWT() | 
|  | fmt.Fprintf(GinkgoWriter, "JWT: %s\n", string(jwt)) | 
|  |  | 
|  | certBytes, err := ioutil.ReadFile("./testkeys/jwtcert.pem") | 
|  | Expect(err).Should(Succeed()) | 
|  | cert, err := crypto.ParseRSAPublicKeyFromPEM(certBytes) | 
|  | Expect(err).Should(Succeed()) | 
|  |  | 
|  | parsedJwt, err := jws.ParseJWT(jwt) | 
|  | Expect(err).Should(Succeed()) | 
|  |  | 
|  | err = parsedJwt.Validate(cert, crypto.SigningMethodRS256) | 
|  | Expect(err).Should(Succeed()) | 
|  | }) | 
|  | }) | 
|  |  | 
|  | func buslogicHandler(w http.ResponseWriter, r *http.Request) { | 
|  | p := FetchParams(r) | 
|  | cid := p.ByName("param1") | 
|  | Expect(cid).To(Equal("xyz")) | 
|  | cid = p.ByName("param2") | 
|  | Expect(cid).To(Equal("123")) | 
|  | } | 
|  |  | 
|  | func getText(url string) (int, string) { | 
|  | req, err := http.NewRequest("GET", url, nil) | 
|  | Expect(err).Should(Succeed()) | 
|  | req.Header.Set("Accept", "text/plain") | 
|  | resp, err := http.DefaultClient.Do(req) | 
|  | Expect(err).Should(Succeed()) | 
|  | defer resp.Body.Close() | 
|  | bod, err := ioutil.ReadAll(resp.Body) | 
|  | Expect(err).Should(Succeed()) | 
|  | return resp.StatusCode, string(bod) | 
|  | } | 
|  |  | 
|  | func getJSON(url string) (int, map[string]string) { | 
|  | req, err := http.NewRequest("GET", url, nil) | 
|  | Expect(err).Should(Succeed()) | 
|  | req.Header.Set("Accept", "application/json") | 
|  | resp, err := http.DefaultClient.Do(req) | 
|  | Expect(err).Should(Succeed()) | 
|  | defer resp.Body.Close() | 
|  | bod, err := ioutil.ReadAll(resp.Body) | 
|  | Expect(err).Should(Succeed()) | 
|  | var vals map[string]string | 
|  | err = json.Unmarshal(bod, &vals) | 
|  | Expect(err).Should(Succeed()) | 
|  | return resp.StatusCode, vals | 
|  | } | 
|  |  | 
|  | func validatePprof(addr string) { | 
|  | code, _ := getText(fmt.Sprintf("http://%s/debug/pprof/", addr)) | 
|  | Expect(code).Should(Equal(200)) | 
|  | code, cmdline := getText(fmt.Sprintf("http://%s/debug/pprof/cmdline", addr)) | 
|  | Expect(code).Should(Equal(200)) | 
|  | Expect(cmdline).ShouldNot(BeEmpty()) | 
|  | } | 
|  |  | 
|  | func testGet(s *HTTPScaffold, path string) bool { | 
|  | resp, err := http.Get(fmt.Sprintf("http://%s", s.InsecureAddress())) | 
|  | if err != nil { | 
|  | fmt.Fprintf(GinkgoWriter, "Get %s = %s\n", path, err) | 
|  | return false | 
|  | } | 
|  | resp.Body.Close() | 
|  | if resp.StatusCode != 200 { | 
|  | fmt.Fprintf(GinkgoWriter, "Get %s = %d\n", path, resp.StatusCode) | 
|  | return false | 
|  | } | 
|  | return true | 
|  | } | 
|  |  | 
|  | func testGetSecure(s *HTTPScaffold, path string) bool { | 
|  | resp, err := insecureClient.Get(fmt.Sprintf("https://%s", s.SecureAddress())) | 
|  | if err != nil { | 
|  | fmt.Fprintf(GinkgoWriter, "Get %s = %s\n", path, err) | 
|  | return false | 
|  | } | 
|  | resp.Body.Close() | 
|  | if resp.StatusCode != 200 { | 
|  | fmt.Fprintf(GinkgoWriter, "Get %s = %d\n", path, resp.StatusCode) | 
|  | return false | 
|  | } | 
|  | return true | 
|  | } | 
|  |  | 
|  | type testHandler struct { | 
|  | } | 
|  |  | 
|  | func (h *testHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) { | 
|  | var err error | 
|  | var delayTime time.Duration | 
|  |  | 
|  | delayStr := req.URL.Query().Get("delay") | 
|  | if delayStr != "" { | 
|  | delayTime, err = time.ParseDuration(delayStr) | 
|  | if err != nil { | 
|  | resp.WriteHeader(http.StatusBadRequest) | 
|  | return | 
|  | } | 
|  | } | 
|  |  | 
|  | if delayTime > 0 { | 
|  | time.Sleep(delayTime) | 
|  | } | 
|  | } | 
|  |  | 
|  | func GetLocalIP() []byte { | 
|  | addrs, err := net.InterfaceAddrs() | 
|  | if err != nil { | 
|  | return nil | 
|  | } | 
|  | for _, address := range addrs { | 
|  | if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() { | 
|  | if ipnet.IP.To4() != nil { | 
|  | return ipnet.IP | 
|  | } | 
|  | } | 
|  | } | 
|  | return nil | 
|  | } | 
|  |  | 
|  | func GetLocalIPStr() string { | 
|  | addrs, err := net.InterfaceAddrs() | 
|  | if err != nil { | 
|  | return "" | 
|  | } | 
|  | for _, address := range addrs { | 
|  | if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() { | 
|  | if ipnet.IP.To4() != nil { | 
|  | return ipnet.IP.String() | 
|  | } | 
|  | } | 
|  | } | 
|  | return "" | 
|  | } | 
|  |  | 
|  | func createJWT() []byte { | 
|  | keyBytes, err := ioutil.ReadFile("./testkeys/jwtkey.pem") | 
|  | Expect(err).Should(Succeed()) | 
|  | pk, err := crypto.ParseRSAPrivateKeyFromPEM(keyBytes) | 
|  | Expect(err).Should(Succeed()) | 
|  |  | 
|  | claims := jws.Claims{} | 
|  | now := time.Now() | 
|  | claims.SetAudience("http://github.com/30x/goscaffold") | 
|  | claims.SetIssuer("http://github.com/30x/goscaffold") | 
|  | claims.SetSubject("http://github.com/30x/goscaffold") | 
|  | claims.SetIssuedAt(now) | 
|  | claims.SetNotBefore(now) | 
|  | claims.SetExpiration(now.Add(time.Hour)) | 
|  | jwt := jws.NewJWT(claims, crypto.SigningMethodRS256) | 
|  |  | 
|  | rawJwt, err := jwt.Serialize(pk) | 
|  | Expect(err).Should(Succeed()) | 
|  | return rawJwt | 
|  | } |