@@ -25,24 +25,28 @@ import (
25
25
"testing"
26
26
"time"
27
27
28
+ "go.uber.org/goleak"
29
+ "tailscale.com/net/speedtest"
30
+ "tailscale.com/tailcfg"
31
+
28
32
"github.com/bramvdbogaerde/go-scp"
29
33
"github.com/google/uuid"
34
+ "github.com/ory/dockertest/v3"
35
+ "github.com/ory/dockertest/v3/docker"
30
36
"github.com/pion/udp"
31
37
"github.com/pkg/sftp"
32
38
"github.com/prometheus/client_golang/prometheus"
33
39
promgo"github.com/prometheus/client_model/go"
34
40
"github.com/spf13/afero"
35
41
"github.com/stretchr/testify/assert"
36
42
"github.com/stretchr/testify/require"
37
- "go.uber.org/goleak"
38
43
"golang.org/x/crypto/ssh"
39
44
"golang.org/x/exp/slices"
40
45
"golang.org/x/xerrors"
41
- "tailscale.com/net/speedtest"
42
- "tailscale.com/tailcfg"
43
46
44
47
"cdr.dev/slog"
45
48
"cdr.dev/slog/sloggers/slogtest"
49
+
46
50
"github.com/coder/coder/v2/agent"
47
51
"github.com/coder/coder/v2/agent/agentssh"
48
52
"github.com/coder/coder/v2/agent/agenttest"
@@ -1761,6 +1765,69 @@ func TestAgent_ReconnectingPTY(t *testing.T) {
1761
1765
}
1762
1766
}
1763
1767
1768
+ // This tests end-to-end functionality of connecting to a running container
1769
+ // and executing a command. It creates a real Docker container and runs a
1770
+ // command. As such, it does not run by default in CI.
1771
+ // You can run it manually as follows:
1772
+ //
1773
+ // CODER_TEST_USE_DOCKER=1 go test -count=1 ./agent -run TestAgent_ReconnectingPTYContainer
1774
+ func TestAgent_ReconnectingPTYContainer (t * testing.T ) {
1775
+ t .Parallel ()
1776
+ if ctud ,ok := os .LookupEnv ("CODER_TEST_USE_DOCKER" );! ok || ctud != "1" {
1777
+ t .Skip ("Set CODER_TEST_USE_DOCKER=1 to run this test" )
1778
+ }
1779
+
1780
+ ctx ,cancel := context .WithTimeout (context .Background (),testutil .WaitLong )
1781
+ defer cancel ()
1782
+
1783
+ pool ,err := dockertest .NewPool ("" )
1784
+ require .NoError (t ,err ,"Could not connect to docker" )
1785
+ ct ,err := pool .RunWithOptions (& dockertest.RunOptions {
1786
+ Repository :"busybox" ,
1787
+ Tag :"latest" ,
1788
+ Cmd : []string {"sleep" ,"infnity" },
1789
+ },func (config * docker.HostConfig ) {
1790
+ config .AutoRemove = true
1791
+ config .RestartPolicy = docker.RestartPolicy {Name :"no" }
1792
+ })
1793
+ require .NoError (t ,err ,"Could not start container" )
1794
+ // Wait for container to start
1795
+ require .Eventually (t ,func ()bool {
1796
+ ct ,ok := pool .ContainerByName (ct .Container .Name )
1797
+ return ok && ct .Container .State .Running
1798
+ },testutil .WaitShort ,testutil .IntervalSlow ,"Container did not start in time" )
1799
+
1800
+ // nolint: dogsled
1801
+ conn ,_ ,_ ,_ ,_ := setupAgent (t , agentsdk.Manifest {},0 )
1802
+ ac ,err := conn .ReconnectingPTY (ctx ,uuid .New (),80 ,80 ,"/bin/sh" ,func (arp * workspacesdk.AgentReconnectingPTYInit ) {
1803
+ arp .Container = ct .Container .ID
1804
+ })
1805
+ require .NoError (t ,err ,"failed to create ReconnectingPTY" )
1806
+ defer ac .Close ()
1807
+ tr := testutil .NewTerminalReader (t ,ac )
1808
+
1809
+ require .NoError (t ,tr .ReadUntil (ctx ,func (line string )bool {
1810
+ return strings .Contains (line ,"#" )|| strings .Contains (line ,"$" )
1811
+ }),"find prompt" )
1812
+
1813
+ require .NoError (t ,json .NewEncoder (ac ).Encode (workspacesdk.ReconnectingPTYRequest {
1814
+ Data :"hostname\r " ,
1815
+ }),"write hostname" )
1816
+ require .NoError (t ,tr .ReadUntil (ctx ,func (line string )bool {
1817
+ return strings .Contains (line ,"hostname" )
1818
+ }),"find hostname command" )
1819
+
1820
+ require .NoError (t ,tr .ReadUntil (ctx ,func (line string )bool {
1821
+ return strings .Contains (line ,ct .Container .Config .Hostname )
1822
+ }),"find hostname output" )
1823
+ require .NoError (t ,json .NewEncoder (ac ).Encode (workspacesdk.ReconnectingPTYRequest {
1824
+ Data :"exit\r " ,
1825
+ }),"write exit command" )
1826
+
1827
+ // Wait for the connection to close.
1828
+ require .ErrorIs (t ,tr .ReadUntil (ctx ,nil ),io .EOF )
1829
+ }
1830
+
1764
1831
func TestAgent_Dial (t * testing.T ) {
1765
1832
t .Parallel ()
1766
1833