Skip to content

Commit 7c7bdfb

Browse files
committed
transfer uploader tests for relativeociref
1 parent 94fae36 commit 7c7bdfb

File tree

5 files changed

+320
-3
lines changed

5 files changed

+320
-3
lines changed

api/oci/utils.go

+5-1
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,15 @@ func AsTags(tag string) []string {
1818
}
1919

2020
func StandardOCIRef(host, repository, version string) string {
21+
return fmt.Sprintf("%s%s%s", host, grammar.RepositorySeparator, RelativeOCIRef(repository, version))
22+
}
23+
24+
func RelativeOCIRef(repository, version string) string {
2125
sep := grammar.TagSeparator
2226
if ok, _ := artdesc.IsDigest(version); ok {
2327
sep = grammar.DigestSeparator
2428
}
25-
return fmt.Sprintf("%s%s%s%s%s", host, grammar.RepositorySeparator, repository, sep, version)
29+
return fmt.Sprintf("%s%s%s", repository, sep, version)
2630
}
2731

2832
func IsIntermediate(spec RepositorySpec) bool {

api/ocm/extensions/accessmethods/ociartifact/method.go

+9-1
Original file line numberDiff line numberDiff line change
@@ -78,11 +78,19 @@ func (a *AccessSpec) Describe(ctx accspeccpi.Context) string {
7878
func (a *AccessSpec) Info(ctx accspeccpi.Context) *accspeccpi.UniformAccessSpecInfo {
7979
ref, _ := oci.ParseRef(a.ImageReference)
8080
host, port := ref.HostPort()
81+
82+
r := ref.Repository
83+
if ref.Tag != nil {
84+
r += ":" + *ref.Tag
85+
}
86+
if ref.Digest != nil {
87+
r += "@" + ref.Digest.String()
88+
}
8189
return &accspeccpi.UniformAccessSpecInfo{
8290
Kind: Type,
8391
Host: host,
8492
Port: port,
85-
Info: ref.Version(),
93+
Info: r,
8694
}
8795
}
8896

api/ocm/tools/transfer/options.go

+3
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@ type localOptions struct {
4141

4242
func (opts *localOptions) Eval(optlist ...transferhandler.TransferOption) error {
4343
for _, o := range optlist {
44+
if o == nil {
45+
continue
46+
}
4447
if _, ok := o.(transferhandler.TransferOptionsCreator); !ok {
4548
err := o.ApplyTransferOption(opts)
4649
if err != nil {

api/ocm/tools/transfer/transfer.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@ func copyVersion(printer common.Printer, log logging.Logger, hist common.History
255255
hint := ocmcpi.ArtifactNameHint(a, src)
256256
old, err = cur.GetResourceByIdentity(r.Meta().GetIdentity(srccd.Resources))
257257

258-
changed := err != nil || old.Digest == nil || !old.Digest.Equal(r.Meta().Digest)
258+
changed := err != nil || old.Digest == nil || r.Meta().Digest == nil || !old.Digest.Equal(r.Meta().Digest)
259259
valueNeeded := err == nil && needsTransport(src.GetContext(), r, &old)
260260
if changed || valueNeeded {
261261
var msgs []interface{}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,302 @@
1+
package standard_test
2+
3+
import (
4+
. "github.com/mandelsoft/goutils/testutils"
5+
. "github.com/onsi/ginkgo/v2"
6+
. "github.com/onsi/gomega"
7+
. "ocm.software/ocm/api/helper/builder"
8+
"ocm.software/ocm/api/oci"
9+
"ocm.software/ocm/api/oci/artdesc"
10+
"ocm.software/ocm/api/oci/extensions/repositories/artifactset"
11+
ocictf "ocm.software/ocm/api/oci/extensions/repositories/ctf"
12+
. "ocm.software/ocm/api/oci/testhelper"
13+
"ocm.software/ocm/api/ocm"
14+
metav1 "ocm.software/ocm/api/ocm/compdesc/meta/v1"
15+
"ocm.software/ocm/api/ocm/extensions/accessmethods/localblob"
16+
"ocm.software/ocm/api/ocm/extensions/accessmethods/ociartifact"
17+
"ocm.software/ocm/api/ocm/extensions/accessmethods/relativeociref"
18+
resourcetypes "ocm.software/ocm/api/ocm/extensions/artifacttypes"
19+
"ocm.software/ocm/api/ocm/extensions/attrs/keepblobattr"
20+
"ocm.software/ocm/api/ocm/extensions/blobhandler"
21+
storagecontext "ocm.software/ocm/api/ocm/extensions/blobhandler/handlers/oci"
22+
"ocm.software/ocm/api/ocm/extensions/blobhandler/handlers/oci/ocirepo"
23+
"ocm.software/ocm/api/ocm/extensions/repositories/ctf"
24+
"ocm.software/ocm/api/ocm/tools/transfer"
25+
"ocm.software/ocm/api/ocm/tools/transfer/transferhandler"
26+
"ocm.software/ocm/api/ocm/tools/transfer/transferhandler/standard"
27+
"ocm.software/ocm/api/utils"
28+
"ocm.software/ocm/api/utils/accessio"
29+
"ocm.software/ocm/api/utils/accessobj"
30+
common "ocm.software/ocm/api/utils/misc"
31+
)
32+
33+
const OCIHOST2 = "target"
34+
35+
var _ = Describe("value transport with relative ocireg", func() {
36+
var env *Builder
37+
38+
BeforeEach(func() {
39+
env = NewBuilder()
40+
41+
env.RSAKeyPair(SIGNATURE)
42+
43+
env.OCICommonTransport(OCIPATH, accessio.FormatDirectory, func() {
44+
OCIManifest1(env)
45+
})
46+
47+
FakeOCIRepo(env, OCIPATH, OCIHOST)
48+
FakeOCIRepo(env, ARCH, OCIHOST2)
49+
50+
env.OCMCommonTransport(OCIPATH, accessio.FormatDirectory, func() {
51+
env.Component(COMPONENT, func() {
52+
env.Version(VERSION, func() {
53+
env.Provider(PROVIDER)
54+
env.Resource("artifact", "", resourcetypes.OCI_IMAGE, metav1.LocalRelation, func() {
55+
env.Access(
56+
relativeociref.New(oci.RelativeOCIRef(OCINAMESPACE, OCIVERSION)),
57+
)
58+
})
59+
})
60+
})
61+
})
62+
})
63+
64+
AfterEach(func() {
65+
env.Cleanup()
66+
})
67+
68+
It("it should use additional resolver to resolve component ref", func() {
69+
src := Must(ctf.Open(env.OCMContext(), accessobj.ACC_READONLY, OCIPATH, 0, env))
70+
defer Close(src, "src")
71+
72+
cv := Must(src.LookupComponentVersion(COMPONENT, VERSION))
73+
defer Close(cv, "cv")
74+
75+
r := Must(cv.GetResourceByIndex(0))
76+
CheckBlob(r, D_OCIMANIFEST1, 628)
77+
})
78+
79+
DescribeTable("transfers per value", func(keep bool, mod func(env *Builder), dig string, size int, opts ...transferhandler.TransferOption) {
80+
env.OCMContext().BlobHandlers().Register(ocirepo.NewArtifactHandler(FakeOCIRegBaseFunction),
81+
blobhandler.ForRepo(oci.CONTEXT_TYPE, ocictf.Type), blobhandler.ForMimeType(artdesc.ToContentMediaType(artdesc.MediaTypeImageManifest)))
82+
keepblobattr.Set(env.OCMContext(), keep)
83+
84+
p, buf := common.NewBufferedPrinter()
85+
topts := append([]transferhandler.TransferOption{
86+
standard.ResourcesByValue(), transfer.WithPrinter(p),
87+
}, opts...)
88+
89+
src := Must(ctf.Open(env.OCMContext(), accessobj.ACC_READONLY, OCIPATH, 0, env))
90+
defer Close(src, "src")
91+
92+
cv := Must(src.LookupComponentVersion(COMPONENT, VERSION))
93+
defer Close(cv, "cv")
94+
95+
mod(env)
96+
97+
tgt := Must(ctf.Open(env, accessobj.ACC_WRITABLE, ARCH, 0, env))
98+
ctgt := accessio.OnceCloser(tgt)
99+
defer Close(ctgt, "tgt")
100+
101+
MustBeSuccessful(transfer.Transfer(cv, tgt, topts...))
102+
103+
options := &standard.Options{}
104+
transferhandler.ApplyOptions(options, topts...)
105+
106+
out := `
107+
transferring version "github.com/mandelsoft/test:v1"...
108+
...resource 0 artifact\[ociImage\]\(ocm/value:v2.0\)...
109+
...adding component version...
110+
`
111+
if options.IsOverwrite() {
112+
out = `
113+
transferring version "github.com/mandelsoft/test:v1"...
114+
warning: version "github.com/mandelsoft/test:v1" already present, but differs because some artifact.*changed \(transport enforced by overwrite option\)
115+
...resource 0 artifact\[ociImage\]\(ocm/value:v2.0\).*
116+
...adding component version...
117+
`
118+
}
119+
Expect(string(buf.Bytes())).To(StringMatchTrimmedWithContext(utils.Crop(out, 2)))
120+
MustBeSuccessful(ctgt.Close())
121+
122+
tgt = Must(ctf.Open(env, accessobj.ACC_READONLY, ARCH, 0, env))
123+
ctgt = accessio.OnceCloser(tgt)
124+
defer Close(ctgt, "tgt2")
125+
126+
tcv := Must(tgt.LookupComponentVersion(COMPONENT, VERSION))
127+
ctcv := accessio.OnceCloser(tcv)
128+
defer Close(ctcv, "tcv")
129+
130+
r := Must(tcv.GetResourceByIndex(0))
131+
acc := Must(r.Access())
132+
133+
atype := ociartifact.Type
134+
if keep {
135+
atype = localblob.Type
136+
}
137+
Expect(acc.GetKind()).To(Equal(atype))
138+
139+
info := acc.Info(env.OCMContext())
140+
if keep {
141+
Expect(info.Info).To(Equal("sha256:" + H_OCIARCHMANIFEST1))
142+
143+
} else {
144+
Expect(info.Host).To(Equal(OCIHOST2 + ".alias"))
145+
Expect(info.Info).To(Equal("ocm/value:v2.0"))
146+
}
147+
148+
CheckBlob(r, dig, size)
149+
150+
MustBeSuccessful(ctcv.Close())
151+
MustBeSuccessful(ctgt.Close())
152+
153+
CheckAritifact(env, dig, size)
154+
155+
// re-transport
156+
buf.Reset()
157+
tgt = Must(ctf.Open(env, accessobj.ACC_WRITABLE, ARCH, 0, env))
158+
ctgt = accessio.OnceCloser(tgt)
159+
defer Close(ctgt, "tgt3")
160+
161+
MustBeSuccessful(transfer.Transfer(cv, tgt, topts...))
162+
163+
tcv = Must(tgt.LookupComponentVersion(COMPONENT, VERSION))
164+
ctcv = accessio.OnceCloser(tcv)
165+
defer Close(ctcv, "ctcv")
166+
167+
r = Must(tcv.GetResourceByIndex(0))
168+
acc = Must(r.Access())
169+
Expect(acc.GetKind()).To(Equal(atype))
170+
171+
info = acc.Info(env.OCMContext())
172+
if keep {
173+
Expect(info.Info).To(Equal("sha256:" + H_OCIARCHMANIFEST1))
174+
175+
} else {
176+
Expect(info.Info).To(Equal("ocm/value:v2.0"))
177+
}
178+
179+
MustBeSuccessful(ctcv.Close())
180+
MustBeSuccessful(ctgt.Close())
181+
182+
CheckAritifact(env, dig, size)
183+
184+
},
185+
Entry("empty target", false, EmptyTarget, D_OCIMANIFEST1, 628),
186+
Entry("identical target", false, IdenticalTarget, D_OCIMANIFEST1, 628),
187+
Entry("different target", false, DifferentTarget, D_OCIMANIFEST1, 628),
188+
Entry("different CV", false, DifferentCV, D_OCIMANIFEST1, 628, standard.Overwrite()),
189+
Entry("different namespace", false, DifferentNamespace, D_OCIMANIFEST1, 628, standard.Overwrite()),
190+
Entry("different name", false, DifferentName, D_OCIMANIFEST1, 628, standard.Overwrite()),
191+
Entry("keep, empty target", true, EmptyTarget, D_OCIMANIFEST1, 628),
192+
193+
Entry("keep, identical target", true, IdenticalTarget, D_OCIMANIFEST1, 628),
194+
Entry("keep, different target", true, DifferentTarget, D_OCIMANIFEST1, 628),
195+
Entry("keep, different CV", true, DifferentCV, D_OCIMANIFEST1, 628, standard.Overwrite()),
196+
Entry("keep, different namespace", true, DifferentNamespace, D_OCIMANIFEST1, 628, standard.Overwrite()),
197+
Entry("keep, different name", true, DifferentName, D_OCIMANIFEST1, 628, standard.Overwrite()),
198+
)
199+
})
200+
201+
func EmptyTarget(env *Builder) {
202+
env.OCMCommonTransport(ARCH, accessio.FormatDirectory)
203+
}
204+
205+
func IdenticalTarget(env *Builder) {
206+
env.OCMCommonTransport(ARCH, accessio.FormatDirectory, func() {
207+
OCIManifest1For(env, OCINAMESPACE, OCIVERSION)
208+
})
209+
}
210+
211+
func DifferentTarget(env *Builder) {
212+
env.OCMCommonTransport(ARCH, accessio.FormatDirectory, func() {
213+
OCIManifest2For(env, OCINAMESPACE, OCIVERSION)
214+
})
215+
}
216+
217+
func DifferentCV(env *Builder) {
218+
env.OCICommonTransport(ARCH, accessio.FormatDirectory, func() {
219+
OCIManifest2For(env, OCINAMESPACE, OCIVERSION)
220+
})
221+
env.OCMCommonTransport(ARCH, accessio.FormatDirectory, func() {
222+
env.Component(COMPONENT, func() {
223+
env.Version(VERSION, func() {
224+
env.Provider(PROVIDER)
225+
env.Resource("artifact", "", resourcetypes.OCI_IMAGE, metav1.LocalRelation, func() {
226+
env.Access(
227+
ociartifact.New(oci.StandardOCIRef(OCIHOST2+".alias", OCINAMESPACE, OCIVERSION)),
228+
)
229+
})
230+
})
231+
})
232+
})
233+
}
234+
235+
func DifferentNamespace(env *Builder) {
236+
env.OCICommonTransport(ARCH, accessio.FormatDirectory, func() {
237+
OCIManifest2For(env, OCINAMESPACE2, OCIVERSION)
238+
})
239+
env.OCMCommonTransport(ARCH, accessio.FormatDirectory, func() {
240+
env.Component(COMPONENT, func() {
241+
env.Version(VERSION, func() {
242+
env.Provider(PROVIDER)
243+
env.Resource("artifact", "", resourcetypes.OCI_IMAGE, metav1.LocalRelation, func() {
244+
env.Access(
245+
relativeociref.New(oci.RelativeOCIRef(OCINAMESPACE2, OCIVERSION)),
246+
)
247+
})
248+
})
249+
})
250+
})
251+
}
252+
253+
func DifferentName(env *Builder) {
254+
env.OCICommonTransport(ARCH, accessio.FormatDirectory, func() {
255+
OCIManifest1For(env, OCINAMESPACE, OCIVERSION)
256+
})
257+
env.OCMCommonTransport(ARCH, accessio.FormatDirectory, func() {
258+
env.Component(COMPONENT, func() {
259+
env.Version(VERSION, func() {
260+
env.Provider(PROVIDER)
261+
env.Resource("other", "", resourcetypes.OCI_IMAGE, metav1.LocalRelation, func() {
262+
env.Access(
263+
ociartifact.New(oci.StandardOCIRef(OCIHOST2+".alias", OCINAMESPACE, OCIVERSION)),
264+
)
265+
})
266+
})
267+
})
268+
})
269+
}
270+
271+
func FakeOCIRegBaseFunction(ctx *storagecontext.StorageContext) string {
272+
return OCIHOST2 + ".alias"
273+
}
274+
275+
func CheckBlob(r ocm.ResourceAccess, dig string, size int) {
276+
blob := Must(r.BlobAccess())
277+
defer Close(blob, "blob")
278+
279+
ExpectWithOffset(1, int(blob.Size())).To(Equal(size))
280+
set := Must(artifactset.OpenFromBlob(accessobj.ACC_READONLY, blob))
281+
defer Close(set, "set")
282+
283+
digest := set.GetMain()
284+
ExpectWithOffset(1, digest.Hex()).To(Equal(dig))
285+
286+
acc := Must(set.GetArtifact(digest.String()))
287+
defer Close(acc, "acc")
288+
289+
ExpectWithOffset(1, acc.IsManifest()).To(BeTrue())
290+
ExpectWithOffset(1, acc.Digest().Hex()).To(Equal(dig))
291+
}
292+
293+
func CheckAritifact(env *Builder, dig string, size int) {
294+
repo := Must(ocictf.Open(env, accessobj.ACC_READONLY, ARCH, 0, env))
295+
defer Close(repo, "oci repo")
296+
297+
art := Must(repo.LookupArtifact(OCINAMESPACE, OCIVERSION))
298+
defer Close(art, "art")
299+
300+
ExpectWithOffset(1, art.IsManifest()).To(BeTrue())
301+
ExpectWithOffset(1, art.Digest().Hex()).To(Equal(dig))
302+
}

0 commit comments

Comments
 (0)