Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
gitpod-io
GitHub Repository: gitpod-io/gitpod
Path: blob/main/components/registry-facade/pkg/registry/layersource_test.go
2499 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 registry
6
7
import (
8
"bytes"
9
"context"
10
"encoding/json"
11
"flag"
12
"io"
13
"os"
14
"testing"
15
"time"
16
17
ctesting "github.com/gitpod-io/gitpod/common-go/testing"
18
"golang.org/x/xerrors"
19
20
"github.com/containerd/containerd/remotes"
21
"github.com/containerd/containerd/remotes/docker"
22
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
23
)
24
25
type testStaticLayerSourceFixture struct {
26
SourceRef string `json:"sourceRef"`
27
Content map[string][]byte `json:"content"`
28
Envs []string `json:"envs"`
29
}
30
31
var fetchFixture = flag.String("fetch-fixture", "", "create a new fixture from an image ref")
32
33
func TestStaticLayerSource(t *testing.T) {
34
if *fetchFixture != "" {
35
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
36
defer cancel()
37
38
fix, err := createFixtureFromImage(ctx, docker.NewResolver(docker.ResolverOptions{}), *fetchFixture)
39
if err != nil {
40
t.Fatalf("cannot download ref: %+q", err)
41
}
42
43
out, err := json.MarshalIndent(fix, "", " ")
44
if err != nil {
45
t.Fatalf("cannot marshal fixture: %+q", err)
46
}
47
48
err = os.WriteFile("fixtures/layersrc_new.json", out, 0600)
49
if err != nil {
50
t.Fatalf("cannot write fixture: %+q", err)
51
}
52
53
t.Log("wrote fixture to fixtures/layersrc_new.json")
54
return
55
}
56
57
type gold struct {
58
Error string `json:"error"`
59
Layer []AddonLayer `json:"layer"`
60
Envs []string `json:"envs"`
61
}
62
test := ctesting.FixtureTest{
63
T: t,
64
Path: "fixtures/layersrc_*.json",
65
Test: func(t *testing.T, input interface{}) interface{} {
66
fixture := input.(*testStaticLayerSourceFixture)
67
68
src, err := NewStaticSourceFromImage(context.Background(), func() remotes.Resolver { return &fakeFetcher{Content: fixture.Content} }, fixture.SourceRef)
69
if err != nil {
70
return &gold{Error: err.Error()}
71
}
72
73
res := make([]AddonLayer, len(src.layers))
74
for i := range src.layers {
75
res[i] = src.layers[i].AddonLayer
76
}
77
envs := parseEnvs(fixture.Envs)
78
for _, e := range src.envs {
79
e(envs)
80
}
81
return &gold{Layer: res, Envs: envs.serialize()}
82
},
83
Fixture: func() interface{} { return &testStaticLayerSourceFixture{} },
84
Gold: func() interface{} { return &gold{} },
85
}
86
test.Run()
87
}
88
89
func createFixtureFromImage(ctx context.Context, resolver remotes.Resolver, ref string) (*testStaticLayerSourceFixture, error) {
90
fetcher, err := resolver.Fetcher(ctx, ref)
91
if err != nil {
92
return nil, err
93
}
94
95
content := make(map[string][]byte)
96
_, desc, err := resolver.Resolve(ctx, ref)
97
if err != nil {
98
return nil, err
99
}
100
content[ref], err = json.Marshal(desc)
101
if err != nil {
102
return nil, err
103
}
104
105
mf, _, err := DownloadManifest(ctx, AsFetcherFunc(fetcher), desc)
106
if err != nil {
107
return nil, err
108
}
109
content[desc.Digest.Encoded()], err = json.Marshal(mf)
110
if err != nil {
111
return nil, err
112
}
113
114
cfg, err := DownloadConfig(ctx, AsFetcherFunc(fetcher), ref, mf.Config)
115
if err != nil {
116
return nil, err
117
}
118
content[mf.Config.Digest.Encoded()], err = json.Marshal(cfg)
119
if err != nil {
120
return nil, err
121
}
122
123
return &testStaticLayerSourceFixture{
124
SourceRef: ref,
125
Content: content,
126
}, nil
127
}
128
129
type fakeFetcher struct {
130
Content map[string][]byte
131
}
132
133
func (f *fakeFetcher) Resolve(ctx context.Context, ref string) (name string, desc ocispec.Descriptor, err error) {
134
name = ref
135
c, ok := f.Content[ref]
136
if !ok {
137
err = xerrors.Errorf("not found")
138
return
139
}
140
141
err = json.Unmarshal(c, &desc)
142
return
143
}
144
145
// Pusher returns a new pusher for the provided reference
146
func (f *fakeFetcher) Pusher(ctx context.Context, ref string) (remotes.Pusher, error) {
147
return nil, xerrors.Errorf("not implemented")
148
}
149
150
// Fetcher returns a new fetcher for the provided reference.
151
// All content fetched from the returned fetcher will be
152
// from the namespace referred to by ref.
153
func (f *fakeFetcher) Fetcher(ctx context.Context, ref string) (remotes.Fetcher, error) {
154
return f, nil
155
}
156
157
func (f *fakeFetcher) Fetch(ctx context.Context, desc ocispec.Descriptor) (io.ReadCloser, error) {
158
c, ok := f.Content[desc.Digest.Encoded()]
159
if !ok {
160
return nil, xerrors.Errorf("not found")
161
}
162
return io.NopCloser(bytes.NewReader(c)), nil
163
}
164
165