2018-02-05 16:05:59 -05:00
|
|
|
package remotecontext // import "github.com/docker/docker/builder/remotecontext"
|
2015-04-04 10:54:43 -04:00
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
2016-05-01 06:58:39 -04:00
|
|
|
"io"
|
2015-04-04 10:54:43 -04:00
|
|
|
"io/ioutil"
|
2016-05-01 06:58:39 -04:00
|
|
|
"net/http"
|
|
|
|
"net/http/httptest"
|
|
|
|
"net/url"
|
2015-04-04 10:54:43 -04:00
|
|
|
"testing"
|
2016-05-01 06:58:39 -04:00
|
|
|
|
2017-03-20 18:22:29 -04:00
|
|
|
"github.com/docker/docker/builder"
|
2018-03-13 15:28:34 -04:00
|
|
|
"github.com/gotestyourself/gotestyourself/assert"
|
|
|
|
is "github.com/gotestyourself/gotestyourself/assert/cmp"
|
2017-11-08 13:06:57 -05:00
|
|
|
"github.com/gotestyourself/gotestyourself/fs"
|
2015-04-04 10:54:43 -04:00
|
|
|
)
|
|
|
|
|
|
|
|
var binaryContext = []byte{0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00} //xz magic
|
|
|
|
|
2015-09-06 13:26:40 -04:00
|
|
|
func TestSelectAcceptableMIME(t *testing.T) {
|
|
|
|
validMimeStrings := []string{
|
|
|
|
"application/x-bzip2",
|
|
|
|
"application/bzip2",
|
|
|
|
"application/gzip",
|
|
|
|
"application/x-gzip",
|
|
|
|
"application/x-xz",
|
|
|
|
"application/xz",
|
|
|
|
"application/tar",
|
|
|
|
"application/x-tar",
|
|
|
|
"application/octet-stream",
|
|
|
|
"text/plain",
|
|
|
|
}
|
|
|
|
|
|
|
|
invalidMimeStrings := []string{
|
|
|
|
"",
|
|
|
|
"application/octet",
|
|
|
|
"application/json",
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, m := range invalidMimeStrings {
|
|
|
|
if len(selectAcceptableMIME(m)) > 0 {
|
2015-11-25 04:30:13 -05:00
|
|
|
t.Fatalf("Should not have accepted %q", m)
|
2015-09-06 13:26:40 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, m := range validMimeStrings {
|
|
|
|
if str := selectAcceptableMIME(m); str == "" {
|
2015-11-25 04:30:13 -05:00
|
|
|
t.Fatalf("Should have accepted %q", m)
|
2015-09-06 13:26:40 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-04 10:54:43 -04:00
|
|
|
func TestInspectEmptyResponse(t *testing.T) {
|
|
|
|
ct := "application/octet-stream"
|
|
|
|
br := ioutil.NopCloser(bytes.NewReader([]byte("")))
|
|
|
|
contentType, bReader, err := inspectResponse(ct, br, 0)
|
|
|
|
if err == nil {
|
2017-02-21 03:53:29 -05:00
|
|
|
t.Fatal("Should have generated an error for an empty response")
|
2015-04-04 10:54:43 -04:00
|
|
|
}
|
|
|
|
if contentType != "application/octet-stream" {
|
|
|
|
t.Fatalf("Content type should be 'application/octet-stream' but is %q", contentType)
|
|
|
|
}
|
|
|
|
body, err := ioutil.ReadAll(bReader)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if len(body) != 0 {
|
|
|
|
t.Fatal("response body should remain empty")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestInspectResponseBinary(t *testing.T) {
|
|
|
|
ct := "application/octet-stream"
|
|
|
|
br := ioutil.NopCloser(bytes.NewReader(binaryContext))
|
2015-07-23 17:19:58 -04:00
|
|
|
contentType, bReader, err := inspectResponse(ct, br, int64(len(binaryContext)))
|
2015-04-04 10:54:43 -04:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if contentType != "application/octet-stream" {
|
|
|
|
t.Fatalf("Content type should be 'application/octet-stream' but is %q", contentType)
|
|
|
|
}
|
|
|
|
body, err := ioutil.ReadAll(bReader)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if len(body) != len(binaryContext) {
|
|
|
|
t.Fatalf("Wrong response size %d, should be == len(binaryContext)", len(body))
|
|
|
|
}
|
|
|
|
for i := range body {
|
|
|
|
if body[i] != binaryContext[i] {
|
|
|
|
t.Fatalf("Corrupted response body at byte index %d", i)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestResponseUnsupportedContentType(t *testing.T) {
|
2016-05-03 05:10:51 -04:00
|
|
|
content := []byte(dockerfileContents)
|
2015-04-04 10:54:43 -04:00
|
|
|
ct := "application/json"
|
|
|
|
br := ioutil.NopCloser(bytes.NewReader(content))
|
2016-05-03 05:10:51 -04:00
|
|
|
contentType, bReader, err := inspectResponse(ct, br, int64(len(dockerfileContents)))
|
2015-04-04 10:54:43 -04:00
|
|
|
|
|
|
|
if err == nil {
|
|
|
|
t.Fatal("Should have returned an error on content-type 'application/json'")
|
|
|
|
}
|
|
|
|
if contentType != ct {
|
|
|
|
t.Fatalf("Should not have altered content-type: orig: %s, altered: %s", ct, contentType)
|
|
|
|
}
|
|
|
|
body, err := ioutil.ReadAll(bReader)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2016-05-03 05:10:51 -04:00
|
|
|
if string(body) != dockerfileContents {
|
2015-04-04 10:54:43 -04:00
|
|
|
t.Fatalf("Corrupted response body %s", body)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestInspectResponseTextSimple(t *testing.T) {
|
2016-05-03 05:10:51 -04:00
|
|
|
content := []byte(dockerfileContents)
|
2015-04-04 10:54:43 -04:00
|
|
|
ct := "text/plain"
|
|
|
|
br := ioutil.NopCloser(bytes.NewReader(content))
|
2015-07-23 17:19:58 -04:00
|
|
|
contentType, bReader, err := inspectResponse(ct, br, int64(len(content)))
|
2015-04-04 10:54:43 -04:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if contentType != "text/plain" {
|
|
|
|
t.Fatalf("Content type should be 'text/plain' but is %q", contentType)
|
|
|
|
}
|
|
|
|
body, err := ioutil.ReadAll(bReader)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2016-05-03 05:10:51 -04:00
|
|
|
if string(body) != dockerfileContents {
|
2015-04-04 10:54:43 -04:00
|
|
|
t.Fatalf("Corrupted response body %s", body)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestInspectResponseEmptyContentType(t *testing.T) {
|
2016-05-03 05:10:51 -04:00
|
|
|
content := []byte(dockerfileContents)
|
2015-04-04 10:54:43 -04:00
|
|
|
br := ioutil.NopCloser(bytes.NewReader(content))
|
2015-07-23 17:19:58 -04:00
|
|
|
contentType, bodyReader, err := inspectResponse("", br, int64(len(content)))
|
2015-04-04 10:54:43 -04:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if contentType != "text/plain" {
|
|
|
|
t.Fatalf("Content type should be 'text/plain' but is %q", contentType)
|
|
|
|
}
|
|
|
|
body, err := ioutil.ReadAll(bodyReader)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2016-05-03 05:10:51 -04:00
|
|
|
if string(body) != dockerfileContents {
|
2015-04-04 10:54:43 -04:00
|
|
|
t.Fatalf("Corrupted response body %s", body)
|
|
|
|
}
|
|
|
|
}
|
2016-05-01 06:58:39 -04:00
|
|
|
|
2017-01-30 03:02:47 -05:00
|
|
|
func TestUnknownContentLength(t *testing.T) {
|
|
|
|
content := []byte(dockerfileContents)
|
|
|
|
ct := "text/plain"
|
|
|
|
br := ioutil.NopCloser(bytes.NewReader(content))
|
|
|
|
contentType, bReader, err := inspectResponse(ct, br, -1)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if contentType != "text/plain" {
|
|
|
|
t.Fatalf("Content type should be 'text/plain' but is %q", contentType)
|
|
|
|
}
|
|
|
|
body, err := ioutil.ReadAll(bReader)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if string(body) != dockerfileContents {
|
|
|
|
t.Fatalf("Corrupted response body %s", body)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-08 13:06:57 -05:00
|
|
|
func TestDownloadRemote(t *testing.T) {
|
|
|
|
contextDir := fs.NewDir(t, "test-builder-download-remote",
|
|
|
|
fs.WithFile(builder.DefaultDockerfileName, dockerfileContents))
|
|
|
|
defer contextDir.Remove()
|
2016-05-01 06:58:39 -04:00
|
|
|
|
|
|
|
mux := http.NewServeMux()
|
|
|
|
server := httptest.NewServer(mux)
|
|
|
|
serverURL, _ := url.Parse(server.URL)
|
|
|
|
|
2017-03-20 18:22:29 -04:00
|
|
|
serverURL.Path = "/" + builder.DefaultDockerfileName
|
2016-05-01 06:58:39 -04:00
|
|
|
remoteURL := serverURL.String()
|
|
|
|
|
2017-11-08 13:06:57 -05:00
|
|
|
mux.Handle("/", http.FileServer(http.Dir(contextDir.Path())))
|
2016-05-01 06:58:39 -04:00
|
|
|
|
2017-11-08 13:06:57 -05:00
|
|
|
contentType, content, err := downloadRemote(remoteURL)
|
2018-03-13 15:28:34 -04:00
|
|
|
assert.NilError(t, err)
|
2016-05-01 06:58:39 -04:00
|
|
|
|
2018-03-13 15:28:34 -04:00
|
|
|
assert.Check(t, is.Equal(mimeTypes.TextPlain, contentType))
|
2017-11-08 13:06:57 -05:00
|
|
|
raw, err := ioutil.ReadAll(content)
|
2018-03-13 15:28:34 -04:00
|
|
|
assert.NilError(t, err)
|
|
|
|
assert.Check(t, is.Equal(dockerfileContents, string(raw)))
|
2016-05-01 06:58:39 -04:00
|
|
|
}
|
2017-06-01 17:05:44 -04:00
|
|
|
|
|
|
|
func TestGetWithStatusError(t *testing.T) {
|
|
|
|
var testcases = []struct {
|
|
|
|
err error
|
|
|
|
statusCode int
|
|
|
|
expectedErr string
|
|
|
|
expectedBody string
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
statusCode: 200,
|
|
|
|
expectedBody: "THE BODY",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
statusCode: 400,
|
|
|
|
expectedErr: "with status 400 Bad Request: broke",
|
|
|
|
expectedBody: "broke",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
for _, testcase := range testcases {
|
|
|
|
ts := httptest.NewServer(
|
|
|
|
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
buffer := bytes.NewBufferString(testcase.expectedBody)
|
|
|
|
w.WriteHeader(testcase.statusCode)
|
|
|
|
w.Write(buffer.Bytes())
|
|
|
|
}),
|
|
|
|
)
|
|
|
|
defer ts.Close()
|
|
|
|
response, err := GetWithStatusError(ts.URL)
|
|
|
|
|
|
|
|
if testcase.expectedErr == "" {
|
2018-03-13 15:28:34 -04:00
|
|
|
assert.NilError(t, err)
|
2017-06-01 17:05:44 -04:00
|
|
|
|
2017-08-21 18:50:40 -04:00
|
|
|
body, err := readBody(response.Body)
|
2018-03-13 15:28:34 -04:00
|
|
|
assert.NilError(t, err)
|
|
|
|
assert.Check(t, is.Contains(string(body), testcase.expectedBody))
|
2017-06-01 17:05:44 -04:00
|
|
|
} else {
|
2018-05-20 18:06:50 -04:00
|
|
|
assert.Check(t, is.ErrorContains(err, testcase.expectedErr))
|
2017-06-01 17:05:44 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-08-21 18:50:40 -04:00
|
|
|
|
|
|
|
func readBody(b io.ReadCloser) ([]byte, error) {
|
|
|
|
defer b.Close()
|
|
|
|
return ioutil.ReadAll(b)
|
|
|
|
}
|