Skip to content

Commit f0bf2e8

Browse files
Prince Rachit Sinharoboquat
authored andcommitted
[integration-test] Enable tests to run from local
1 parent 0cdce52 commit f0bf2e8

File tree

5 files changed

+112
-30
lines changed

5 files changed

+112
-30
lines changed

test/README.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,5 +69,4 @@ To run the tests:
6969
-enterprise=<true|false> \
7070
-gitlab=<true|false>
7171
```
72-
3. Tests `TestUploadDownloadBlob` and `TestUploadDownloadBlobViaServer` will fail when testing locally, as they are trying to connect to cluster local resources directly. To test them use docker image instead that runs within the cluster.
73-
4. If you want to run specific test, add `-run <test>` before `-kubeconfig` parameter.
72+
3. If you want to run specific test, add `-run <test>` before `-kubeconfig` parameter.

test/pkg/integration/apis.go

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import (
1717
"encoding/json"
1818
"errors"
1919
"fmt"
20+
"net"
2021
"net/http"
2122
"net/url"
2223
"strconv"
@@ -157,6 +158,39 @@ func EncryptValue(value []byte, key []byte) (data string, iv string) {
157158
return
158159
}
159160

161+
// Storage provides a url of the storage provider
162+
// it takes a url as input and creates a port forward if required
163+
// e.g. when minio running in gitpod cluster
164+
// and modifies the url to refer to the localhost instead of dns name
165+
func (c *ComponentAPI) Storage(connUrl string) (string, error) {
166+
u, err := url.Parse(connUrl)
167+
if err != nil {
168+
return "", err
169+
}
170+
host, port, _ := net.SplitHostPort(u.Host)
171+
if !strings.HasSuffix(host, ".svc.cluster.local") {
172+
return connUrl, nil
173+
}
174+
serviceName := strings.Split(host, ".")[0]
175+
176+
localPort, err := getFreePort()
177+
if err != nil {
178+
return "", err
179+
}
180+
181+
ctx, cancel := context.WithCancel(context.Background())
182+
ready, errc := common.ForwardPortOfSvc(ctx, c.kubeconfig, c.namespace, serviceName, fmt.Sprintf("%d:%s", localPort, port))
183+
select {
184+
case err = <-errc:
185+
cancel()
186+
return "", err
187+
case <-ready:
188+
}
189+
c.appendCloser(func() error { cancel(); return nil })
190+
191+
return strings.Replace(connUrl, u.Host, fmt.Sprintf("localhost:%d", localPort), 1), nil
192+
}
193+
160194
// Supervisor provides a gRPC connection to a workspace's supervisor
161195
func (c *ComponentAPI) Supervisor(instanceID string) (grpc.ClientConnInterface, error) {
162196
pod, _, err := selectPod(ComponentWorkspace, selectPodOptions{
@@ -172,7 +206,7 @@ func (c *ComponentAPI) Supervisor(instanceID string) (grpc.ClientConnInterface,
172206
}
173207

174208
ctx, cancel := context.WithCancel(context.Background())
175-
ready, errc := common.ForwardPort(ctx, c.kubeconfig, c.namespace, pod, fmt.Sprintf("%d:22999", localPort))
209+
ready, errc := common.ForwardPortOfPod(ctx, c.kubeconfig, c.namespace, pod, fmt.Sprintf("%d:22999", localPort))
176210
select {
177211
case err = <-errc:
178212
cancel()
@@ -594,7 +628,7 @@ func (c *ComponentAPI) WorkspaceManager() (wsmanapi.WorkspaceManagerClient, erro
594628
}
595629

596630
ctx, cancel := context.WithCancel(context.Background())
597-
ready, errc := common.ForwardPort(ctx, c.kubeconfig, c.namespace, pod, fmt.Sprintf("%d:8080", localPort))
631+
ready, errc := common.ForwardPortOfPod(ctx, c.kubeconfig, c.namespace, pod, fmt.Sprintf("%d:8080", localPort))
598632
select {
599633
case err := <-errc:
600634
cancel()
@@ -667,7 +701,7 @@ func (c *ComponentAPI) BlobService() (csapi.BlobServiceClient, error) {
667701
}
668702

669703
ctx, cancel := context.WithCancel(context.Background())
670-
ready, errc := common.ForwardPort(ctx, c.kubeconfig, c.namespace, pod, fmt.Sprintf("%d:8080", localPort))
704+
ready, errc := common.ForwardPortOfPod(ctx, c.kubeconfig, c.namespace, pod, fmt.Sprintf("%d:8080", localPort))
671705
select {
672706
case err := <-errc:
673707
cancel()
@@ -720,7 +754,7 @@ func (c *ComponentAPI) DB(options ...DBOpt) (*sql.DB, error) {
720754
// if configured: setup local port-forward to DB pod
721755
if config.ForwardPort != nil {
722756
ctx, cancel := context.WithCancel(context.Background())
723-
ready, errc := common.ForwardPort(ctx, c.kubeconfig, c.namespace, config.ForwardPort.PodName, fmt.Sprintf("%d:%d", config.Port, config.ForwardPort.RemotePort))
757+
ready, errc := common.ForwardPortOfPod(ctx, c.kubeconfig, c.namespace, config.ForwardPort.PodName, fmt.Sprintf("%d:%d", config.Port, config.ForwardPort.RemotePort))
724758
select {
725759
case err := <-errc:
726760
cancel()
@@ -966,7 +1000,7 @@ func (c *ComponentAPI) ImageBuilder(opts ...APIImageBuilderOpt) (imgbldr.ImageBu
9661000
}
9671001

9681002
ctx, cancel := context.WithCancel(context.Background())
969-
ready, errc := common.ForwardPort(ctx, c.kubeconfig, c.namespace, pod, fmt.Sprintf("%d:8080", localPort))
1003+
ready, errc := common.ForwardPortOfPod(ctx, c.kubeconfig, c.namespace, pod, fmt.Sprintf("%d:8080", localPort))
9701004
select {
9711005
case err = <-errc:
9721006
cancel()
@@ -1015,7 +1049,7 @@ func (c *ComponentAPI) ContentService() (ContentService, error) {
10151049
}
10161050

10171051
ctx, cancel := context.WithCancel(context.Background())
1018-
ready, errc := common.ForwardPort(ctx, c.kubeconfig, c.namespace, pod, fmt.Sprintf("%d:8080", localPort))
1052+
ready, errc := common.ForwardPortOfPod(ctx, c.kubeconfig, c.namespace, pod, fmt.Sprintf("%d:8080", localPort))
10191053
select {
10201054
case err := <-errc:
10211055
cancel()

test/pkg/integration/common/port_forward.go

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,28 @@ import (
1515
"golang.org/x/xerrors"
1616
)
1717

18-
// ForwardPort establishes a TCP port forwarding to a Kubernetes pod
18+
// ForwardPortOfPod establishes a TCP port forwarding to a Kubernetes pod
19+
func ForwardPortOfPod(ctx context.Context, kubeconfig string, namespace, name, port string) (readychan chan struct{}, errchan chan error) {
20+
return forwardPort(ctx, kubeconfig, namespace, "pod", name, port)
21+
}
22+
23+
// ForwardPortOfSvc establishes a TCP port forwarding to a Kubernetes service
24+
func ForwardPortOfSvc(ctx context.Context, kubeconfig string, namespace, name, port string) (readychan chan struct{}, errchan chan error) {
25+
return forwardPort(ctx, kubeconfig, namespace, "service", name, port)
26+
}
27+
28+
// forwardPort establishes a TCP port forwarding to a Kubernetes resource - pod or service
1929
// Uses kubectl instead of Go to use a local process that can reproduce the same behavior outside the tests
2030
// Since we are using kubectl directly we need to pass kubeconfig explicitly
21-
func ForwardPort(ctx context.Context, kubeconfig string, namespace, pod, port string) (readychan chan struct{}, errchan chan error) {
31+
func forwardPort(ctx context.Context, kubeconfig string, namespace, resourceType, name, port string) (readychan chan struct{}, errchan chan error) {
2232
errchan = make(chan error, 1)
2333
readychan = make(chan struct{}, 1)
2434

2535
go func() {
2636
args := []string{
2737
"port-forward",
2838
"--address=0.0.0.0",
29-
fmt.Sprintf("pod/%v", pod),
39+
fmt.Sprintf("%s/%v", resourceType, name),
3040
fmt.Sprintf("--namespace=%v", namespace),
3141
fmt.Sprintf("--kubeconfig=%v", kubeconfig),
3242
port,

test/pkg/integration/integration.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ func Instrument(component ComponentType, agentName string, namespace string, kub
215215
}
216216
}()
217217

218-
fwdReady, fwdErr := common.ForwardPort(ctx, kubeconfig, namespace, podName, strconv.Itoa(localAgentPort))
218+
fwdReady, fwdErr := common.ForwardPortOfPod(ctx, kubeconfig, namespace, podName, strconv.Itoa(localAgentPort))
219219
select {
220220
case <-fwdReady:
221221
case err := <-execErrs:

test/tests/components/content-service/content-service_test.go

Lines changed: 57 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"fmt"
1010
"io"
1111
"net/http"
12+
"net/url"
1213
"strings"
1314
"testing"
1415
"time"
@@ -190,19 +191,27 @@ func TestUploadDownloadBlob(t *testing.T) {
190191
if err != nil {
191192
t.Fatal(err)
192193
}
193-
url := resp.Url
194-
t.Logf("upload URL: %s", url)
194+
originalUrl := resp.Url
195+
updatedUrl, err := api.Storage(originalUrl)
196+
if err != nil {
197+
t.Fatalf("error resolving blob upload target url")
198+
}
199+
t.Logf("upload URL: %s", updatedUrl)
195200

196-
uploadBlob(t, url, blobContent)
201+
uploadBlob(t, originalUrl, updatedUrl, blobContent)
197202

198203
resp2, err := bs.DownloadUrl(ctx, &content_service_api.DownloadUrlRequest{OwnerId: gitpodBuiltinUserID, Name: "test-blob"})
199204
if err != nil {
200205
t.Fatal(err)
201206
}
202-
url = resp2.Url
203-
t.Logf("download URL: %s", url)
207+
originalUrl = resp2.Url
208+
updatedUrl, err = api.Storage(originalUrl)
209+
if err != nil {
210+
t.Fatalf("error resolving blob download target url")
211+
}
212+
t.Logf("download URL: %s", updatedUrl)
204213

205-
body := downloadBlob(t, url)
214+
body := downloadBlob(t, originalUrl, updatedUrl)
206215
if string(body) != blobContent {
207216
t.Fatalf("blob content mismatch: should '%s' but is '%s'", blobContent, body)
208217
}
@@ -235,21 +244,30 @@ func TestUploadDownloadBlobViaServer(t *testing.T) {
235244
t.Fatalf("cannot get content blob upload URL: %q", err)
236245
}
237246

238-
url, err := server.GetContentBlobUploadURL(ctx, "test-blob")
247+
originalUrl, err := server.GetContentBlobUploadURL(ctx, "test-blob")
239248
if err != nil {
240249
t.Fatalf("cannot get content blob upload URL: %q", err)
241250
}
242-
t.Logf("upload URL: %s", url)
251+
updatedUrl, err := api.Storage(originalUrl)
252+
if err != nil {
253+
t.Fatalf("error resolving blob upload target url")
254+
}
255+
t.Logf("upload URL: %s", updatedUrl)
243256

244-
uploadBlob(t, url, blobContent)
257+
uploadBlob(t, originalUrl, updatedUrl, blobContent)
245258

246-
url, err = server.GetContentBlobDownloadURL(ctx, "test-blob")
259+
originalUrl, err = server.GetContentBlobDownloadURL(ctx, "test-blob")
247260
if err != nil {
248261
t.Fatalf("cannot get content blob download URL: %q", err)
249262
}
250-
t.Logf("download URL: %s", url)
251263

252-
body := downloadBlob(t, url)
264+
updatedUrl, err = api.Storage(originalUrl)
265+
if err != nil {
266+
t.Fatalf("error resolving blob download target url")
267+
}
268+
t.Logf("download URL: %s", updatedUrl)
269+
270+
body := downloadBlob(t, originalUrl, updatedUrl)
253271
if string(body) != blobContent {
254272
t.Fatalf("blob content mismatch: should '%s' but is '%s'", blobContent, body)
255273
}
@@ -263,12 +281,20 @@ func TestUploadDownloadBlobViaServer(t *testing.T) {
263281
testEnv.Test(t, f)
264282
}
265283

266-
func uploadBlob(t *testing.T, url string, content string) {
284+
func uploadBlob(t *testing.T, originalUrl, updatedUrl, content string) {
285+
// Always use original URL to extract the host information.
286+
// This will avoid any Signature mismatch errors
287+
u, err := url.Parse(originalUrl)
288+
if err != nil {
289+
t.Fatal(err)
290+
}
267291
var client = &http.Client{Timeout: time.Second * 10}
268-
httpreq, err := http.NewRequest(http.MethodPut, url, strings.NewReader(content))
292+
httpreq, err := http.NewRequest(http.MethodPut, updatedUrl, strings.NewReader(content))
269293
if err != nil {
270294
t.Fatalf("cannot create HTTP PUT request: %q", err)
271295
}
296+
// Add Host header
297+
httpreq.Host = u.Host
272298
httpresp, err := client.Do(httpreq)
273299
if err != nil {
274300
t.Fatalf("HTTP PUT request failed: %q", err)
@@ -282,14 +308,27 @@ func uploadBlob(t *testing.T, url string, content string) {
282308
}
283309
}
284310

285-
func downloadBlob(t *testing.T, url string) string {
286-
httpresp, err := http.Get(url)
311+
func downloadBlob(t *testing.T, originalUrl, updatedUrl string) string {
312+
// Always use original URL to extract the host information.
313+
// This will avoid any Signature mismatch errors
314+
u, err := url.Parse(originalUrl)
315+
if err != nil {
316+
t.Fatal(err)
317+
}
318+
var client = &http.Client{Timeout: time.Second * 10}
319+
httpreq, err := http.NewRequest(http.MethodGet, updatedUrl, nil)
287320
if err != nil {
288-
t.Fatalf("HTTP GET requst failed: %q", err)
321+
t.Fatalf("cannot create HTTP GET request: %q", err)
322+
}
323+
// Add Host header
324+
httpreq.Host = u.Host
325+
httpresp, err := client.Do(httpreq)
326+
if err != nil {
327+
t.Fatalf("HTTP GET request failed: %q", err)
289328
}
290329
body, err := io.ReadAll(httpresp.Body)
291330
if err != nil {
292-
t.Fatalf("cannot read response body of HTTP PUT: %q", err)
331+
t.Fatalf("cannot read response body of HTTP GET: %q", err)
293332
}
294333
return string(body)
295334
}

0 commit comments

Comments
 (0)