func fakeExecServer(t *testing.T, i int, stdinData, stdoutData, stderrData, errorData string, tty bool, messageCount int) http.HandlerFunc { // error + stdin + stdout expectedStreams := 3 if !tty { // stderr expectedStreams++ } return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { protocol, err := httpstream.Handshake(req, w, []string{StreamProtocolV2Name}, StreamProtocolV1Name) if err != nil { t.Fatal(err) } if protocol != StreamProtocolV2Name { t.Fatalf("unexpected protocol: %s", protocol) } streamCh := make(chan httpstream.Stream) upgrader := spdy.NewResponseUpgrader() conn := upgrader.UpgradeResponse(w, req, func(stream httpstream.Stream) error { streamCh <- stream return nil }) // from this point on, we can no longer call methods on w if conn == nil { // The upgrader is responsible for notifying the client of any errors that // occurred during upgrading. All we can do is return here at this point // if we weren't successful in upgrading. return } defer conn.Close() var errorStream, stdinStream, stdoutStream, stderrStream httpstream.Stream receivedStreams := 0 WaitForStreams: for { select { case stream := <-streamCh: streamType := stream.Headers().Get(api.StreamType) switch streamType { case api.StreamTypeError: errorStream = stream receivedStreams++ case api.StreamTypeStdin: stdinStream = stream receivedStreams++ case api.StreamTypeStdout: stdoutStream = stream receivedStreams++ case api.StreamTypeStderr: stderrStream = stream receivedStreams++ default: t.Errorf("%d: unexpected stream type: %q", i, streamType) } if receivedStreams == expectedStreams { break WaitForStreams } } } if len(errorData) > 0 { n, err := fmt.Fprint(errorStream, errorData) if err != nil { t.Errorf("%d: error writing to errorStream: %v", i, err) } if e, a := len(errorData), n; e != a { t.Errorf("%d: expected to write %d bytes to errorStream, but only wrote %d", i, e, a) } errorStream.Close() } if len(stdoutData) > 0 { for j := 0; j < messageCount; j++ { n, err := fmt.Fprint(stdoutStream, stdoutData) if err != nil { t.Errorf("%d: error writing to stdoutStream: %v", i, err) } if e, a := len(stdoutData), n; e != a { t.Errorf("%d: expected to write %d bytes to stdoutStream, but only wrote %d", i, e, a) } } stdoutStream.Close() } if len(stderrData) > 0 { for j := 0; j < messageCount; j++ { n, err := fmt.Fprint(stderrStream, stderrData) if err != nil { t.Errorf("%d: error writing to stderrStream: %v", i, err) } if e, a := len(stderrData), n; e != a { t.Errorf("%d: expected to write %d bytes to stderrStream, but only wrote %d", i, e, a) } } stderrStream.Close() } if len(stdinData) > 0 { data := make([]byte, len(stdinData)) for j := 0; j < messageCount; j++ { n, err := io.ReadFull(stdinStream, data) if err != nil { t.Errorf("%d: error reading stdin stream: %v", i, err) } if e, a := len(stdinData), n; e != a { t.Errorf("%d: expected to read %d bytes from stdinStream, but only read %d", i, e, a) } if e, a := stdinData, string(data); e != a { t.Errorf("%d: stdin: expected %q, got %q", i, e, a) } } stdinStream.Close() } }) }