github.com/Heebron/moby@v0.0.0-20221111184709-6eab4f55faf7/builder/remotecontext/remote_test.go (about)

     1  package remotecontext // import "github.com/docker/docker/builder/remotecontext"
     2  
     3  import (
     4  	"bytes"
     5  	"io"
     6  	"net/http"
     7  	"net/http/httptest"
     8  	"net/url"
     9  	"testing"
    10  
    11  	"github.com/docker/docker/builder"
    12  	"gotest.tools/v3/assert"
    13  	is "gotest.tools/v3/assert/cmp"
    14  	"gotest.tools/v3/fs"
    15  )
    16  
    17  var binaryContext = []byte{0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00} // xz magic
    18  
    19  func TestSelectAcceptableMIME(t *testing.T) {
    20  	validMimeStrings := []string{
    21  		"application/x-bzip2",
    22  		"application/bzip2",
    23  		"application/gzip",
    24  		"application/x-gzip",
    25  		"application/x-xz",
    26  		"application/xz",
    27  		"application/tar",
    28  		"application/x-tar",
    29  		"application/octet-stream",
    30  		"text/plain",
    31  	}
    32  
    33  	invalidMimeStrings := []string{
    34  		"",
    35  		"application/octet",
    36  		"application/json",
    37  	}
    38  
    39  	for _, m := range invalidMimeStrings {
    40  		if len(selectAcceptableMIME(m)) > 0 {
    41  			t.Fatalf("Should not have accepted %q", m)
    42  		}
    43  	}
    44  
    45  	for _, m := range validMimeStrings {
    46  		if str := selectAcceptableMIME(m); str == "" {
    47  			t.Fatalf("Should have accepted %q", m)
    48  		}
    49  	}
    50  }
    51  
    52  func TestInspectEmptyResponse(t *testing.T) {
    53  	ct := "application/octet-stream"
    54  	br := io.NopCloser(bytes.NewReader([]byte("")))
    55  	contentType, bReader, err := inspectResponse(ct, br, 0)
    56  	if err == nil {
    57  		t.Fatal("Should have generated an error for an empty response")
    58  	}
    59  	if contentType != "application/octet-stream" {
    60  		t.Fatalf("Content type should be 'application/octet-stream' but is %q", contentType)
    61  	}
    62  	body, err := io.ReadAll(bReader)
    63  	if err != nil {
    64  		t.Fatal(err)
    65  	}
    66  	if len(body) != 0 {
    67  		t.Fatal("response body should remain empty")
    68  	}
    69  }
    70  
    71  func TestInspectResponseBinary(t *testing.T) {
    72  	ct := "application/octet-stream"
    73  	br := io.NopCloser(bytes.NewReader(binaryContext))
    74  	contentType, bReader, err := inspectResponse(ct, br, int64(len(binaryContext)))
    75  	if err != nil {
    76  		t.Fatal(err)
    77  	}
    78  	if contentType != "application/octet-stream" {
    79  		t.Fatalf("Content type should be 'application/octet-stream' but is %q", contentType)
    80  	}
    81  	body, err := io.ReadAll(bReader)
    82  	if err != nil {
    83  		t.Fatal(err)
    84  	}
    85  	if len(body) != len(binaryContext) {
    86  		t.Fatalf("Wrong response size %d, should be == len(binaryContext)", len(body))
    87  	}
    88  	for i := range body {
    89  		if body[i] != binaryContext[i] {
    90  			t.Fatalf("Corrupted response body at byte index %d", i)
    91  		}
    92  	}
    93  }
    94  
    95  func TestResponseUnsupportedContentType(t *testing.T) {
    96  	content := []byte(dockerfileContents)
    97  	ct := "application/json"
    98  	br := io.NopCloser(bytes.NewReader(content))
    99  	contentType, bReader, err := inspectResponse(ct, br, int64(len(dockerfileContents)))
   100  
   101  	if err == nil {
   102  		t.Fatal("Should have returned an error on content-type 'application/json'")
   103  	}
   104  	if contentType != ct {
   105  		t.Fatalf("Should not have altered content-type: orig: %s, altered: %s", ct, contentType)
   106  	}
   107  	body, err := io.ReadAll(bReader)
   108  	if err != nil {
   109  		t.Fatal(err)
   110  	}
   111  	if string(body) != dockerfileContents {
   112  		t.Fatalf("Corrupted response body %s", body)
   113  	}
   114  }
   115  
   116  func TestInspectResponseTextSimple(t *testing.T) {
   117  	content := []byte(dockerfileContents)
   118  	ct := "text/plain"
   119  	br := io.NopCloser(bytes.NewReader(content))
   120  	contentType, bReader, err := inspectResponse(ct, br, int64(len(content)))
   121  	if err != nil {
   122  		t.Fatal(err)
   123  	}
   124  	if contentType != "text/plain" {
   125  		t.Fatalf("Content type should be 'text/plain' but is %q", contentType)
   126  	}
   127  	body, err := io.ReadAll(bReader)
   128  	if err != nil {
   129  		t.Fatal(err)
   130  	}
   131  	if string(body) != dockerfileContents {
   132  		t.Fatalf("Corrupted response body %s", body)
   133  	}
   134  }
   135  
   136  func TestInspectResponseEmptyContentType(t *testing.T) {
   137  	content := []byte(dockerfileContents)
   138  	br := io.NopCloser(bytes.NewReader(content))
   139  	contentType, bodyReader, err := inspectResponse("", br, int64(len(content)))
   140  	if err != nil {
   141  		t.Fatal(err)
   142  	}
   143  	if contentType != "text/plain" {
   144  		t.Fatalf("Content type should be 'text/plain' but is %q", contentType)
   145  	}
   146  	body, err := io.ReadAll(bodyReader)
   147  	if err != nil {
   148  		t.Fatal(err)
   149  	}
   150  	if string(body) != dockerfileContents {
   151  		t.Fatalf("Corrupted response body %s", body)
   152  	}
   153  }
   154  
   155  func TestUnknownContentLength(t *testing.T) {
   156  	content := []byte(dockerfileContents)
   157  	ct := "text/plain"
   158  	br := io.NopCloser(bytes.NewReader(content))
   159  	contentType, bReader, err := inspectResponse(ct, br, -1)
   160  	if err != nil {
   161  		t.Fatal(err)
   162  	}
   163  	if contentType != "text/plain" {
   164  		t.Fatalf("Content type should be 'text/plain' but is %q", contentType)
   165  	}
   166  	body, err := io.ReadAll(bReader)
   167  	if err != nil {
   168  		t.Fatal(err)
   169  	}
   170  	if string(body) != dockerfileContents {
   171  		t.Fatalf("Corrupted response body %s", body)
   172  	}
   173  }
   174  
   175  func TestDownloadRemote(t *testing.T) {
   176  	contextDir := fs.NewDir(t, "test-builder-download-remote",
   177  		fs.WithFile(builder.DefaultDockerfileName, dockerfileContents))
   178  	defer contextDir.Remove()
   179  
   180  	mux := http.NewServeMux()
   181  	server := httptest.NewServer(mux)
   182  	serverURL, _ := url.Parse(server.URL)
   183  
   184  	serverURL.Path = "/" + builder.DefaultDockerfileName
   185  	remoteURL := serverURL.String()
   186  
   187  	mux.Handle("/", http.FileServer(http.Dir(contextDir.Path())))
   188  
   189  	contentType, content, err := downloadRemote(remoteURL)
   190  	assert.NilError(t, err)
   191  
   192  	assert.Check(t, is.Equal(mimeTypes.TextPlain, contentType))
   193  	raw, err := io.ReadAll(content)
   194  	assert.NilError(t, err)
   195  	assert.Check(t, is.Equal(dockerfileContents, string(raw)))
   196  }
   197  
   198  func TestGetWithStatusError(t *testing.T) {
   199  	var testcases = []struct {
   200  		err          error
   201  		statusCode   int
   202  		expectedErr  string
   203  		expectedBody string
   204  	}{
   205  		{
   206  			statusCode:   200,
   207  			expectedBody: "THE BODY",
   208  		},
   209  		{
   210  			statusCode:   400,
   211  			expectedErr:  "with status 400 Bad Request: broke",
   212  			expectedBody: "broke",
   213  		},
   214  	}
   215  	for _, testcase := range testcases {
   216  		ts := httptest.NewServer(
   217  			http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   218  				buffer := bytes.NewBufferString(testcase.expectedBody)
   219  				w.WriteHeader(testcase.statusCode)
   220  				w.Write(buffer.Bytes())
   221  			}),
   222  		)
   223  		defer ts.Close()
   224  		response, err := GetWithStatusError(ts.URL)
   225  
   226  		if testcase.expectedErr == "" {
   227  			assert.NilError(t, err)
   228  
   229  			body, err := readBody(response.Body)
   230  			assert.NilError(t, err)
   231  			assert.Check(t, is.Contains(string(body), testcase.expectedBody))
   232  		} else {
   233  			assert.Check(t, is.ErrorContains(err, testcase.expectedErr))
   234  		}
   235  	}
   236  }
   237  
   238  func readBody(b io.ReadCloser) ([]byte, error) {
   239  	defer b.Close()
   240  	return io.ReadAll(b)
   241  }