// TODO: this test is largely cut and paste, refactor to share code func TestRequestAttachRemoteCommand(t *testing.T) { testCases := []struct { Stdin string Stdout string Stderr string Error string Tty bool }{ { Error: "bail", }, { Stdin: "a", Stdout: "b", Stderr: "c", }, { Stdin: "a", Stdout: "b", Tty: true, }, } for i, testCase := range testCases { localOut := &bytes.Buffer{} localErr := &bytes.Buffer{} server := httptest.NewServer(fakeExecServer(t, i, testCase.Stdin, testCase.Stdout, testCase.Stderr, testCase.Error, testCase.Tty, 1)) url, _ := url.ParseRequestURI(server.URL) c := restclient.NewRESTClient(url, "", restclient.ContentConfig{GroupVersion: &unversioned.GroupVersion{Group: "x"}}, -1, -1, nil) req := c.Post().Resource("testing") conf := &restclient.Config{ Host: server.URL, } e, err := NewExecutor(conf, "POST", req.URL()) if err != nil { t.Errorf("%d: unexpected error: %v", i, err) continue } err = e.Stream(strings.NewReader(testCase.Stdin), localOut, localErr, testCase.Tty) hasErr := err != nil if len(testCase.Error) > 0 { if !hasErr { t.Errorf("%d: expected an error", i) } else { if e, a := testCase.Error, err.Error(); !strings.Contains(a, e) { t.Errorf("%d: expected error stream read '%v', got '%v'", i, e, a) } } // TODO: Uncomment when fix #19254 // server.Close() continue } if hasErr { t.Errorf("%d: unexpected error: %v", i, err) // TODO: Uncomment when fix #19254 // server.Close() continue } if len(testCase.Stdout) > 0 { if e, a := testCase.Stdout, localOut; e != a.String() { t.Errorf("%d: expected stdout data '%s', got '%s'", i, e, a) } } if testCase.Stderr != "" { if e, a := testCase.Stderr, localErr; e != a.String() { t.Errorf("%d: expected stderr data '%s', got '%s'", i, e, a) } } // TODO: Uncomment when fix #19254 // server.Close() } }
func TestStream(t *testing.T) { testCases := []struct { TestName string Stdin string Stdout string Stderr string Error string Tty bool MessageCount int ClientProtocols []string ServerProtocols []string }{ { TestName: "error", Error: "bail", Stdout: "a", ClientProtocols: []string{remotecommand.StreamProtocolV2Name}, ServerProtocols: []string{remotecommand.StreamProtocolV2Name}, }, { TestName: "in/out/err", Stdin: "a", Stdout: "b", Stderr: "c", MessageCount: 100, ClientProtocols: []string{remotecommand.StreamProtocolV2Name}, ServerProtocols: []string{remotecommand.StreamProtocolV2Name}, }, { TestName: "in/out/tty", Stdin: "a", Stdout: "b", Tty: true, MessageCount: 100, ClientProtocols: []string{remotecommand.StreamProtocolV2Name}, ServerProtocols: []string{remotecommand.StreamProtocolV2Name}, }, { // 1.0 kubectl, 1.0 kubelet TestName: "unversioned client, unversioned server", Stdout: "b", Stderr: "c", MessageCount: 1, ClientProtocols: []string{}, ServerProtocols: []string{}, }, { // 1.0 kubectl, 1.1+ kubelet TestName: "unversioned client, versioned server", Stdout: "b", Stderr: "c", MessageCount: 1, ClientProtocols: []string{}, ServerProtocols: []string{remotecommand.StreamProtocolV2Name, remotecommand.StreamProtocolV1Name}, }, { // 1.1+ kubectl, 1.0 kubelet TestName: "versioned client, unversioned server", Stdout: "b", Stderr: "c", MessageCount: 1, ClientProtocols: []string{remotecommand.StreamProtocolV2Name, remotecommand.StreamProtocolV1Name}, ServerProtocols: []string{}, }, } for _, testCase := range testCases { for _, exec := range []bool{true, false} { var name string if exec { name = testCase.TestName + " (exec)" } else { name = testCase.TestName + " (attach)" } var ( streamIn io.Reader streamOut, streamErr io.Writer ) localOut := &bytes.Buffer{} localErr := &bytes.Buffer{} server := httptest.NewServer(fakeServer(t, name, exec, testCase.Stdin, testCase.Stdout, testCase.Stderr, testCase.Error, testCase.Tty, testCase.MessageCount, testCase.ServerProtocols)) url, _ := url.ParseRequestURI(server.URL) config := restclient.ContentConfig{ GroupVersion: &schema.GroupVersion{Group: "x"}, NegotiatedSerializer: testapi.Default.NegotiatedSerializer(), } c, err := restclient.NewRESTClient(url, "", config, -1, -1, nil, nil) if err != nil { t.Fatalf("failed to create a client: %v", err) } req := c.Post().Resource("testing") if exec { req.Param("command", "ls") req.Param("command", "/") } if len(testCase.Stdin) > 0 { req.Param(api.ExecStdinParam, "1") streamIn = strings.NewReader(strings.Repeat(testCase.Stdin, testCase.MessageCount)) } if len(testCase.Stdout) > 0 { req.Param(api.ExecStdoutParam, "1") streamOut = localOut } if testCase.Tty { req.Param(api.ExecTTYParam, "1") } else if len(testCase.Stderr) > 0 { req.Param(api.ExecStderrParam, "1") streamErr = localErr } conf := &restclient.Config{ Host: server.URL, } e, err := NewExecutor(conf, "POST", req.URL()) if err != nil { t.Errorf("%s: unexpected error: %v", name, err) continue } err = e.Stream(StreamOptions{ SupportedProtocols: testCase.ClientProtocols, Stdin: streamIn, Stdout: streamOut, Stderr: streamErr, Tty: testCase.Tty, }) hasErr := err != nil if len(testCase.Error) > 0 { if !hasErr { t.Errorf("%s: expected an error", name) } else { if e, a := testCase.Error, err.Error(); !strings.Contains(a, e) { t.Errorf("%s: expected error stream read %q, got %q", name, e, a) } } server.Close() continue } if hasErr { t.Errorf("%s: unexpected error: %v", name, err) server.Close() continue } if len(testCase.Stdout) > 0 { if e, a := strings.Repeat(testCase.Stdout, testCase.MessageCount), localOut; e != a.String() { t.Errorf("%s: expected stdout data %q, got %q", name, e, a) } } if testCase.Stderr != "" { if e, a := strings.Repeat(testCase.Stderr, testCase.MessageCount), localErr; e != a.String() { t.Errorf("%s: expected stderr data %q, got %q", name, e, a) } } server.Close() } } }
func TestRequestExecuteRemoteCommand(t *testing.T) { testCases := []struct { Stdin string Stdout string Stderr string Error string Tty bool MessageCount int }{ { Error: "bail", }, { Stdin: "a", Stdout: "b", Stderr: "c", // TODO bump this to a larger number such as 100 once // https://github.com/docker/spdystream/issues/55 is fixed and the Godep // is bumped. Sending multiple messages over stdin/stdout/stderr results // in more frames being spread across multiple spdystream frame workers. // This makes it more likely that the spdystream bug will be encountered, // where streams are closed as soon as a goaway frame is received, and // any pending frames that haven't been processed yet may not be // delivered (it's a race). MessageCount: 1, }, { Stdin: "a", Stdout: "b", Tty: true, }, } for i, testCase := range testCases { localOut := &bytes.Buffer{} localErr := &bytes.Buffer{} server := httptest.NewServer(fakeExecServer(t, i, testCase.Stdin, testCase.Stdout, testCase.Stderr, testCase.Error, testCase.Tty, testCase.MessageCount)) url, _ := url.ParseRequestURI(server.URL) c := restclient.NewRESTClient(url, "", restclient.ContentConfig{GroupVersion: &unversioned.GroupVersion{Group: "x"}}, -1, -1, nil) req := c.Post().Resource("testing") req.SetHeader(httpstream.HeaderProtocolVersion, StreamProtocolV2Name) req.Param("command", "ls") req.Param("command", "/") conf := &restclient.Config{ Host: server.URL, } e, err := NewExecutor(conf, "POST", req.URL()) if err != nil { t.Errorf("%d: unexpected error: %v", i, err) continue } err = e.Stream(strings.NewReader(strings.Repeat(testCase.Stdin, testCase.MessageCount)), localOut, localErr, testCase.Tty) hasErr := err != nil if len(testCase.Error) > 0 { if !hasErr { t.Errorf("%d: expected an error", i) } else { if e, a := testCase.Error, err.Error(); !strings.Contains(a, e) { t.Errorf("%d: expected error stream read '%v', got '%v'", i, e, a) } } // TODO: Uncomment when fix #19254 // server.Close() continue } if hasErr { t.Errorf("%d: unexpected error: %v", i, err) // TODO: Uncomment when fix #19254 // server.Close() continue } if len(testCase.Stdout) > 0 { if e, a := strings.Repeat(testCase.Stdout, testCase.MessageCount), localOut; e != a.String() { t.Errorf("%d: expected stdout data '%s', got '%s'", i, e, a) } } if testCase.Stderr != "" { if e, a := strings.Repeat(testCase.Stderr, testCase.MessageCount), localErr; e != a.String() { t.Errorf("%d: expected stderr data '%s', got '%s'", i, e, a) } } // TODO: Uncomment when fix #19254 // server.Close() } }