github.com/onsi/ginkgo@v1.16.6-0.20211118180735-4e1925ba4c95/internal/parallel_support/http_client.go (about) 1 package parallel_support 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "fmt" 7 "io" 8 "net/http" 9 "time" 10 11 "github.com/onsi/ginkgo/types" 12 ) 13 14 type httpClient struct { 15 serverHost string 16 } 17 18 func newHttpClient(serverHost string) *httpClient { 19 return &httpClient{ 20 serverHost: serverHost, 21 } 22 } 23 24 func (client *httpClient) Connect() bool { 25 resp, err := http.Get(client.serverHost + "/up") 26 if err != nil { 27 return false 28 } 29 resp.Body.Close() 30 return resp.StatusCode == http.StatusOK 31 } 32 33 func (client *httpClient) Close() error { 34 return nil 35 } 36 37 func (client *httpClient) post(path string, data interface{}) error { 38 var body io.Reader 39 if data != nil { 40 encoded, err := json.Marshal(data) 41 if err != nil { 42 return err 43 } 44 body = bytes.NewBuffer(encoded) 45 } 46 resp, err := http.Post(client.serverHost+path, "application/json", body) 47 if err != nil { 48 return err 49 } 50 defer resp.Body.Close() 51 if resp.StatusCode != http.StatusOK { 52 return fmt.Errorf("received unexpected status code %d", resp.StatusCode) 53 } 54 return nil 55 } 56 57 func (client *httpClient) poll(path string, data interface{}) error { 58 for { 59 resp, err := http.Get(client.serverHost + path) 60 if err != nil { 61 return err 62 } 63 if resp.StatusCode == http.StatusTooEarly { 64 resp.Body.Close() 65 time.Sleep(POLLING_INTERVAL) 66 continue 67 } 68 defer resp.Body.Close() 69 if resp.StatusCode == http.StatusGone { 70 return ErrorGone 71 } 72 if resp.StatusCode == http.StatusFailedDependency { 73 return ErrorFailed 74 } 75 if resp.StatusCode != http.StatusOK { 76 return fmt.Errorf("received unexpected status code %d", resp.StatusCode) 77 } 78 if data != nil { 79 return json.NewDecoder(resp.Body).Decode(data) 80 } 81 return nil 82 } 83 } 84 85 func (client *httpClient) PostSuiteWillBegin(report types.Report) error { 86 return client.post("/suite-will-begin", report) 87 } 88 89 func (client *httpClient) PostDidRun(report types.SpecReport) error { 90 return client.post("/did-run", report) 91 } 92 93 func (client *httpClient) PostSuiteDidEnd(report types.Report) error { 94 return client.post("/suite-did-end", report) 95 } 96 97 func (client *httpClient) PostSynchronizedBeforeSuiteCompleted(state types.SpecState, data []byte) error { 98 beforeSuiteState := BeforeSuiteState{ 99 State: state, 100 Data: data, 101 } 102 return client.post("/before-suite-completed", beforeSuiteState) 103 } 104 105 func (client *httpClient) BlockUntilSynchronizedBeforeSuiteData() (types.SpecState, []byte, error) { 106 var beforeSuiteState BeforeSuiteState 107 err := client.poll("/before-suite-state", &beforeSuiteState) 108 if err == ErrorGone { 109 return types.SpecStateInvalid, nil, types.GinkgoErrors.SynchronizedBeforeSuiteDisappearedOnProc1() 110 } 111 return beforeSuiteState.State, beforeSuiteState.Data, err 112 } 113 114 func (client *httpClient) BlockUntilNonprimaryProcsHaveFinished() error { 115 return client.poll("/have-nonprimary-procs-finished", nil) 116 } 117 118 func (client *httpClient) BlockUntilAggregatedNonprimaryProcsReport() (types.Report, error) { 119 var report types.Report 120 err := client.poll("/aggregated-nonprimary-procs-report", &report) 121 if err == ErrorGone { 122 return types.Report{}, types.GinkgoErrors.AggregatedReportUnavailableDueToNodeDisappearing() 123 } 124 return report, err 125 } 126 127 func (client *httpClient) FetchNextCounter() (int, error) { 128 var counter ParallelIndexCounter 129 err := client.poll("/counter", &counter) 130 return counter.Index, err 131 } 132 133 func (client *httpClient) PostAbort() error { 134 return client.post("/abort", nil) 135 } 136 137 func (client *httpClient) ShouldAbort() bool { 138 err := client.poll("/abort", nil) 139 if err == ErrorGone { 140 return true 141 } 142 return false 143 } 144 145 func (client *httpClient) Write(p []byte) (int, error) { 146 resp, err := http.Post(client.serverHost+"/emit-output", "text/plain;charset=UTF-8 ", bytes.NewReader(p)) 147 resp.Body.Close() 148 if resp.StatusCode != http.StatusOK { 149 return 0, fmt.Errorf("failed to emit output") 150 } 151 return len(p), err 152 }