Skip to content

Commit 4a5eb88

Browse files
clrprodjonjohnsonjr
authored andcommitted
transport: Fix ping code to wrap errors in a transport.Error (google#551)
* transport: Fix ping code to wrap errors in a transport.Error I added a high level test that the operation returns an error for a server which only returns one status code. I'll probably add a few more cases to help find other pathways that are swallowing the error and contained status code. * transport: Add error test for status.Teapot from the manifest * Add copyright header * Wire up a blob test for error code returning
1 parent 53e1ac5 commit 4a5eb88

File tree

2 files changed

+129
-1
lines changed

2 files changed

+129
-1
lines changed

pkg/v1/remote/error_roundtrip_test.go

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
// Copyright 2019 Google LLC All Rights Reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package remote_test
16+
17+
import (
18+
"fmt"
19+
"log"
20+
"net/http"
21+
"net/http/httptest"
22+
"strings"
23+
"testing"
24+
25+
"github.com/google/go-containerregistry/pkg/name"
26+
"github.com/google/go-containerregistry/pkg/registry"
27+
"github.com/google/go-containerregistry/pkg/v1/random"
28+
"github.com/google/go-containerregistry/pkg/v1/remote"
29+
"github.com/google/go-containerregistry/pkg/v1/remote/transport"
30+
)
31+
32+
func TestStatusCodeReturned(t *testing.T) {
33+
34+
tcs := []struct {
35+
Description string
36+
Handler http.Handler
37+
}{{
38+
Description: "Only returns teapot status",
39+
Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
40+
w.WriteHeader(http.StatusTeapot)
41+
}),
42+
}, {
43+
Description: "Handle v2, returns teapot status else",
44+
Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
45+
log.Print(r.URL.Path)
46+
if r.URL.Path == "/v2/" {
47+
return
48+
}
49+
w.WriteHeader(http.StatusTeapot)
50+
}),
51+
}}
52+
53+
for _, tc := range tcs {
54+
t.Run(tc.Description, func(t *testing.T) {
55+
o := httptest.NewServer(tc.Handler)
56+
defer o.Close()
57+
58+
ref, err := name.NewDigest(strings.TrimPrefix(o.URL+"/foo:@sha256:53b27244ffa2f585799adbfaf79fba5a5af104597751b289c8b235e7b8f7ebf5", "http://"))
59+
60+
if err != nil {
61+
t.Fatalf("Unable to parse digest: %v", err)
62+
}
63+
64+
_, err = remote.Image(ref)
65+
terr, ok := err.(*transport.Error)
66+
if !ok {
67+
t.Fatalf("Unable to cast error to transport error: %v", err)
68+
}
69+
if terr.StatusCode != http.StatusTeapot {
70+
t.Errorf("Incorrect status code received, got %v, wanted %v", terr.StatusCode, http.StatusTeapot)
71+
}
72+
})
73+
}
74+
}
75+
76+
func TestBlobStatusCodeReturned(t *testing.T) {
77+
reg := registry.New()
78+
rh := httptest.NewServer(reg)
79+
defer rh.Close()
80+
i, _ := random.Image(1024, 16)
81+
tag := strings.TrimPrefix(fmt.Sprintf("%s/foo:bar", rh.URL), "http://")
82+
d, _ := name.NewTag(tag)
83+
if err := remote.Write(d, i); err != nil {
84+
t.Fatalf("Unable to write empty image: %v", err)
85+
}
86+
87+
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
88+
log.Print(r.URL.Path)
89+
if strings.Contains(r.URL.Path, "blob") {
90+
w.WriteHeader(http.StatusTeapot)
91+
return
92+
}
93+
reg.ServeHTTP(w, r)
94+
})
95+
96+
o := httptest.NewServer(handler)
97+
defer o.Close()
98+
99+
ref, err := name.NewTag(strings.TrimPrefix(fmt.Sprintf("%s/foo:bar", o.URL), "http://"))
100+
if err != nil {
101+
t.Fatalf("Unable to parse digest: %v", err)
102+
}
103+
104+
ri, err := remote.Image(ref)
105+
if err != nil {
106+
t.Fatalf("Unable to fetch manifest: %v", err)
107+
}
108+
l, err := ri.Layers()
109+
if err != nil {
110+
t.Fatalf("Unable to fetch layers: %v", err)
111+
}
112+
_, err = l[0].Compressed()
113+
terr, ok := err.(*transport.Error)
114+
if !ok {
115+
t.Fatalf("Unable to cast error to transport error: %v", err)
116+
}
117+
if terr.StatusCode != http.StatusTeapot {
118+
t.Errorf("Incorrect status code received, got %v, wanted %v", terr.StatusCode, http.StatusTeapot)
119+
}
120+
_, err = l[0].Uncompressed()
121+
terr, ok = err.(*transport.Error)
122+
if !ok {
123+
t.Fatalf("Unable to cast error to transport error: %v", err)
124+
}
125+
if terr.StatusCode != http.StatusTeapot {
126+
t.Errorf("Incorrect status code received, got %v, wanted %v", terr.StatusCode, http.StatusTeapot)
127+
}
128+
}

pkg/v1/remote/transport/ping.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ func ping(reg name.Registry, t http.RoundTripper) (*pingResp, error) {
108108
scheme: scheme,
109109
}, nil
110110
default:
111-
return nil, fmt.Errorf("unrecognized HTTP status: %v", resp.Status)
111+
return nil, CheckError(resp, http.StatusOK, http.StatusUnauthorized)
112112
}
113113
}
114114
return nil, connErr

0 commit comments

Comments
 (0)