diff --git a/internal/upstream/routes.go b/internal/upstream/routes.go index 11f990542b5c676c747084e8bdb7a92a0a8e822e..520cef5230b6be873756e69d3053726ccfb52205 100644 --- a/internal/upstream/routes.go +++ b/internal/upstream/routes.go @@ -161,6 +161,7 @@ func (u *Upstream) configureRoutes() { // Terminal websocket wsRoute(projectPattern+`environments/[0-9]+/terminal.ws\z`, terminal.Handler(api)), + wsRoute(projectPattern+`-/jobs/[0-9]+/terminal.ws\z`, terminal.Handler(api)), // Long poll and limit capacity given to jobs/request and builds/register.json route("", apiPattern+`v4/jobs/request\z`, ciAPILongPolling), diff --git a/terminal_test.go b/terminal_test.go index 8d7da8b2cab75b5139e9eaafec809a227d940084..9d91a2803c70ad1e1b2df4811e7ded062a1a6cd1 100644 --- a/terminal_test.go +++ b/terminal_test.go @@ -20,7 +20,10 @@ import ( "gitlab.com/gitlab-org/gitlab-workhorse/internal/api" ) -var terminalPath = fmt.Sprintf("%s/environments/1/terminal.ws", testProject) +var ( + envTerminalPath = fmt.Sprintf("%s/environments/1/terminal.ws", testProject) + jobTerminalPath = fmt.Sprintf("%s/-/jobs/1/terminal.ws", testProject) +) type connWithReq struct { conn *websocket.Conn @@ -28,39 +31,50 @@ type connWithReq struct { } func TestTerminalHappyPath(t *testing.T) { - serverConns, clientURL, close := wireupTerminal(nil, "channel.k8s.io") - defer close() - - client, _, err := dialWebsocket(clientURL, nil, "terminal.gitlab.com") - if err != nil { - t.Fatal(err) + tests := []struct { + name string + terminalPath string + }{ + {"environments", envTerminalPath}, + {"jobs", jobTerminalPath}, } - - server := (<-serverConns).conn - defer server.Close() - - message := "test message" - - // channel.k8s.io: server writes to channel 1, STDOUT - if err := say(server, "\x01"+message); err != nil { - t.Fatal(err) + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + serverConns, clientURL, close := wireupTerminal(test.terminalPath, nil, "channel.k8s.io") + defer close() + + client, _, err := dialWebsocket(clientURL, nil, "terminal.gitlab.com") + if err != nil { + t.Fatal(err) + } + + server := (<-serverConns).conn + defer server.Close() + + message := "test message" + + // channel.k8s.io: server writes to channel 1, STDOUT + if err := say(server, "\x01"+message); err != nil { + t.Fatal(err) + } + assertReadMessage(t, client, websocket.BinaryMessage, message) + + if err := say(client, message); err != nil { + t.Fatal(err) + } + + // channel.k8s.io: client writes get put on channel 0, STDIN + assertReadMessage(t, server, websocket.BinaryMessage, "\x00"+message) + + // Closing the client should send an EOT signal to the server's STDIN + client.Close() + assertReadMessage(t, server, websocket.BinaryMessage, "\x00\x04") + }) } - assertReadMessage(t, client, websocket.BinaryMessage, message) - - if err := say(client, message); err != nil { - t.Fatal(err) - } - - // channel.k8s.io: client writes get put on channel 0, STDIN - assertReadMessage(t, server, websocket.BinaryMessage, "\x00"+message) - - // Closing the client should send an EOT signal to the server's STDIN - client.Close() - assertReadMessage(t, server, websocket.BinaryMessage, "\x00\x04") } func TestTerminalBadTLS(t *testing.T) { - _, clientURL, close := wireupTerminal(badCA, "channel.k8s.io") + _, clientURL, close := wireupTerminal(envTerminalPath, badCA, "channel.k8s.io") defer close() client, _, err := dialWebsocket(clientURL, nil, "terminal.gitlab.com") @@ -74,7 +88,7 @@ func TestTerminalBadTLS(t *testing.T) { } func TestTerminalSessionTimeout(t *testing.T) { - serverConns, clientURL, close := wireupTerminal(timeout, "channel.k8s.io") + serverConns, clientURL, close := wireupTerminal(envTerminalPath, timeout, "channel.k8s.io") defer close() client, _, err := dialWebsocket(clientURL, nil, "terminal.gitlab.com") @@ -96,7 +110,7 @@ func TestTerminalSessionTimeout(t *testing.T) { func TestTerminalProxyForwardsHeadersFromUpstream(t *testing.T) { hdr := make(http.Header) hdr.Set("Random-Header", "Value") - serverConns, clientURL, close := wireupTerminal(setHeader(hdr), "channel.k8s.io") + serverConns, clientURL, close := wireupTerminal(envTerminalPath, setHeader(hdr), "channel.k8s.io") defer close() client, _, err := dialWebsocket(clientURL, nil, "terminal.gitlab.com") @@ -113,7 +127,7 @@ func TestTerminalProxyForwardsHeadersFromUpstream(t *testing.T) { } func TestTerminalProxyForwardsXForwardedForFromClient(t *testing.T) { - serverConns, clientURL, close := wireupTerminal(nil, "channel.k8s.io") + serverConns, clientURL, close := wireupTerminal(envTerminalPath, nil, "channel.k8s.io") defer close() hdr := make(http.Header) @@ -136,7 +150,7 @@ func TestTerminalProxyForwardsXForwardedForFromClient(t *testing.T) { } } -func wireupTerminal(modifier func(*api.Response), subprotocols ...string) (chan connWithReq, string, func()) { +func wireupTerminal(terminalPath string, modifier func(*api.Response), subprotocols ...string) (chan connWithReq, string, func()) { serverConns, remote := startWebsocketServer(subprotocols...) authResponse := terminalOkBody(remote, nil, subprotocols...) if modifier != nil {