Skip to content

Commit 9ac302e

Browse files
committed
Update tag list conformance test to verify sort order
> If the list is not empty, the tags MUST be in lexical order (i.e. case-insensitive alphanumeric order). This update explicitly allows either lexical *or* "asciibetical", as many existing registries have already implemented this requirement via `sort.Strings`. This also adds uppercase versions of the `testN` tags to help test "case-insensitive alphanumeric order" (the edge cases that matter for sorted order). Signed-off-by: Tianon Gravi <admwiggin@gmail.com>
1 parent 583e014 commit 9ac302e

File tree

1 file changed

+21
-12
lines changed

1 file changed

+21
-12
lines changed

conformance/03_discovery_test.go

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"fmt"
66
"net/http"
77
"os"
8+
"sort"
89
"strconv"
910
"strings"
1011

@@ -61,17 +62,18 @@ var test03ContentDiscovery = func() {
6162
SkipIfDisabled(contentDiscovery)
6263
RunOnlyIf(runContentDiscoverySetup)
6364
for i := 0; i < numTags; i++ {
64-
tag := fmt.Sprintf("test%d", i)
65-
tagList = append(tagList, tag)
66-
req := client.NewRequest(reggie.PUT, "/v2/<name>/manifests/<reference>",
67-
reggie.WithReference(tag)).
68-
SetHeader("Content-Type", "application/vnd.oci.image.manifest.v1+json").
69-
SetBody(manifests[2].Content)
70-
resp, err := client.Do(req)
71-
Expect(err).To(BeNil())
72-
Expect(resp.StatusCode()).To(SatisfyAll(
73-
BeNumerically(">=", 200),
74-
BeNumerically("<", 300)))
65+
for _, tag := range []string{"test" + strconv.Itoa(i), "TEST" + strconv.Itoa(i)} {
66+
tagList = append(tagList, tag)
67+
req := client.NewRequest(reggie.PUT, "/v2/<name>/manifests/<reference>",
68+
reggie.WithReference(tag)).
69+
SetHeader("Content-Type", "application/vnd.oci.image.manifest.v1+json").
70+
SetBody(manifests[2].Content)
71+
resp, err := client.Do(req)
72+
Expect(err).To(BeNil())
73+
Expect(resp.StatusCode()).To(SatisfyAll(
74+
BeNumerically(">=", 200),
75+
BeNumerically("<", 300)))
76+
}
7577
}
7678
req := client.NewRequest(reggie.GET, "/v2/<name>/tags/list")
7779
resp, err := client.Do(req)
@@ -253,14 +255,21 @@ var test03ContentDiscovery = func() {
253255
})
254256

255257
g.Context("Test content discovery endpoints (listing tags)", func() {
256-
g.Specify("GET request to list tags should yield 200 response", func() {
258+
g.Specify("GET request to list tags should yield 200 response and be in sorted order", func() {
257259
SkipIfDisabled(contentDiscovery)
258260
req := client.NewRequest(reggie.GET, "/v2/<name>/tags/list")
259261
resp, err := client.Do(req)
260262
Expect(err).To(BeNil())
261263
Expect(resp.StatusCode()).To(Equal(http.StatusOK))
262264
tagList = getTagList(resp)
263265
numTags = len(tagList)
266+
// If the list is not empty, the tags MUST be in lexical order (i.e. case-insensitive alphanumeric order).
267+
sortedTagListLexical := append([]string{}, tagList...)
268+
sort.SliceStable(sortedTagListLexical, func(i, j int) bool { return strings.ToLower(sortedTagListLexical[i]) < strings.ToLower(sortedTagListLexical[j]) })
269+
// Historically, registries have not been lexical, so allow `sort.Strings` to be valid too.
270+
sortedTagListAsciibetical := append([]string{}, tagList...)
271+
sort.Strings(sortedTagListAsciibetical)
272+
Expect(tagList).To(Or(Equal(sortedTagListLexical), Equal(sortedTagListAsciibetical)))
264273
})
265274

266275
g.Specify("GET number of tags should be limitable by `n` query parameter", func() {

0 commit comments

Comments
 (0)