github.com/telepresenceio/telepresence/v2@v2.20.0-pro.6.0.20240517030216-236ea954e789/integration_test/api_test.go (about) 1 package integration_test 2 3 import ( 4 "context" 5 goRuntime "runtime" 6 "sync" 7 "unicode" 8 "unicode/utf8" 9 10 "github.com/google/go-cmp/cmp" 11 "github.com/google/go-cmp/cmp/cmpopts" 12 "helm.sh/helm/v3/pkg/cli/values" 13 14 "github.com/telepresenceio/telepresence/rpc/v2/connector" 15 "github.com/telepresenceio/telepresence/v2/integration_test/itest" 16 "github.com/telepresenceio/telepresence/v2/pkg/client" 17 "github.com/telepresenceio/telepresence/v2/pkg/client/cli" 18 "github.com/telepresenceio/telepresence/v2/pkg/client/cli/api" 19 "github.com/telepresenceio/telepresence/v2/pkg/client/cli/helm" 20 "github.com/telepresenceio/telepresence/v2/pkg/dos" 21 "github.com/telepresenceio/telepresence/v2/pkg/version" 22 ) 23 24 type apiSuite struct { 25 itest.Suite 26 itest.NamespacePair 27 svc string 28 } 29 30 func (s *apiSuite) SuiteName() string { 31 return "API" 32 } 33 34 func init() { 35 itest.AddNamespacePairSuite("", func(h itest.NamespacePair) itest.TestingSuite { 36 return &apiSuite{Suite: itest.Suite{Harness: h}, NamespacePair: h, svc: "echo"} 37 }) 38 } 39 40 func (s *apiSuite) request() api.ConnectRequest { 41 rq := api.ConnectRequest{} 42 rq.KubeFlags = map[string]string{ 43 "namespace": s.AppNamespace(), 44 "kubeconfig": itest.KubeConfig(s.Context()), 45 } 46 rq.ManagerNamespace = s.ManagerNamespace() 47 return rq 48 } 49 50 func (s *apiSuite) AmendSuiteContext(ctx context.Context) context.Context { 51 // The default executable will be the test executable. We need the telepresence executable here. 52 return dos.WithExe(ctx, s) 53 } 54 55 func (s *apiSuite) SetupSuite() { 56 s.Suite.SetupSuite() 57 wg := sync.WaitGroup{} 58 wg.Add(2) 59 go func() { 60 defer wg.Done() 61 ctx := s.Context() 62 hr := helm.Request{ 63 Options: values.Options{ 64 Values: s.GetValuesForHelm(ctx, nil, false), 65 }, 66 Type: helm.Install, 67 } 68 s.Require().NoError(cli.NewClient(ctx).Helm(&hr, s.request())) 69 }() 70 go func() { 71 defer wg.Done() 72 s.ApplyEchoService(s.Context(), s.svc, 80) 73 }() 74 wg.Wait() 75 } 76 77 func (s *apiSuite) TearDownSuite() { 78 wg := sync.WaitGroup{} 79 wg.Add(2) 80 go func() { 81 defer wg.Done() 82 s.DeleteSvcAndWorkload(s.Context(), "deploy", s.svc) 83 }() 84 go func() { 85 defer wg.Done() 86 hr := helm.Request{Type: helm.Uninstall} 87 s.Require().NoError(cli.NewClient(s.Context()).Helm(&hr, s.request())) 88 }() 89 wg.Wait() 90 } 91 92 func (s *apiSuite) Test_Connect() { 93 rq := s.Require() 94 ctx := s.Context() 95 client := cli.NewClient(ctx) 96 conn, err := client.Connect(s.request()) 97 rq.NoError(err) 98 defer func() { 99 s.NoError(conn.Disconnect()) 100 }() 101 rq.Equal(conn.Info().Namespace, s.AppNamespace()) 102 } 103 104 func (s *apiSuite) Test_List() { 105 rq := s.Require() 106 ctx := s.Context() 107 client := cli.NewClient(ctx) 108 109 conn, err := client.Connect(s.request()) 110 rq.NoError(err) 111 defer func() { 112 s.NoError(conn.Disconnect()) 113 }() 114 115 wfs, err := conn.List("") 116 rq.NoError(err) 117 rq.Len(wfs, 1) 118 rq.Equal(wfs[0].Name, s.svc) 119 rq.Equal(conn.Info().Namespace, s.AppNamespace()) 120 } 121 122 func (s *apiSuite) Test_StartIntercept() { 123 rq := s.Require() 124 ctx := s.Context() 125 client := cli.NewClient(ctx) 126 127 conn, err := client.Connect(s.request()) 128 rq.NoError(err) 129 defer func() { 130 s.NoError(conn.Disconnect()) 131 }() 132 133 ii, err := conn.StartIntercept(api.InterceptRequest{ 134 WorkloadName: "echo", 135 Port: "8080", 136 }, "") 137 rq.NoError(err) 138 defer func() { 139 s.NoError(conn.EndIntercept(ii.Name)) 140 }() 141 s.NotNil(ii.Environment) 142 s.Equal("echo-server", ii.Environment["TELEPRESENCE_CONTAINER"]) 143 } 144 145 func (s *apiSuite) Test_RunIntercept() { 146 if s.IsCI() && !(goRuntime.GOOS == "linux" && goRuntime.GOARCH == "amd64") { 147 s.T().Skip("CI can't run linux docker containers inside non-linux runners") 148 } 149 150 ctx := itest.WithConfig(s.Context(), func(cfg client.Config) { 151 cfg.Intercept().UseFtp = false 152 }) 153 154 rq := s.Require() 155 client := cli.NewClient(ctx) 156 157 cr := s.request() 158 cr.Docker = true 159 conn, err := client.Connect(cr) 160 rq.NoError(err) 161 defer func() { 162 s.NoError(conn.Disconnect()) 163 }() 164 165 _, err = conn.RunIntercept( 166 api.InterceptRequest{ 167 WorkloadName: "echo", 168 Port: "8080", 169 }, 170 api.DockerRunInterceptHandler{ 171 Image: "busybox", 172 Arguments: []string{"ls", "/var/run/secrets/kubernetes.io/serviceaccount"}, 173 }) 174 rq.NoError(err) 175 } 176 177 func (s *apiSuite) Test_Connections() { 178 if s.IsCI() && !(goRuntime.GOOS == "linux" && goRuntime.GOARCH == "amd64") { 179 s.T().Skip("CI can't run linux docker containers inside non-linux runners") 180 } 181 182 ctx := itest.WithConfig(s.Context(), func(cfg client.Config) { 183 cfg.Intercept().UseFtp = false 184 }) 185 186 // Establish two connections 187 rq := s.Require() 188 client := cli.NewClient(ctx) 189 r1 := s.request() 190 r1.Name = "alpha" 191 r1.Docker = true 192 c1, err := client.Connect(r1) 193 rq.NoError(err) 194 defer func() { 195 s.NoError(c1.Disconnect()) 196 }() 197 198 r2 := s.request() 199 r2.Name = "beta" 200 r2.Docker = true 201 r2.KubeFlags["namespace"] = s.ManagerNamespace() 202 c2, err := client.Connect(r2) 203 rq.NoError(err) 204 defer func() { 205 s.NoError(c2.Disconnect()) 206 }() 207 208 // Verify that the two connections can be listed 209 conns, err := client.Connections() 210 rq.NoError(err) 211 rq.Equal(2, len(conns)) 212 213 if conns[0].Name == r1.Name { 214 rq.Equal(conns[1].Name, r2.Name) 215 } else { 216 rq.Equal(conns[1].Name, r1.Name) 217 rq.Equal(conns[0].Name, r2.Name) 218 } 219 220 // Retrieve connection by name 221 cc1, err := client.Connection("alpha") 222 rq.NoError(err) 223 224 // The error is set to ALREADY_CONNECTED when the connection is already established. This is expected. 225 ignoreErr := cmpopts.IgnoreFields(connector.ConnectInfo{}, "Error") 226 ignoreUnEx := cmp.FilterPath(unexported, cmp.Ignore()) 227 228 rq.True(cmp.Equal(c1.Info(), cc1.Info(), ignoreErr, ignoreUnEx), cmp.Diff(c1.Info(), cc1.Info(), ignoreErr, ignoreUnEx)) 229 230 // Retrieve connection by name 231 cc2, err := client.Connection("beta") 232 rq.NoError(err) 233 rq.True(cmp.Equal(c2.Info(), cc2.Info(), ignoreErr, ignoreUnEx), cmp.Diff(c2.Info(), cc2.Info(), ignoreErr, ignoreUnEx)) 234 } 235 236 func (s *apiSuite) Test_Version() { 237 client := cli.NewClient(s.Context()) 238 s.Equal(version.Structured, client.Version()) 239 } 240 241 func unexported(p cmp.Path) bool { 242 if f, ok := p.Index(-1).(cmp.StructField); ok { 243 r, _ := utf8.DecodeRuneInString(f.Name()) 244 return !unicode.IsUpper(r) 245 } 246 return false 247 }