1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
|
# Copyright 2013-2024 Lawrence Livermore National Security, LLC and other
# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
import re
import pytest
import spack.spec
from spack.oci.image import Digest, ImageReference, default_tag, tag
@pytest.mark.parametrize(
"image_ref, expected",
[
(
f"example.com:1234/a/b/c:tag@sha256:{'a'*64}",
("example.com:1234", "a/b/c", "tag", Digest.from_sha256("a" * 64)),
),
("example.com:1234/a/b/c:tag", ("example.com:1234", "a/b/c", "tag", None)),
("example.com:1234/a/b/c", ("example.com:1234", "a/b/c", "latest", None)),
(
f"example.com:1234/a/b/c@sha256:{'a'*64}",
("example.com:1234", "a/b/c", "latest", Digest.from_sha256("a" * 64)),
),
# ipv4
("1.2.3.4:1234/a/b/c:tag", ("1.2.3.4:1234", "a/b/c", "tag", None)),
# ipv6
("[2001:db8::1]:1234/a/b/c:tag", ("[2001:db8::1]:1234", "a/b/c", "tag", None)),
# Follow docker rules for parsing
("ubuntu:22.04", ("index.docker.io", "library/ubuntu", "22.04", None)),
("myname/myimage:abc", ("index.docker.io", "myname/myimage", "abc", None)),
("myname:1234/myimage:abc", ("myname:1234", "myimage", "abc", None)),
("localhost/myimage:abc", ("localhost", "myimage", "abc", None)),
("localhost:1234/myimage:abc", ("localhost:1234", "myimage", "abc", None)),
(
"example.com/UPPERCASE/lowercase:AbC",
("example.com", "uppercase/lowercase", "AbC", None),
),
],
)
def test_name_parsing(image_ref, expected):
x = ImageReference.from_string(image_ref)
assert (x.domain, x.name, x.tag, x.digest) == expected
@pytest.mark.parametrize(
"image_ref",
[
# wrong order of tag and sha
f"example.com:1234/a/b/c@sha256:{'a'*64}:tag",
# double tag
"example.com:1234/a/b/c:tag:tag",
# empty tag
"example.com:1234/a/b/c:",
# empty digest
"example.com:1234/a/b/c@sha256:",
# unsupport digest algorithm
f"example.com:1234/a/b/c@sha512:{'a'*128}",
# invalid digest length
f"example.com:1234/a/b/c@sha256:{'a'*63}",
# whitespace
"example.com:1234/a/b/c :tag",
"example.com:1234/a/b/c: tag",
"example.com:1234/a/b/c:tag ",
" example.com:1234/a/b/c:tag",
# broken ipv4
"1.2..3:1234/a/b/c:tag",
],
)
def test_parsing_failure(image_ref):
with pytest.raises(ValueError):
ImageReference.from_string(image_ref)
def test_digest():
valid_digest = "1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"
# Test string roundtrip
assert str(Digest.from_string(f"sha256:{valid_digest}")) == f"sha256:{valid_digest}"
# Invalid digest length
with pytest.raises(ValueError):
Digest.from_string("sha256:abcdef")
# Missing algorithm
with pytest.raises(ValueError):
Digest.from_string(valid_digest)
@pytest.mark.parametrize(
"spec",
[
# Standard case
"short-name@=1.2.3",
# Unsupported characters in git version
f"git-version@{1:040x}=develop",
# Too long of a name
f"{'too-long':x<256}@=1.2.3",
],
)
def test_default_tag(spec: str):
"""Make sure that computed image tags are valid."""
assert re.fullmatch(tag, default_tag(spack.spec.Spec(spec)))
|