Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
gitpod-io
GitHub Repository: gitpod-io/gitpod
Path: blob/main/test/tests/components/content-service/content-service_test.go
2499 views
1
// Copyright (c) 2021 Gitpod GmbH. All rights reserved.
2
// Licensed under the GNU Affero General Public License (AGPL).
3
// See License.AGPL.txt in the project root for license information.
4
5
package contentservice
6
7
import (
8
"context"
9
"fmt"
10
"io"
11
"net/http"
12
"net/url"
13
"strings"
14
"testing"
15
"time"
16
17
"google.golang.org/grpc/codes"
18
"google.golang.org/grpc/status"
19
"sigs.k8s.io/e2e-framework/pkg/envconf"
20
"sigs.k8s.io/e2e-framework/pkg/features"
21
22
content_service_api "github.com/gitpod-io/gitpod/content-service/api"
23
"github.com/gitpod-io/gitpod/test/pkg/integration"
24
)
25
26
var (
27
gitpodBuiltinUserID = "00000000-0000-0000-0000-000000000000"
28
)
29
30
func hasErrorCode(err error, code codes.Code) bool {
31
st, ok := status.FromError(err)
32
return ok && st.Code() == code
33
}
34
35
func TestUploadUrl(t *testing.T) {
36
tests := []struct {
37
Name string
38
InputOwnerID string
39
InputName string
40
ExpectedErrorCode codes.Code
41
}{
42
{
43
Name: "simple name",
44
InputOwnerID: gitpodBuiltinUserID,
45
InputName: "test-blob",
46
},
47
{
48
Name: "new user",
49
InputOwnerID: "new-user",
50
InputName: "test-blob",
51
},
52
{
53
Name: "name with whitespace",
54
InputOwnerID: gitpodBuiltinUserID,
55
InputName: "whitespaces are not allowed",
56
ExpectedErrorCode: codes.InvalidArgument,
57
},
58
{
59
Name: "name with invalid char",
60
InputOwnerID: gitpodBuiltinUserID,
61
InputName: "รค-is-not-allowed",
62
ExpectedErrorCode: codes.InvalidArgument,
63
},
64
}
65
66
f := features.New("UploadUrlRequest").
67
WithLabel("component", "content-service").
68
Assess("it should run content-service tests", func(testCtx context.Context, t *testing.T, cfg *envconf.Config) context.Context {
69
t.Parallel()
70
71
ctx, cancel := context.WithTimeout(testCtx, 5*time.Minute)
72
defer cancel()
73
74
api := integration.NewComponentAPI(ctx, cfg.Namespace(), kubeconfig, cfg.Client())
75
t.Cleanup(func() {
76
api.Done(t)
77
})
78
79
bs, err := api.BlobService()
80
if err != nil {
81
t.Fatal(err)
82
}
83
84
for _, test := range tests {
85
t.Run(test.Name, func(t *testing.T) {
86
resp, err := bs.UploadUrl(ctx, &content_service_api.UploadUrlRequest{OwnerId: test.InputOwnerID, Name: test.InputName})
87
if err != nil && test.ExpectedErrorCode == codes.OK {
88
t.Fatal(err)
89
}
90
if err == nil && test.ExpectedErrorCode != codes.OK {
91
t.Fatalf("expected error with error code '%v' but got no error at all", test.ExpectedErrorCode)
92
}
93
if !hasErrorCode(err, test.ExpectedErrorCode) {
94
t.Fatalf("expected error with error code '%v' but got error %v", test.ExpectedErrorCode, err)
95
}
96
if err != nil && test.ExpectedErrorCode == codes.OK {
97
url := resp.Url
98
if url == "" {
99
t.Fatal("upload url is empty")
100
}
101
t.Logf("Got URL repsonse: %s", url)
102
}
103
})
104
}
105
106
return testCtx
107
}).
108
Feature()
109
110
testEnv.Test(t, f)
111
}
112
113
func TestDownloadUrl(t *testing.T) {
114
tests := []struct {
115
Name string
116
InputOwnerID string
117
InputName string
118
ExpectedErrorCode codes.Code
119
}{
120
{
121
Name: "not existing download",
122
InputOwnerID: gitpodBuiltinUserID,
123
InputName: "this-does-not-exist",
124
ExpectedErrorCode: codes.NotFound,
125
},
126
}
127
128
f := features.New("DownloadUrl").
129
WithLabel("component", "server").
130
Assess("it should pass download URL tests", func(testCtx context.Context, t *testing.T, cfg *envconf.Config) context.Context {
131
t.Parallel()
132
133
ctx, cancel := context.WithTimeout(testCtx, 5*time.Minute)
134
defer cancel()
135
136
api := integration.NewComponentAPI(ctx, cfg.Namespace(), kubeconfig, cfg.Client())
137
t.Cleanup(func() {
138
api.Done(t)
139
})
140
141
bs, err := api.BlobService()
142
if err != nil {
143
t.Fatal(err)
144
}
145
146
for _, test := range tests {
147
t.Run(test.Name, func(t *testing.T) {
148
resp, err := bs.DownloadUrl(ctx, &content_service_api.DownloadUrlRequest{OwnerId: test.InputOwnerID, Name: test.InputName})
149
if err != nil && test.ExpectedErrorCode == codes.OK {
150
t.Fatal(err)
151
}
152
if err == nil && test.ExpectedErrorCode != codes.OK {
153
t.Fatalf("expected error with error code '%v' but got no error at all", test.ExpectedErrorCode)
154
}
155
if !hasErrorCode(err, test.ExpectedErrorCode) {
156
t.Fatalf("expected error with error code '%v' but got error %v", test.ExpectedErrorCode, err)
157
}
158
if err != nil && test.ExpectedErrorCode == codes.OK {
159
url := resp.Url
160
if url == "" {
161
t.Fatal("download url is empty")
162
}
163
t.Logf("Got URL repsonse: %s", url)
164
}
165
})
166
}
167
168
return testCtx
169
}).
170
Feature()
171
172
testEnv.Test(t, f)
173
}
174
175
func TestUploadDownloadBlob(t *testing.T) {
176
f := features.New("UploadDownloadBlob").
177
WithLabel("component", "server").
178
Assess("it should upload and download blob", func(testCtx context.Context, t *testing.T, cfg *envconf.Config) context.Context {
179
t.Parallel()
180
181
ctx, cancel := context.WithTimeout(testCtx, 5*time.Minute)
182
defer cancel()
183
184
api := integration.NewComponentAPI(ctx, cfg.Namespace(), kubeconfig, cfg.Client())
185
t.Cleanup(func() {
186
api.Done(t)
187
})
188
189
blobContent := fmt.Sprintf("Hello Blobs! It's %s!", time.Now())
190
191
bs, err := api.BlobService()
192
if err != nil {
193
t.Fatal(err)
194
}
195
196
resp, err := bs.UploadUrl(ctx, &content_service_api.UploadUrlRequest{OwnerId: gitpodBuiltinUserID, Name: "test-blob"})
197
if err != nil {
198
t.Fatal(err)
199
}
200
originalUrl := resp.Url
201
updatedUrl, err := api.Storage(originalUrl)
202
if err != nil {
203
t.Fatalf("error resolving blob upload target url: %q", err)
204
}
205
t.Logf("upload URL: %s", updatedUrl)
206
207
uploadBlob(t, originalUrl, updatedUrl, blobContent)
208
209
resp2, err := bs.DownloadUrl(ctx, &content_service_api.DownloadUrlRequest{OwnerId: gitpodBuiltinUserID, Name: "test-blob"})
210
if err != nil {
211
t.Fatal(err)
212
}
213
originalUrl = resp2.Url
214
updatedUrl, err = api.Storage(originalUrl)
215
if err != nil {
216
t.Fatalf("error resolving blob download target url: %q", err)
217
}
218
t.Logf("download URL: %s", updatedUrl)
219
220
body := downloadBlob(t, originalUrl, updatedUrl)
221
if string(body) != blobContent {
222
t.Fatalf("blob content mismatch: should '%s' but is '%s'", blobContent, body)
223
}
224
225
return testCtx
226
}).
227
Feature()
228
229
testEnv.Test(t, f)
230
}
231
232
func uploadBlob(t *testing.T, originalUrl, updatedUrl, content string) {
233
// Always use original URL to extract the host information.
234
// This will avoid any Signature mismatch errors
235
u, err := url.Parse(originalUrl)
236
if err != nil {
237
t.Fatal(err)
238
}
239
var client = &http.Client{Timeout: time.Second * 10}
240
httpreq, err := http.NewRequest(http.MethodPut, updatedUrl, strings.NewReader(content))
241
if err != nil {
242
t.Fatalf("cannot create HTTP PUT request: %q", err)
243
}
244
// Add Host header
245
httpreq.Host = u.Host
246
httpresp, err := client.Do(httpreq)
247
if err != nil {
248
t.Fatalf("HTTP PUT request failed: %q", err)
249
}
250
body, err := io.ReadAll(httpresp.Body)
251
if err != nil {
252
t.Fatalf("cannot read response body of HTTP PUT: %q", err)
253
}
254
if string(body) != "" {
255
t.Fatalf("unexpected response body of HTTP PUT: '%q'", body)
256
}
257
}
258
259
func downloadBlob(t *testing.T, originalUrl, updatedUrl string) string {
260
// Always use original URL to extract the host information.
261
// This will avoid any Signature mismatch errors
262
u, err := url.Parse(originalUrl)
263
if err != nil {
264
t.Fatal(err)
265
}
266
var client = &http.Client{Timeout: time.Second * 10}
267
httpreq, err := http.NewRequest(http.MethodGet, updatedUrl, nil)
268
if err != nil {
269
t.Fatalf("cannot create HTTP GET request: %q", err)
270
}
271
// Add Host header
272
httpreq.Host = u.Host
273
httpresp, err := client.Do(httpreq)
274
if err != nil {
275
t.Fatalf("HTTP GET request failed: %q", err)
276
}
277
body, err := io.ReadAll(httpresp.Body)
278
if err != nil {
279
t.Fatalf("cannot read response body of HTTP GET: %q", err)
280
}
281
return string(body)
282
}
283
284