Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
gitpod-io
GitHub Repository: gitpod-io/gitpod
Path: blob/main/components/content-service/pkg/layer/provider_test.go
2500 views
1
// Copyright (c) 2020 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 layer
6
7
import (
8
"bytes"
9
"context"
10
"encoding/json"
11
"errors"
12
"flag"
13
"fmt"
14
"io"
15
"io/fs"
16
"net/http"
17
"os"
18
"strings"
19
"testing"
20
21
"github.com/google/go-cmp/cmp"
22
"github.com/opencontainers/go-digest"
23
24
csapi "github.com/gitpod-io/gitpod/content-service/api"
25
"github.com/gitpod-io/gitpod/content-service/pkg/storage"
26
)
27
28
const (
29
ownerID = "workspace-owner"
30
workspaceID = "workspace-id"
31
)
32
33
var (
34
update = flag.Bool("update", false, "update .golden files")
35
force = flag.Bool("force", false, "overwrite .golden files even if they already exist")
36
)
37
38
func TestGetContentLayer(t *testing.T) {
39
tests := []struct {
40
Name string
41
ContentManifestType string
42
ContentManifest *csapi.WorkspaceContentManifest
43
Backup *storage.DownloadInfo
44
Initializer *csapi.WorkspaceInitializer
45
}{
46
{
47
Name: "git initializer",
48
Initializer: &csapi.WorkspaceInitializer{
49
Spec: &csapi.WorkspaceInitializer_Git{
50
Git: &csapi.GitInitializer{
51
CheckoutLocation: "/foo",
52
CloneTaget: "head",
53
Config: &csapi.GitConfig{
54
Authentication: csapi.GitAuthMethod_NO_AUTH,
55
},
56
RemoteUri: "somewhere-else",
57
TargetMode: csapi.CloneTargetMode_LOCAL_BRANCH,
58
},
59
},
60
},
61
},
62
{
63
Name: "legacy backup",
64
Backup: &storage.DownloadInfo{
65
URL: "https://somewhere-else.com/backup.tar",
66
},
67
},
68
}
69
70
for _, test := range tests {
71
t.Run(test.Name, func(t *testing.T) {
72
var (
73
mf []byte
74
err error
75
objs = make(map[string]*storage.DownloadInfo)
76
)
77
if test.ContentManifest != nil {
78
mf, err = json.Marshal(test.ContentManifest)
79
if err != nil {
80
t.Fatal(err)
81
return
82
}
83
84
objs[fmt.Sprintf(fmtWorkspaceManifest, workspaceID)] = &storage.DownloadInfo{
85
Meta: storage.ObjectMeta{
86
ContentType: test.ContentManifestType,
87
Digest: digest.FromBytes(mf).String(),
88
},
89
Size: int64(len(mf)),
90
URL: "http://content-manifest",
91
}
92
93
for _, l := range test.ContentManifest.Layers {
94
objs[l.Object] = &storage.DownloadInfo{
95
Meta: storage.ObjectMeta{
96
Digest: l.Digest.String(),
97
},
98
URL: fmt.Sprintf("http://some-storage-system/%s/%s", l.Bucket, l.Object),
99
}
100
}
101
}
102
if test.Backup != nil {
103
objs[fmt.Sprintf(fmtLegacyBackupName, workspaceID)] = test.Backup
104
}
105
106
s := &testStorage{Objs: objs}
107
p := &Provider{
108
Storage: s,
109
Client: &http.Client{
110
Transport: roundTripFunc(func(req *http.Request) *http.Response {
111
switch req.URL.String() {
112
case "http://content-manifest":
113
return &http.Response{
114
StatusCode: http.StatusOK,
115
Header: make(http.Header),
116
Body: io.NopCloser(bytes.NewReader(mf)),
117
}
118
default:
119
return &http.Response{
120
StatusCode: http.StatusNotFound,
121
Header: make(http.Header),
122
}
123
}
124
}),
125
},
126
}
127
l, m, rerr := p.GetContentLayer(context.Background(), ownerID, workspaceID, test.Initializer)
128
129
type fixture struct {
130
Layer []Layer `json:"layer,omitempty"`
131
Manifest *csapi.WorkspaceContentManifest `json:"contentManifest,omitempty"`
132
Error string `json:"error,omitempty"`
133
}
134
135
var got fixture
136
if rerr != nil {
137
got.Error = rerr.Error()
138
}
139
got.Layer = l
140
got.Manifest = m
141
142
var (
143
want fixture
144
fixfn = fmt.Sprintf("fixtures/%s.json", strings.ToLower(strings.ReplaceAll(test.Name, " ", "_")))
145
)
146
if *update {
147
want = got
148
fixc, err := json.MarshalIndent(want, "", " ")
149
if err != nil {
150
t.Fatalf("cannot marshal fixture: %q", err)
151
return
152
}
153
154
if _, err := os.Stat(fixfn); err == nil && !*force {
155
t.Fatalf("fixture %s exists already - not overwriting", fixfn)
156
}
157
158
err = os.WriteFile(fixfn, fixc, 0600)
159
if err != nil {
160
t.Fatalf("cannot write fixture: %q", err)
161
return
162
}
163
} else {
164
fixc, err := os.ReadFile(fixfn)
165
if errors.Is(err, fs.ErrNotExist) && !*update {
166
t.Fatalf("no fixture %s. Run test with -update", fixfn)
167
return
168
}
169
if err != nil {
170
t.Fatalf("cannot load fixture: %q", err)
171
}
172
173
err = json.Unmarshal(fixc, &want)
174
if err != nil {
175
t.Fatalf("cannot unmarshal fixture: %q", err)
176
return
177
}
178
}
179
180
if diff := cmp.Diff(want, got); diff != "" {
181
t.Errorf("Fixture mismatch (-want +got):\n%s", diff)
182
}
183
})
184
}
185
}
186
187
type testStorage struct {
188
Objs map[string]*storage.DownloadInfo
189
}
190
191
// Bucket provides the bucket name for a particular user
192
func (*testStorage) Bucket(userID string) string {
193
return "bucket-" + userID
194
}
195
196
func (*testStorage) BlobObject(userID, name string) (string, error) {
197
return "blobs/" + name, nil
198
}
199
200
func (s *testStorage) EnsureExists(ctx context.Context, bucket string) (err error) {
201
return nil
202
}
203
204
func (s *testStorage) DiskUsage(ctx context.Context, bucket string, prefix string) (size int64, err error) {
205
return 0, nil
206
}
207
208
func (s *testStorage) SignDownload(ctx context.Context, bucket, obj string, options *storage.SignedURLOptions) (info *storage.DownloadInfo, err error) {
209
info, ok := s.Objs[obj]
210
if !ok || info == nil {
211
return nil, storage.ErrNotFound
212
}
213
return info, nil
214
}
215
216
func (s *testStorage) SignUpload(ctx context.Context, bucket, obj string, options *storage.SignedURLOptions) (info *storage.UploadInfo, err error) {
217
return nil, nil
218
}
219
220
func (s *testStorage) DeleteObject(ctx context.Context, bucket string, query *storage.DeleteObjectQuery) error {
221
return nil
222
}
223
224
func (s *testStorage) DeleteBucket(ctx context.Context, userID, bucket string) error {
225
return nil
226
}
227
228
func (*testStorage) BackupObject(ownerID string, workspaceID string, name string) string {
229
return ""
230
}
231
232
func (*testStorage) InstanceObject(ownerID string, workspaceID string, instanceID string, name string) string {
233
return ""
234
}
235
236
func (*testStorage) ObjectHash(ctx context.Context, bucket string, obj string) (string, error) {
237
return "", nil
238
}
239
240
func (*testStorage) ObjectExists(ctx context.Context, bucket string, path string) (bool, error) {
241
return false, nil
242
}
243
244
type roundTripFunc func(req *http.Request) *http.Response
245
246
// RoundTrip .
247
func (f roundTripFunc) RoundTrip(req *http.Request) (*http.Response, error) {
248
return f(req), nil
249
}
250
251